Skip to content

Commit

Permalink
feat: Improve errors from dev-time illegal module imports (#13329)
Browse files Browse the repository at this point in the history
* feat: Improve errors from dev-time illegal module imports

* periodt

* Update packages/kit/src/exports/vite/index.js

Co-authored-by: Willow (GHOST) <[email protected]>

* chore: tests

* fix tests

* format

---------

Co-authored-by: Simon H <[email protected]>
Co-authored-by: Willow (GHOST) <[email protected]>
Co-authored-by: Chew Tee Ming <[email protected]>
  • Loading branch information
4 people authored Jan 22, 2025
1 parent cc6dace commit 416dbdf
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 26 deletions.
11 changes: 9 additions & 2 deletions packages/kit/src/exports/vite/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -421,15 +421,22 @@ async function kit({ svelte_config }) {

const illegal_module = strip_virtual_prefix(relative);

const error_prefix = `Cannot import ${illegal_module} into client-side code. This could leak sensitive information.`;
const error_suffix = `
Tips:
- To resolve this error, ensure that no exports from ${illegal_module} are used, even transitively, in client-side code.
- If you're only using the import as a type, change it to \`import type\`.
- If you're not sure which module is causing this, try building your app -- it will create a more helpful error.`;

if (import_map.has(illegal_module)) {
const importer = path.relative(
cwd,
/** @type {string} */ (import_map.get(illegal_module))
);
throw new Error(`Cannot import ${illegal_module} into client-side code: ${importer}`);
throw new Error(`${error_prefix}\nImported by: ${importer}.${error_suffix}`);
}

throw new Error(`Cannot import ${illegal_module} into client-side code`);
throw new Error(`${error_prefix}${error_suffix}`);
}
}

Expand Down
76 changes: 52 additions & 24 deletions packages/kit/test/apps/dev-only/test/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,72 +16,100 @@ test.describe.serial('Illegal imports', () => {
await page.goto('/illegal-imports/env/dynamic-private', {
wait_for_started: false
});
expect(await page.textContent('.message-body')).toBe(
'Cannot import $env/dynamic/private into client-side code: src/routes/illegal-imports/env/dynamic-private/+page.svelte'
);
expect(await page.textContent('.message-body'))
.toBe(`Cannot import $env/dynamic/private into client-side code. This could leak sensitive information.
Imported by: src/routes/illegal-imports/env/dynamic-private/+page.svelte.
Tips:
- To resolve this error, ensure that no exports from $env/dynamic/private are used, even transitively, in client-side code.
- If you're only using the import as a type, change it to \`import type\`.
- If you're not sure which module is causing this, try building your app -- it will create a more helpful error.`);
});

test('$env/dynamic/private is not dynamically importable from the client', async ({ page }) => {
await page.goto('/illegal-imports/env/dynamic-private-dynamic-import', {
wait_for_started: false
});
expect(await page.textContent('.message-body')).toBe(
'Cannot import $env/dynamic/private into client-side code: src/routes/illegal-imports/env/dynamic-private-dynamic-import/+page.svelte'
);
expect(await page.textContent('.message-body'))
.toBe(`Cannot import $env/dynamic/private into client-side code. This could leak sensitive information.
Imported by: src/routes/illegal-imports/env/dynamic-private-dynamic-import/+page.svelte.
Tips:
- To resolve this error, ensure that no exports from $env/dynamic/private are used, even transitively, in client-side code.
- If you're only using the import as a type, change it to \`import type\`.
- If you're not sure which module is causing this, try building your app -- it will create a more helpful error.`);
});

test('$env/static/private is not statically importable from the client', async ({ page }) => {
await page.goto('/illegal-imports/env/static-private', {
wait_for_started: false
});
expect(await page.textContent('.message-body')).toBe(
'Cannot import $env/static/private into client-side code: src/routes/illegal-imports/env/static-private/+page.svelte'
);
expect(await page.textContent('.message-body'))
.toBe(`Cannot import $env/static/private into client-side code. This could leak sensitive information.
Imported by: src/routes/illegal-imports/env/static-private/+page.svelte.
Tips:
- To resolve this error, ensure that no exports from $env/static/private are used, even transitively, in client-side code.
- If you're only using the import as a type, change it to \`import type\`.
- If you're not sure which module is causing this, try building your app -- it will create a more helpful error.`);
});

