diff --git a/.changeset/stupid-singers-talk.md b/.changeset/stupid-singers-talk.md new file mode 100644 index 000000000000..2d1dfb99c375 --- /dev/null +++ b/.changeset/stupid-singers-talk.md @@ -0,0 +1,5 @@ +--- +'@sveltejs/kit': patch +--- + +fix: correctly access transport decoders on the client when building for a single or inline output app diff --git a/packages/kit/src/runtime/app/forms.js b/packages/kit/src/runtime/app/forms.js index d9bbd573990e..f4d0a352f628 100644 --- a/packages/kit/src/runtime/app/forms.js +++ b/packages/kit/src/runtime/app/forms.js @@ -6,8 +6,6 @@ import { app as server_app } from '../server/app.js'; export { applyAction }; -const decoders = BROWSER ? client_app.decoders : server_app?.decoders; - /** * Use this function to deserialize the response from a form submission. * Usage: @@ -34,7 +32,9 @@ export function deserialize(result) { const parsed = JSON.parse(result); if (parsed.data) { - parsed.data = devalue.parse(parsed.data, decoders); + // the decoders should never be initialised at the top-level because `app` + // will not initialised yet if `kit.output.bundleStrategy` is 'single' or 'inline' + parsed.data = devalue.parse(parsed.data, BROWSER ? client_app.decoders : server_app.decoders); } return parsed; diff --git a/packages/kit/test/apps/options-2/src/routes/deserialize/+page.svelte b/packages/kit/test/apps/options-2/src/routes/deserialize/+page.svelte new file mode 100644 index 000000000000..a35e3cf30df1 --- /dev/null +++ b/packages/kit/test/apps/options-2/src/routes/deserialize/+page.svelte @@ -0,0 +1,5 @@ + + +
{data.data.text}
diff --git a/packages/kit/test/apps/options-2/src/routes/deserialize/+page.ts b/packages/kit/test/apps/options-2/src/routes/deserialize/+page.ts new file mode 100644 index 000000000000..b3e20666383e --- /dev/null +++ b/packages/kit/test/apps/options-2/src/routes/deserialize/+page.ts @@ -0,0 +1,15 @@ +import { deserialize } from '$app/forms'; + +export const ssr = false; + +export function load() { + const result = deserialize( + JSON.stringify({ + type: 'success', + status: 200, + data: '[{"text":1},"Hello world!"]' + }) + ); + + return result; +} diff --git a/packages/kit/test/apps/options-2/test/test.js b/packages/kit/test/apps/options-2/test/test.js index ba5f10003284..b7fb132aa510 100644 --- a/packages/kit/test/apps/options-2/test/test.js +++ b/packages/kit/test/apps/options-2/test/test.js @@ -108,7 +108,7 @@ test.describe('Service worker', () => { }); expect(self.base).toBe('/basepath'); - expect(self.build[0]).toMatch(/\/basepath\/_app\/immutable\/bundle\.[\w-]+\.js/); + expect(self.build?.[0]).toMatch(/\/basepath\/_app\/immutable\/bundle\.[\w-]+\.js/); expect(self.image_src).toMatch(/\/basepath\/_app\/immutable\/assets\/image\.[\w-]+\.jpg/); }); @@ -120,6 +120,7 @@ test.describe('Service worker', () => { test.describe("bundleStrategy: 'single'", () => { test.skip(({ javaScriptEnabled }) => !javaScriptEnabled || !!process.env.DEV); + test('loads a single js file and a single css file', async ({ page }) => { /** @type {string[]} */ const requests = []; @@ -135,4 +136,9 @@ test.describe("bundleStrategy: 'single'", () => { expect(requests.filter((req) => req.endsWith('.js')).length).toBe(1); expect(requests.filter((req) => req.endsWith('.css')).length).toBe(1); }); + + test('app.decoders is accessed only after app has been initialised', async ({ page }) => { + await page.goto('/basepath/deserialize'); + await expect(page.locator('p')).toHaveText('Hello world!'); + }); });