diff --git a/CHANGELOG.md b/CHANGELOG.md index 6f2a9a444..2523750d9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # sapper changelog +## 0.11.0 + +* Create launcher file ([#240](https://github.com/sveltejs/sapper/issues/240)) +* Only keep necessary parts of webpack stats ([#251](https://github.com/sveltejs/sapper/pull/251)) +* Allow `NODE_ENV` to be overridden when building ([#241](https://github.com/sveltejs/sapper/issues/241)) + ## 0.10.7 * Allow routes to have a leading `.` ([#243](https://github.com/sveltejs/sapper/pull/243)) diff --git a/package.json b/package.json index 2d52c5183..74c933bef 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "sapper", - "version": "0.10.7", + "version": "0.11.0", "description": "Military-grade apps, engineered by Svelte", "main": "dist/middleware.ts.js", "bin": { @@ -34,35 +34,35 @@ "rimraf": "^2.6.2", "sade": "^1.4.0", "sander": "^0.6.0", - "source-map-support": "^0.5.4", + "source-map-support": "^0.5.5", "tslib": "^1.9.0", "url-parse": "^1.2.0", "webpack-format-messages": "^1.0.2" }, "devDependencies": { - "@std/esm": "^0.25.3", "@types/glob": "^5.0.34", "@types/mkdirp": "^0.5.2", "@types/rimraf": "^2.0.2", "compression": "^1.7.1", "eslint": "^4.13.1", "eslint-plugin-import": "^2.8.0", + "esm": "^3.0.28", "express": "^4.16.3", "get-port": "^3.2.0", "mocha": "^5.0.4", "nightmare": "^3.0.0", "npm-run-all": "^4.1.2", "polka": "^0.3.4", - "rollup": "^0.57.0", - "rollup-plugin-commonjs": "^9.1.0", + "rollup": "^0.58.2", + "rollup-plugin-commonjs": "^9.1.3", "rollup-plugin-json": "^2.3.0", "rollup-plugin-string": "^2.0.2", "rollup-plugin-typescript": "^0.8.1", "serve-static": "^1.13.2", - "svelte": "^1.57.4", - "svelte-loader": "^2.5.1", - "ts-node": "^5.0.1", - "typescript": "^2.6.2", + "svelte": "^2.4.4", + "svelte-loader": "^2.9.0", + "ts-node": "^6.0.2", + "typescript": "^2.8.3", "walk-sync": "^0.3.2", "webpack": "^4.1.0" }, diff --git a/src/cli.ts b/src/cli.ts index 8913b9f5e..12c79b2ae 100755 --- a/src/cli.ts +++ b/src/cli.ts @@ -21,10 +21,12 @@ prog.command('dev') prog.command('build [dest]') .describe('Create a production-ready version of your app') - .action(async (dest = 'build') => { + .option('-p, --port', 'Default of process.env.PORT', '3000') + .example(`build custom-dir -p 4567`) + .action(async (dest = 'build', opts: { port: string }) => { console.log(`> Building...`); - process.env.NODE_ENV = 'production'; + process.env.NODE_ENV = process.env.NODE_ENV || 'production'; process.env.SAPPER_DEST = dest; const start = Date.now(); @@ -32,7 +34,20 @@ prog.command('build [dest]') try { const { build } = await import('./cli/build'); await build(); - console.error(`\n> Finished in ${elapsed(start)}. Type ${clorox.bold.cyan(dest === 'build' ? 'npx sapper start' : `npx sapper start ${dest}`)} to run the app.`); + + const launcher = path.resolve(dest, 'index.js'); + + fs.writeFileSync(launcher, ` + // generated by sapper build at ${new Date().toISOString()} + process.env.NODE_ENV = process.env.NODE_ENV || 'production'; + process.env.SAPPER_DEST = __dirname; + process.env.PORT = process.env.PORT || ${opts.port || 3000}; + + console.log('Starting server on port ' + process.env.PORT); + require('./server.js'); + `.replace(/^\t+/gm, '').trim()); + + console.error(`\n> Finished in ${elapsed(start)}. Type ${clorox.bold.cyan(`node ${dest}`)} to run the app.`); } catch (err) { console.error(err ? err.details || err.stack || err.message || err : 'Unknown error'); } diff --git a/src/cli/build.ts b/src/cli/build.ts index c997f4ae5..1e452947b 100644 --- a/src/cli/build.ts +++ b/src/cli/build.ts @@ -35,7 +35,9 @@ export async function build() { const client_stats = await compile(client); console.log(`${clorox.inverse(`\nbuilt client`)}`); console.log(client_stats.toString({ colors: true })); - fs.writeFileSync(path.join(output, 'client_info.json'), JSON.stringify(client_stats.toJson())); + fs.writeFileSync(path.join(output, 'client_info.json'), JSON.stringify({ + assets: client_stats.toJson().assetsByChunkName + })); const server_stats = await compile(server); console.log(`${clorox.inverse(`\nbuilt server`)}`); diff --git a/src/cli/dev.ts b/src/cli/dev.ts index 64357d338..76cc9d16f 100644 --- a/src/cli/dev.ts +++ b/src/cli/dev.ts @@ -263,7 +263,9 @@ export async function dev(opts: { port: number, open: boolean }) { }, result: info => { - fs.writeFileSync(path.join(dir, 'client_info.json'), JSON.stringify(info, null, ' ')); + fs.writeFileSync(path.join(dir, 'client_info.json'), JSON.stringify({ + assets: info.assetsByChunkName + }, null, ' ')); deferreds.client.fulfil(); const client_files = info.assets.map((chunk: { name: string }) => `client/${chunk.name}`); diff --git a/src/core/create_routes.ts b/src/core/create_routes.ts index 667614708..a5195d73f 100644 --- a/src/core/create_routes.ts +++ b/src/core/create_routes.ts @@ -7,6 +7,8 @@ export default function create_routes({ files } = { files: glob.sync('**/*.*', { const routes: Route[] = files .filter((file: string) => !/(^|\/|\\)_/.test(file)) .map((file: string) => { + if (/(^|\/|\\)(_|\.(?!well-known))/.test(file)) return; + if (/]\[/.test(file)) { throw new Error(`Invalid route ${file} — parameters must be separated`); } diff --git a/src/middleware.ts b/src/middleware.ts index 53165277b..323bd9f2a 100644 --- a/src/middleware.ts +++ b/src/middleware.ts @@ -90,7 +90,7 @@ export default function middleware({ routes, store }: { cache_control: 'max-age=31536000' }), - get_route_handler(client_info.assetsByChunkName, routes, store) + get_route_handler(client_info.assets, routes, store) ].filter(Boolean)); return middleware; diff --git a/src/runtime/index.ts b/src/runtime/index.ts index 347fbeef9..5e643be4a 100644 --- a/src/runtime/index.ts +++ b/src/runtime/index.ts @@ -214,7 +214,7 @@ let prefetching: { export function prefetch(href: string) { const selected = select_route(new URL(href, document.baseURI)); - if (selected) { + if (selected && (!prefetching || href !== prefetching.href)) { prefetching = { href, promise: selected.route.load().then(mod => prepare_route(mod.default, selected.data)) @@ -222,7 +222,16 @@ export function prefetch(href: string) { } } -function handle_touchstart_mouseover(event: MouseEvent | TouchEvent) { +let mousemove_timeout: NodeJS.Timer; + +function handle_mousemove(event: MouseEvent) { + clearTimeout(mousemove_timeout); + mousemove_timeout = setTimeout(() => { + trigger_prefetch(event); + }, 20); +} + +function trigger_prefetch(event: MouseEvent | TouchEvent) { const a: HTMLAnchorElement = findAnchor(event.target); if (!a || a.rel !== 'prefetch') return; @@ -248,8 +257,8 @@ export function init(_target: Node, _routes: Route[], opts?: { store?: (data: an window.addEventListener('popstate', handle_popstate); // prefetch - window.addEventListener('touchstart', handle_touchstart_mouseover); - window.addEventListener('mouseover', handle_touchstart_mouseover); + window.addEventListener('touchstart', trigger_prefetch); + window.addEventListener('mousemove', handle_mousemove); inited = true; } diff --git a/test/app/routes/4xx.html b/test/app/routes/4xx.html index df21c6bd8..c63ca8406 100644 --- a/test/app/routes/4xx.html +++ b/test/app/routes/4xx.html @@ -1,6 +1,6 @@ -<:Head> - {{status}} - + + {status} +

Not found

-

{{error.message}}

\ No newline at end of file +

{error.message}

\ No newline at end of file diff --git a/test/app/routes/5xx.html b/test/app/routes/5xx.html index 9208b047e..1425e2a8b 100644 --- a/test/app/routes/5xx.html +++ b/test/app/routes/5xx.html @@ -1,6 +1,6 @@ -<:Head> + Internal server error - +

Internal server error

-

{{error.message}}

\ No newline at end of file +

{error.message}

\ No newline at end of file diff --git a/test/app/routes/about.html b/test/app/routes/about.html index e09a72ed6..605e0db2f 100644 --- a/test/app/routes/about.html +++ b/test/app/routes/about.html @@ -1,6 +1,6 @@ -<:Head> + About - +

About this site

diff --git a/test/app/routes/blog/[slug].html b/test/app/routes/blog/[slug].html index ac5245bff..7fdc8b4b1 100644 --- a/test/app/routes/blog/[slug].html +++ b/test/app/routes/blog/[slug].html @@ -1,11 +1,11 @@ -<:Head> - {{post.title}} - + + {post.title} + -

{{post.title}}

+

{post.title}

- {{{post.html}}} + {@html post.html}