From 0d5a32d3c6312839a3d55fcb68ff8035334799b4 Mon Sep 17 00:00:00 2001 From: Ben McCann <322311+benmccann@users.noreply.github.com> Date: Sat, 23 Jul 2022 06:30:00 -0700 Subject: [PATCH 1/6] Set Vite's publicDir and correctly serve public assets earlier in pipeline --- .changeset/light-vans-suffer.md | 6 ++ packages/adapter-node/index.js | 1 - packages/kit/src/core/adapt/builder.js | 5 +- packages/kit/src/core/adapt/builder.spec.js | 8 +-- packages/kit/src/core/prerender/prerender.js | 7 +-- packages/kit/src/vite/build/utils.js | 4 +- packages/kit/src/vite/dev/index.js | 64 ++++++++++++-------- packages/kit/src/vite/index.js | 1 + packages/kit/src/vite/preview/index.js | 7 +-- 9 files changed, 54 insertions(+), 49 deletions(-) create mode 100644 .changeset/light-vans-suffer.md diff --git a/.changeset/light-vans-suffer.md b/.changeset/light-vans-suffer.md new file mode 100644 index 000000000000..f2d15b9dfa82 --- /dev/null +++ b/.changeset/light-vans-suffer.md @@ -0,0 +1,6 @@ +--- +'@sveltejs/adapter-node': patch +'@sveltejs/kit': patch +--- + +Set Vite's publicDir and correctly serve public assets earlier in pipeline diff --git a/packages/adapter-node/index.js b/packages/adapter-node/index.js index ec1d53eeccfe..4dbd7d1bd9ad 100644 --- a/packages/adapter-node/index.js +++ b/packages/adapter-node/index.js @@ -50,7 +50,6 @@ export default function (opts = {}) { if (precompress) { builder.log.minor('Compressing assets'); await compress(`${out}/client`); - await compress(`${out}/static`); await compress(`${out}/prerendered`); } } diff --git a/packages/kit/src/core/adapt/builder.js b/packages/kit/src/core/adapt/builder.js index c93e35075389..d54628378bf6 100644 --- a/packages/kit/src/core/adapt/builder.js +++ b/packages/kit/src/core/adapt/builder.js @@ -122,10 +122,7 @@ export function create_builder({ config, build_data, prerendered, log }) { }, writeClient(dest) { - return [ - ...copy(`${config.kit.outDir}/output/client`, dest), - ...copy(config.kit.files.assets, dest) - ]; + return [...copy(`${config.kit.outDir}/output/client`, dest)]; }, writePrerendered(dest, { fallback } = {}) { diff --git a/packages/kit/src/core/adapt/builder.spec.js b/packages/kit/src/core/adapt/builder.spec.js index 0af84ddec6c5..2f2c82f4a78f 100644 --- a/packages/kit/src/core/adapt/builder.spec.js +++ b/packages/kit/src/core/adapt/builder.spec.js @@ -43,13 +43,7 @@ test('copy files', () => { builder.writeClient(dest); assert.equal( - [ - ...glob('**', { - cwd: /** @type {import('types').ValidatedConfig} */ (mocked).kit.files.assets, - dot: true - }), - ...glob('**', { cwd: `${outDir}/output/client`, dot: true }) - ], + glob('**', { cwd: `${outDir}/output/client`, dot: true }), glob('**', { cwd: dest, dot: true }) ); diff --git a/packages/kit/src/core/prerender/prerender.js b/packages/kit/src/core/prerender/prerender.js index ce27b92bf027..6d6b58187f14 100644 --- a/packages/kit/src/core/prerender/prerender.js +++ b/packages/kit/src/core/prerender/prerender.js @@ -1,4 +1,4 @@ -import { existsSync, readFileSync, writeFileSync } from 'fs'; +import { readFileSync, writeFileSync } from 'fs'; import { dirname, join } from 'path'; import { pathToFileURL, URL } from 'url'; import { mkdirp, posixify, walk } from '../../utils/filesystem.js'; @@ -158,10 +158,7 @@ export async function prerender({ config, client_out_dir, manifest_path, log }) return file; } - const files = new Set([ - ...walk(client_out_dir).map(posixify), - ...(existsSync(config.files.assets) ? walk(config.files.assets).map(posixify) : []) // TODO remove this if we use Vite publicDir option - ]); + const files = new Set(walk(client_out_dir).map(posixify)); const seen = new Set(); const written = new Set(); diff --git a/packages/kit/src/vite/build/utils.js b/packages/kit/src/vite/build/utils.js index 7d6e8f44018a..614a07b79a40 100644 --- a/packages/kit/src/vite/build/utils.js +++ b/packages/kit/src/vite/build/utils.js @@ -117,9 +117,7 @@ export const get_default_config = function ({ config, input, ssr, outDir }) { __SVELTEKIT_APP_VERSION_POLL_INTERVAL__: JSON.stringify(config.kit.version.pollInterval), __SVELTEKIT_DEV__: 'false' }, - // prevent Vite copying the contents of `config.kit.files.assets`, - // if it happens to be 'public' instead of 'static' - publicDir: false, + publicDir: ssr ? false : config.kit.files.assets, resolve: { alias: get_aliases(config.kit) }, diff --git a/packages/kit/src/vite/dev/index.js b/packages/kit/src/vite/dev/index.js index c042c0f16f42..3e1ba0a771f8 100644 --- a/packages/kit/src/vite/dev/index.js +++ b/packages/kit/src/vite/dev/index.js @@ -180,13 +180,39 @@ export async function dev(vite, vite_config, svelte_config) { extensions: [] }); - return () => { - const serve_static_middleware = vite.middlewares.stack.find( - (middleware) => - /** @type {function} */ (middleware.handle).name === 'viteServeStaticMiddleware' - ); + const serve_static_middleware = vite.middlewares.stack.find( + (middleware) => + /** @type {function} */ (middleware.handle).name === 'viteServeStaticMiddleware' + ); + + remove_static_middlewares(vite.middlewares); + + vite.middlewares.use(async (req, res, next) => { + if (!req.url || !req.method) throw new Error('Incomplete request'); + + const base = `${vite.config.server.https ? 'https' : 'http'}://${ + req.headers[':authority'] || req.headers.host + }`; + + const decoded = decodeURI(new URL(base + req.url).pathname); + + if (decoded.startsWith(assets)) { + const pathname = decoded.slice(assets.length); + const file = svelte_config.kit.files.assets + pathname; + + if (fs.existsSync(file) && !fs.statSync(file).isDirectory()) { + if (has_correct_case(file, svelte_config.kit.files.assets)) { + req.url = encodeURI(pathname); // don't need query/hash + asset_server(req, res); + return; + } + } + } - remove_html_middlewares(vite.middlewares); + next(); + }); + + return () => { vite.middlewares.use(async (req, res) => { try { @@ -197,20 +223,6 @@ export async function dev(vite, vite_config, svelte_config) { }`; const decoded = decodeURI(new URL(base + req.url).pathname); - - if (decoded.startsWith(assets)) { - const pathname = decoded.slice(assets.length); - const file = svelte_config.kit.files.assets + pathname; - - if (fs.existsSync(file) && !fs.statSync(file).isDirectory()) { - if (has_correct_case(file, svelte_config.kit.files.assets)) { - req.url = encodeURI(pathname); // don't need query/hash - asset_server(req, res); - return; - } - } - } - const file = posixify(path.resolve(decoded.slice(1))); const is_file = fs.existsSync(file) && !fs.statSync(file).isDirectory(); const allowed = @@ -389,11 +401,15 @@ function not_found(res, message = 'Not found') { /** * @param {import('connect').Server} server */ -function remove_html_middlewares(server) { - const html_middlewares = ['viteServeStaticMiddleware']; +function remove_static_middlewares(server) { + // We don't use viteServePublicMiddleware because of the following issues: + // https://github.com/vitejs/vite/issues/9260 + // https://github.com/vitejs/vite/issues/9236 + // https://github.com/vitejs/vite/issues/9234 + const static_middlewares = ['viteServePublicMiddleware', 'viteServeStaticMiddleware']; for (let i = server.stack.length - 1; i > 0; i--) { - // @ts-expect-error using internals until https://github.com/vitejs/vite/pull/4640 is merged - if (html_middlewares.includes(server.stack[i].handle.name)) { + // @ts-expect-error using internals + if (static_middlewares.includes(server.stack[i].handle.name)) { server.stack.splice(i, 1); } } diff --git a/packages/kit/src/vite/index.js b/packages/kit/src/vite/index.js index c2d8355bee1f..950cae8e25b5 100644 --- a/packages/kit/src/vite/index.js +++ b/packages/kit/src/vite/index.js @@ -213,6 +213,7 @@ function kit() { __SVELTEKIT_DEV__: 'true', __SVELTEKIT_APP_VERSION_POLL_INTERVAL__: '0' }, + publicDir: svelte_config.kit.files.assets, resolve: { alias: get_aliases(svelte_config.kit) }, diff --git a/packages/kit/src/vite/preview/index.js b/packages/kit/src/vite/preview/index.js index 078e6146ed3a..262eb48c9c24 100644 --- a/packages/kit/src/vite/preview/index.js +++ b/packages/kit/src/vite/preview/index.js @@ -44,16 +44,13 @@ export async function preview(vite, config, protocol) { const server = new Server(manifest); return () => { - // files in `static` - vite.middlewares.use(scoped(assets, mutable(config.kit.files.assets))); - - // immutable generated client assets + // generated client assets and the contents of `static` vite.middlewares.use( scoped( assets, sirv(join(config.kit.outDir, 'output/client'), { setHeaders: (res, pathname) => { - // only apply to build directory, not e.g. version.json + // only apply to immutable directory, not e.g. version.json if (pathname.startsWith(`/${config.kit.appDir}/immutable`)) { res.setHeader('cache-control', 'public,max-age=31536000,immutable'); } From 9c3e8913f72b49dad4d6b450ccdfa3c8703cc6ed Mon Sep 17 00:00:00 2001 From: Ben McCann <322311+benmccann@users.noreply.github.com> Date: Sat, 23 Jul 2022 06:33:40 -0700 Subject: [PATCH 2/6] format --- packages/kit/src/vite/dev/index.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/kit/src/vite/dev/index.js b/packages/kit/src/vite/dev/index.js index 3e1ba0a771f8..2f36e10562c4 100644 --- a/packages/kit/src/vite/dev/index.js +++ b/packages/kit/src/vite/dev/index.js @@ -181,8 +181,7 @@ export async function dev(vite, vite_config, svelte_config) { }); const serve_static_middleware = vite.middlewares.stack.find( - (middleware) => - /** @type {function} */ (middleware.handle).name === 'viteServeStaticMiddleware' + (middleware) => /** @type {function} */ (middleware.handle).name === 'viteServeStaticMiddleware' ); remove_static_middlewares(vite.middlewares); @@ -213,7 +212,6 @@ export async function dev(vite, vite_config, svelte_config) { }); return () => { - vite.middlewares.use(async (req, res) => { try { if (!req.url || !req.method) throw new Error('Incomplete request'); From bd383d3eb73d57e4149bd4234a2c6712ca980b83 Mon Sep 17 00:00:00 2001 From: Ben McCann <322311+benmccann@users.noreply.github.com> Date: Sat, 23 Jul 2022 11:13:42 -0700 Subject: [PATCH 3/6] get tests passing --- packages/kit/src/vite/dev/index.js | 48 +++++++++++++++++------------- 1 file changed, 27 insertions(+), 21 deletions(-) diff --git a/packages/kit/src/vite/dev/index.js b/packages/kit/src/vite/dev/index.js index 2f36e10562c4..521ef1f8a6b1 100644 --- a/packages/kit/src/vite/dev/index.js +++ b/packages/kit/src/vite/dev/index.js @@ -180,38 +180,44 @@ export async function dev(vite, vite_config, svelte_config) { extensions: [] }); - const serve_static_middleware = vite.middlewares.stack.find( - (middleware) => /** @type {function} */ (middleware.handle).name === 'viteServeStaticMiddleware' - ); - - remove_static_middlewares(vite.middlewares); - vite.middlewares.use(async (req, res, next) => { - if (!req.url || !req.method) throw new Error('Incomplete request'); + try { + if (!req.url || !req.method) throw new Error('Incomplete request'); - const base = `${vite.config.server.https ? 'https' : 'http'}://${ - req.headers[':authority'] || req.headers.host - }`; + const base = `${vite.config.server.https ? 'https' : 'http'}://${ + req.headers[':authority'] || req.headers.host + }`; - const decoded = decodeURI(new URL(base + req.url).pathname); + const decoded = decodeURI(new URL(base + req.url).pathname); - if (decoded.startsWith(assets)) { - const pathname = decoded.slice(assets.length); - const file = svelte_config.kit.files.assets + pathname; + if (decoded.startsWith(assets)) { + const pathname = decoded.slice(assets.length); + const file = svelte_config.kit.files.assets + pathname; - if (fs.existsSync(file) && !fs.statSync(file).isDirectory()) { - if (has_correct_case(file, svelte_config.kit.files.assets)) { - req.url = encodeURI(pathname); // don't need query/hash - asset_server(req, res); - return; + if (fs.existsSync(file) && !fs.statSync(file).isDirectory()) { + if (has_correct_case(file, svelte_config.kit.files.assets)) { + req.url = encodeURI(pathname); // don't need query/hash + asset_server(req, res); + return; + } } } - } - next(); + next(); + } catch (e) { + const error = coalesce_to_error(e); + res.statusCode = 500; + res.end(fix_stack_trace(error)); + } }); return () => { + const serve_static_middleware = vite.middlewares.stack.find( + (middleware) => /** @type {function} */ (middleware.handle).name === 'viteServeStaticMiddleware' + ); + + remove_static_middlewares(vite.middlewares); + vite.middlewares.use(async (req, res) => { try { if (!req.url || !req.method) throw new Error('Incomplete request'); From 3373ac42c531061caadd25f698ab1f0eb1904fb9 Mon Sep 17 00:00:00 2001 From: Ben McCann <322311+benmccann@users.noreply.github.com> Date: Sat, 23 Jul 2022 11:22:21 -0700 Subject: [PATCH 4/6] format --- packages/kit/src/vite/dev/index.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/kit/src/vite/dev/index.js b/packages/kit/src/vite/dev/index.js index 521ef1f8a6b1..03c5f52fbf1b 100644 --- a/packages/kit/src/vite/dev/index.js +++ b/packages/kit/src/vite/dev/index.js @@ -213,7 +213,8 @@ export async function dev(vite, vite_config, svelte_config) { return () => { const serve_static_middleware = vite.middlewares.stack.find( - (middleware) => /** @type {function} */ (middleware.handle).name === 'viteServeStaticMiddleware' + (middleware) => + /** @type {function} */ (middleware.handle).name === 'viteServeStaticMiddleware' ); remove_static_middlewares(vite.middlewares); From 30691d297bb313f1d3791dfe8d60bb81a98f123d Mon Sep 17 00:00:00 2001 From: Ben McCann <322311+benmccann@users.noreply.github.com> Date: Mon, 25 Jul 2022 08:58:10 -0700 Subject: [PATCH 5/6] update test app to prevent regressions --- packages/kit/test/apps/basics/src/app.html | 3 +++ packages/kit/test/apps/basics/static/empty.js | 0 2 files changed, 3 insertions(+) create mode 100644 packages/kit/test/apps/basics/static/empty.js diff --git a/packages/kit/test/apps/basics/src/app.html b/packages/kit/test/apps/basics/src/app.html index f40e9313e81e..53da9a903602 100644 --- a/packages/kit/test/apps/basics/src/app.html +++ b/packages/kit/test/apps/basics/src/app.html @@ -5,6 +5,9 @@ + + %sveltekit.head% diff --git a/packages/kit/test/apps/basics/static/empty.js b/packages/kit/test/apps/basics/static/empty.js new file mode 100644 index 000000000000..e69de29bb2d1 From 9cee0ab69da44ffdd739a30fdbc4e4d4ced97ab5 Mon Sep 17 00:00:00 2001 From: Ben McCann <322311+benmccann@users.noreply.github.com> Date: Mon, 25 Jul 2022 09:38:09 -0700 Subject: [PATCH 6/6] remove incomplete request checks --- packages/kit/src/vite/dev/index.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/packages/kit/src/vite/dev/index.js b/packages/kit/src/vite/dev/index.js index 03c5f52fbf1b..8d5cd48adfd8 100644 --- a/packages/kit/src/vite/dev/index.js +++ b/packages/kit/src/vite/dev/index.js @@ -182,8 +182,6 @@ export async function dev(vite, vite_config, svelte_config) { vite.middlewares.use(async (req, res, next) => { try { - if (!req.url || !req.method) throw new Error('Incomplete request'); - const base = `${vite.config.server.https ? 'https' : 'http'}://${ req.headers[':authority'] || req.headers.host }`; @@ -221,8 +219,6 @@ export async function dev(vite, vite_config, svelte_config) { vite.middlewares.use(async (req, res) => { try { - if (!req.url || !req.method) throw new Error('Incomplete request'); - const base = `${vite.config.server.https ? 'https' : 'http'}://${ req.headers[':authority'] || req.headers.host }`;