Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changeset/gold-spies-fail.md
Original file line number Diff line number Diff line change
@@ -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
7 changes: 6 additions & 1 deletion packages/kit/src/vite/dev/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
6 changes: 3 additions & 3 deletions packages/kit/src/vite/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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) {
Expand Down
73 changes: 52 additions & 21 deletions packages/kit/src/vite/utils.js
Original file line number Diff line number Diff line change
@@ -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';

/**
Expand Down Expand Up @@ -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<string>} illegal_imports
* @param {Set<string>} 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) {
Expand All @@ -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<string>} illegal_imports
* @param {Set<string>} illegal_imports Illegal module IDs -- be sure to call vite.normalizePath!
* @param {Set<string>} seen
* @returns {Array<import('types').ImportNode> | undefined}
* @returns {Array<import('types').ImportNode> | null}
*/
const find_illegal_rollup_imports = (
node_getter,
Expand All @@ -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<string>} 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<string>} illegal_imports
* @param {Set<string>} illegal_imports Illegal module IDs -- be sure to call vite.normalizePath!
* @param {Iterable<string>} 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<string>} illegal_imports
* @param {Set<string>} illegal_imports Illegal module IDs -- be sure to call vite.normalizePath!
* @param {Set<string>} module_types File extensions to analyze: `.ts`, `.js`, etc.
* @param {Set<string>} seen
* @returns {Array<import('types').ImportNode> | 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;
}
3 changes: 2 additions & 1 deletion packages/kit/src/vite/utils.spec.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { test } from 'uvu';
import * as assert from 'uvu/assert';
import { normalizePath } from 'vite';
import {
deep_merge,
merge_vite_configs,
Expand Down Expand Up @@ -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');
Expand Down