test('$env/static/private is not dynamically importable from the client', async ({ page }) => {
await page.goto('/illegal-imports/env/static-private-dynamic-import', {
wait_for_started: false
});
expect(await page.textContent('.message-body')).toBe(
'Cannot import $env/static/private into client-side code: src/routes/illegal-imports/env/static-private-dynamic-import/+page.svelte'
);
expect(await page.textContent('.message-body'))
.toBe(`Cannot import $env/static/private into client-side code. This could leak sensitive information.
Imported by: src/routes/illegal-imports/env/static-private-dynamic-import/+page.svelte.
Tips:
- To resolve this error, ensure that no exports from $env/static/private are used, even transitively, in client-side code.
- If you're only using the import as a type, change it to \`import type\`.
- If you're not sure which module is causing this, try building your app -- it will create a more helpful error.`);
});

test('server-only module is not statically importable from the client', async ({ page }) => {
await page.goto('/illegal-imports/server-only-modules/static-import', {
wait_for_started: false
});
expect(await page.textContent('.message-body')).toBe(
'Cannot import src/routes/illegal-imports/server-only-modules/illegal.server.js into client-side code'
);
expect(await page.textContent('.message-body'))
.toBe(`Cannot import src/routes/illegal-imports/server-only-modules/illegal.server.js into client-side code. This could leak sensitive information.
Tips:
- To resolve this error, ensure that no exports from src/routes/illegal-imports/server-only-modules/illegal.server.js are used, even transitively, in client-side code.
- If you're only using the import as a type, change it to \`import type\`.
- If you're not sure which module is causing this, try building your app -- it will create a more helpful error.`);
});

test('server-only module is not dynamically importable from the client', async ({ page }) => {
await page.goto('/illegal-imports/server-only-modules/dynamic-import', {
wait_for_started: false
});
expect(await page.textContent('.message-body')).toBe(
'Cannot import src/routes/illegal-imports/server-only-modules/illegal.server.js into client-side code'
);
expect(await page.textContent('.message-body'))
.toBe(`Cannot import src/routes/illegal-imports/server-only-modules/illegal.server.js into client-side code. This could leak sensitive information.
Tips:
- To resolve this error, ensure that no exports from src/routes/illegal-imports/server-only-modules/illegal.server.js are used, even transitively, in client-side code.
- If you're only using the import as a type, change it to \`import type\`.
- If you're not sure which module is causing this, try building your app -- it will create a more helpful error.`);
});

test('server-only folder is not statically importable from the client', async ({ page }) => {
await page.goto('/illegal-imports/server-only-folder/static-import', {
wait_for_started: false
});
expect(await page.textContent('.message-body')).toBe(
'Cannot import $lib/server/blah/private.js into client-side code'
);
expect(await page.textContent('.message-body'))
.toBe(`Cannot import $lib/server/blah/private.js into client-side code. This could leak sensitive information.
Tips:
- To resolve this error, ensure that no exports from $lib/server/blah/private.js are used, even transitively, in client-side code.
- If you're only using the import as a type, change it to \`import type\`.
- If you're not sure which module is causing this, try building your app -- it will create a more helpful error.`);
});

test('server-only folder is not dynamically importable from the client', async ({ page }) => {
await page.goto('/illegal-imports/server-only-folder/dynamic-import', {
wait_for_started: false
});
expect(await page.textContent('.message-body')).toBe(
'Cannot import $lib/server/blah/private.js into client-side code'
);
expect(await page.textContent('.message-body'))
.toBe(`Cannot import $lib/server/blah/private.js into client-side code. This could leak sensitive information.
Tips:
- To resolve this error, ensure that no exports from $lib/server/blah/private.js are used, even transitively, in client-side code.
- If you're only using the import as a type, change it to \`import type\`.
- If you're not sure which module is causing this, try building your app -- it will create a more helpful error.`);
});
});

Expand Down

0 comments on commit 416dbdf

Please sign in to comment.