diff --git a/.changeset/gold-spies-fail.md b/.changeset/gold-spies-fail.md new file mode 100644 index 000000000000..d4cdaf7b252d --- /dev/null +++ b/.changeset/gold-spies-fail.md @@ -0,0 +1,6 @@ +--- +'@sveltejs/kit': patch +--- + +[fix] Windows correctly errors on `$env/*/private` imports +[fix] Illegal module analysis in dev ignores non-js|ts|svelte files diff --git a/packages/kit/src/vite/dev/index.js b/packages/kit/src/vite/dev/index.js index 41fbea153b68..97abdebc10ba 100644 --- a/packages/kit/src/vite/dev/index.js +++ b/packages/kit/src/vite/dev/index.js @@ -64,7 +64,12 @@ export async function dev(vite, vite_config, svelte_config, illegal_imports) { const node = await vite.moduleGraph.getModuleByUrl(url); if (!node) throw new Error(`Could not find node for ${url}`); - prevent_illegal_vite_imports(node, illegal_imports, svelte_config.kit.outDir); + prevent_illegal_vite_imports( + node, + illegal_imports, + [...svelte_config.extensions, ...svelte_config.kit.moduleExtensions], + svelte_config.kit.outDir + ); return { module, diff --git a/packages/kit/src/vite/index.js b/packages/kit/src/vite/index.js index d01b45b40835..e6d347d66b9b 100644 --- a/packages/kit/src/vite/index.js +++ b/packages/kit/src/vite/index.js @@ -191,8 +191,8 @@ function kit() { }; illegal_imports = new Set([ - `${svelte_config.kit.outDir}/runtime/env/dynamic/private.js`, - `${svelte_config.kit.outDir}/runtime/env/static/private.js` + vite.normalizePath(`${svelte_config.kit.outDir}/runtime/env/dynamic/private.js`), + vite.normalizePath(`${svelte_config.kit.outDir}/runtime/env/static/private.js`) ]); if (is_build) { @@ -283,7 +283,7 @@ function kit() { */ async writeBundle(_options, bundle) { for (const file of manifest_data.components) { - const id = path.resolve(file); + const id = vite.normalizePath(path.resolve(file)); const node = this.getModuleInfo(id); if (node) { diff --git a/packages/kit/src/vite/utils.js b/packages/kit/src/vite/utils.js index 721c9398cb90..c6b252336542 100644 --- a/packages/kit/src/vite/utils.js +++ b/packages/kit/src/vite/utils.js @@ -1,6 +1,6 @@ import fs from 'fs'; import path from 'path'; -import { loadConfigFromFile, loadEnv } from 'vite'; +import { loadConfigFromFile, loadEnv, normalizePath } from 'vite'; import { get_runtime_directory } from '../core/utils.js'; /** @@ -200,7 +200,7 @@ export function get_env(mode, prefix) { /** * @param {(id: string) => import('rollup').ModuleInfo | null} node_getter * @param {import('rollup').ModuleInfo} node - * @param {Set} illegal_imports + * @param {Set} illegal_imports Illegal module IDs -- be sure to call vite.normalizePath! * @param {string} out_dir The directory specified by config.kit.outDir */ export function prevent_illegal_rollup_imports(node_getter, node, illegal_imports, out_dir) { @@ -212,9 +212,9 @@ export function prevent_illegal_rollup_imports(node_getter, node, illegal_import * @param {(id: string) => import('rollup').ModuleInfo | null} node_getter * @param {import('rollup').ModuleInfo} node * @param {boolean} dynamic - * @param {Set} illegal_imports + * @param {Set} illegal_imports Illegal module IDs -- be sure to call vite.normalizePath! * @param {Set} seen - * @returns {Array | undefined} + * @returns {Array | null} */ const find_illegal_rollup_imports = ( node_getter, @@ -223,59 +223,90 @@ const find_illegal_rollup_imports = ( illegal_imports, seen = new Set() ) => { - if (seen.has(node.id)) return; - seen.add(node.id); + const name = normalizePath(node.id); + if (seen.has(name)) return null; + seen.add(name); - if (illegal_imports.has(node.id)) { - return [{ name: node.id, dynamic }]; + if (illegal_imports.has(name)) { + return [{ name, dynamic }]; } for (const id of node.importedIds) { const child = node_getter(id); const chain = child && find_illegal_rollup_imports(node_getter, child, false, illegal_imports, seen); - if (chain) return [{ name: node.id, dynamic }, ...chain]; + if (chain) return [{ name, dynamic }, ...chain]; } for (const id of node.dynamicallyImportedIds) { const child = node_getter(id); const chain = child && find_illegal_rollup_imports(node_getter, child, true, illegal_imports, seen); - if (chain) return [{ name: node.id, dynamic }, ...chain]; + if (chain) return [{ name, dynamic }, ...chain]; } + + seen.delete(name); + return null; +}; + +/** + * Vite does some weird things with import trees in dev + * for example, a Tailwind app.css will appear to import + * every file in the project. This isn't a problem for + * Rollup during build. + * @param {Iterable} config_module_types + */ +const get_module_types = (config_module_types) => { + return new Set([ + '.ts', + '.js', + '.svelte', + '.mts', + '.mjs', + '.cts', + '.cjs', + '.svelte.md', + '.svx', + '.md', + ...config_module_types + ]); }; /** * Throw an error if a private module is imported from a client-side node. * @param {import('vite').ModuleNode} node - * @param {Set} illegal_imports + * @param {Set} illegal_imports Illegal module IDs -- be sure to call vite.normalizePath! + * @param {Iterable} module_types File extensions to analyze in addition to the defaults: `.ts`, `.js`, etc. * @param {string} out_dir The directory specified by config.kit.outDir */ -export function prevent_illegal_vite_imports(node, illegal_imports, out_dir) { - const chain = find_illegal_vite_imports(node, illegal_imports); +export function prevent_illegal_vite_imports(node, illegal_imports, module_types, out_dir) { + const chain = find_illegal_vite_imports(node, illegal_imports, get_module_types(module_types)); if (chain) throw new Error(format_illegal_import_chain(chain, out_dir)); } /** * @param {import('vite').ModuleNode} node - * @param {Set} illegal_imports + * @param {Set} illegal_imports Illegal module IDs -- be sure to call vite.normalizePath! + * @param {Set} module_types File extensions to analyze: `.ts`, `.js`, etc. * @param {Set} seen * @returns {Array | null} */ -function find_illegal_vite_imports(node, illegal_imports, seen = new Set()) { +function find_illegal_vite_imports(node, illegal_imports, module_types, seen = new Set()) { if (!node.id) return null; // TODO when does this happen? + const name = normalizePath(node.id); - if (seen.has(node.id)) return null; - seen.add(node.id); + if (seen.has(name) || !module_types.has(path.extname(name))) return null; + seen.add(name); - if (node.id && illegal_imports.has(node.id)) { - return [{ name: node.id, dynamic: false }]; + if (name && illegal_imports.has(name)) { + return [{ name, dynamic: false }]; } for (const child of node.importedModules) { - const chain = child && find_illegal_vite_imports(child, illegal_imports, seen); - if (chain) return [{ name: node.id, dynamic: false }, ...chain]; + const chain = child && find_illegal_vite_imports(child, illegal_imports, module_types, seen); + if (chain) return [{ name, dynamic: false }, ...chain]; } + seen.delete(name); return null; } diff --git a/packages/kit/src/vite/utils.spec.js b/packages/kit/src/vite/utils.spec.js index dc421e86e5eb..76fa1ca170d3 100644 --- a/packages/kit/src/vite/utils.spec.js +++ b/packages/kit/src/vite/utils.spec.js @@ -1,5 +1,6 @@ import { test } from 'uvu'; import * as assert from 'uvu/assert'; +import { normalizePath } from 'vite'; import { deep_merge, merge_vite_configs, @@ -260,7 +261,7 @@ const rollup_node_getter = (id) => { return nodes[id] ?? null; }; -const illegal_imports = new Set(['/illegal/boom.js']); +const illegal_imports = new Set([normalizePath('/illegal/boom.js')]); const ok_rollup_node = rollup_node_getter('/test/path1.js'); const bad_rollup_node_static = rollup_node_getter('/bad/static.js'); const bad_rollup_node_dynamic = rollup_node_getter('/bad/dynamic.js');