From d6ddf3cb8c174fb87d466ec4149e81570ced3443 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Sat, 15 Jan 2022 12:38:54 -0500 Subject: [PATCH] Handling of static assets with `paths.base` (#3346) * Fix svelte-kit dev/preview when config.kit.paths.base is set * add test of truncated base * changeset * failing test of requesting a static asset with basepath prefix * Serve static assets from /basepath in svelte-kit dev * Add changeset * simplify - only mutate req if necessary * assets_path -> assets * doh * check file is a file and not a directory Co-authored-by: Andrew Soutar --- .changeset/tender-actors-tease.md | 5 +++ packages/kit/src/core/dev/index.js | 1 - packages/kit/src/core/dev/plugin.js | 37 +++++++++++++++---- .../kit/test/apps/options-2/static/answer.txt | 1 + packages/kit/test/apps/options-2/test/test.js | 5 +++ 5 files changed, 41 insertions(+), 8 deletions(-) create mode 100644 .changeset/tender-actors-tease.md create mode 100644 packages/kit/test/apps/options-2/static/answer.txt diff --git a/.changeset/tender-actors-tease.md b/.changeset/tender-actors-tease.md new file mode 100644 index 000000000000..93be81d122d0 --- /dev/null +++ b/.changeset/tender-actors-tease.md @@ -0,0 +1,5 @@ +--- +'@sveltejs/kit': patch +--- + +Handle static assets with /basepath in svelte-kit dev diff --git a/packages/kit/src/core/dev/index.js b/packages/kit/src/core/dev/index.js index 33eb6e81a478..3bcd1a9b1b54 100644 --- a/packages/kit/src/core/dev/index.js +++ b/packages/kit/src/core/dev/index.js @@ -68,7 +68,6 @@ export async function dev({ cwd, port, host, https, config }) { }), await create_plugin(config, cwd) ], - publicDir: config.kit.files.assets, base: '/' }); diff --git a/packages/kit/src/core/dev/plugin.js b/packages/kit/src/core/dev/plugin.js index 7f9ecab0bdd3..765ae7abc525 100644 --- a/packages/kit/src/core/dev/plugin.js +++ b/packages/kit/src/core/dev/plugin.js @@ -2,6 +2,7 @@ import fs from 'fs'; import path from 'path'; import { URL } from 'url'; import colors from 'kleur'; +import sirv from 'sirv'; import { respond } from '../../runtime/server/index.js'; import { __fetch_polyfill } from '../../install-fetch.js'; import { create_app } from '../create_app/index.js'; @@ -126,6 +127,14 @@ export async function create_plugin(config, cwd) { vite.watcher.on('add', update_manifest); vite.watcher.on('remove', update_manifest); + const assets = config.kit.paths.assets ? SVELTE_KIT_ASSETS : config.kit.paths.base; + const asset_server = sirv(config.kit.files.assets, { + dev: true, + etag: true, + maxAge: 0, + extensions: [] + }); + return () => { remove_html_middlewares(vite.middlewares); @@ -134,8 +143,24 @@ export async function create_plugin(config, cwd) { if (!req.url || !req.method) throw new Error('Incomplete request'); if (req.url === '/favicon.ico') return not_found(res); - const parsed = new URL(req.url, 'http://localhost/'); - if (!parsed.pathname.startsWith(config.kit.paths.base)) return not_found(res); + const url = new URL( + `${vite.config.server.https ? 'https' : 'http'}://${req.headers.host}${req.url}` + ); + + const decoded = decodeURI(url.pathname); + + if (decoded.startsWith(assets)) { + const pathname = decoded.slice(assets.length); + const file = config.kit.files.assets + pathname; + + if (fs.existsSync(file) && !fs.statSync(file).isDirectory()) { + req.url = encodeURI(pathname); // don't need query/hash + asset_server(req, res); + return; + } + } + + if (!decoded.startsWith(config.kit.paths.base)) return not_found(res); /** @type {Partial} */ const user_hooks = resolve_entry(config.kit.files.hooks) @@ -179,7 +204,7 @@ export async function create_plugin(config, cwd) { paths.set_paths({ base: config.kit.paths.base, - assets: config.kit.paths.assets ? SVELTE_KIT_ASSETS : config.kit.paths.base + assets }); let body; @@ -193,9 +218,7 @@ export async function create_plugin(config, cwd) { const rendered = await respond( { - url: new URL( - `${vite.config.server.https ? 'https' : 'http'}://${req.headers.host}${req.url}` - ), + url, headers: /** @type {import('types/helper').RequestHeaders} */ (req.headers), method: req.method, rawBody: body @@ -218,7 +241,7 @@ export async function create_plugin(config, cwd) { method_override: config.kit.methodOverride, paths: { base: config.kit.paths.base, - assets: config.kit.paths.assets ? SVELTE_KIT_ASSETS : config.kit.paths.base + assets }, prefix: '', prerender: config.kit.prerender.enabled, diff --git a/packages/kit/test/apps/options-2/static/answer.txt b/packages/kit/test/apps/options-2/static/answer.txt new file mode 100644 index 000000000000..f70d7bba4ae1 --- /dev/null +++ b/packages/kit/test/apps/options-2/static/answer.txt @@ -0,0 +1 @@ +42 \ No newline at end of file diff --git a/packages/kit/test/apps/options-2/test/test.js b/packages/kit/test/apps/options-2/test/test.js index 6c0876aef575..0d8ba54090df 100644 --- a/packages/kit/test/apps/options-2/test/test.js +++ b/packages/kit/test/apps/options-2/test/test.js @@ -8,6 +8,11 @@ test.describe.parallel('paths.base', () => { await page.goto('/basepath'); expect(await page.textContent('h1')).toBe('Hello'); }); + + test('serves assets from /basepath', async ({ request }) => { + const response = await request.get('/basepath/answer.txt'); + expect(await response.text()).toBe('42'); + }); }); test.describe.parallel('Service worker', () => {