Skip to content

Commit 261f571

Browse files
dominikgbluwy
andauthored
feat(preprocess): check preprocess dependencies for anomalies (#767)
* feat(preprocess): check preprocess dependencies for anomalies * fix: ensure we keep native path separators on windows in dependencies array, remove .css check as it is too unreliable * Apply suggestions from code review Co-authored-by: Bjorn Lu <[email protected]> --------- Co-authored-by: Bjorn Lu <[email protected]>
1 parent a7a03d4 commit 261f571

File tree

3 files changed

+78
-2
lines changed

3 files changed

+78
-2
lines changed

.changeset/funny-waves-poke.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@sveltejs/vite-plugin-svelte': minor
3+
---
4+
5+
feat(preprocess): add warnings in case preprocess dependencies contain anomalies

packages/vite-plugin-svelte/src/utils/compile.js

+23-2
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,10 @@ import { createMakeHot } from 'svelte-hmr';
44
import { safeBase64Hash } from './hash.js';
55
import { log } from './log.js';
66

7-
import { createInjectScopeEverythingRulePreprocessorGroup } from './preprocess.js';
7+
import {
8+
checkPreprocessDependencies,
9+
createInjectScopeEverythingRulePreprocessorGroup
10+
} from './preprocess.js';
811
import { mapToRelative } from './sourcemaps.js';
912
import { enhanceCompileError } from './error.js';
1013

@@ -22,7 +25,10 @@ export const _createCompileSvelte = (makeHot) => {
2225
return async function compileSvelte(svelteRequest, code, options) {
2326
const { filename, normalizedFilename, cssId, ssr, raw } = svelteRequest;
2427
const { emitCss = true } = options;
28+
/** @type {string[]} */
2529
const dependencies = [];
30+
/** @type {import('svelte/types/compiler/interfaces').Warning[]} */
31+
const warnings = [];
2632

2733
if (options.stats) {
2834
if (options.isBuild) {
@@ -87,7 +93,16 @@ export const _createCompileSvelte = (makeHot) => {
8793
throw e;
8894
}
8995

90-
if (preprocessed.dependencies) dependencies.push(...preprocessed.dependencies);
96+
if (preprocessed.dependencies?.length) {
97+
const checked = checkPreprocessDependencies(filename, preprocessed.dependencies);
98+
if (checked.warnings.length) {
99+
warnings.push(...checked.warnings);
100+
}
101+
if (checked.dependencies.length) {
102+
dependencies.push(...checked.dependencies);
103+
}
104+
}
105+
91106
if (preprocessed.map) compileOptions.sourcemap = preprocessed.map;
92107
}
93108
if (typeof preprocessed?.map === 'object') {
@@ -134,6 +149,12 @@ export const _createCompileSvelte = (makeHot) => {
134149
}
135150
mapToRelative(compiled.js?.map, filename);
136151
mapToRelative(compiled.css?.map, filename);
152+
if (warnings.length) {
153+
if (!compiled.warnings) {
154+
compiled.warnings = [];
155+
}
156+
compiled.warnings.push(...warnings);
157+
}
137158
if (!raw) {
138159
// wire css import and code for hmr
139160
const hasCss = compiled.css?.code?.trim().length > 0;

packages/vite-plugin-svelte/src/utils/preprocess.js

+50
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import MagicString from 'magic-string';
22
import { log } from './log.js';
33
import path from 'node:path';
4+
import { normalizePath } from 'vite';
45

56
/**
67
* this appends a *{} rule to component styles to force the svelte compiler to add style classes to all nodes
@@ -121,3 +122,52 @@ export function addExtraPreprocessors(options, config) {
121122
}
122123
}
123124
}
125+
126+
/**
127+
*
128+
* @param filename {string}
129+
* @param dependencies {string[]}
130+
* @returns {({dependencies: string[], warnings:import('svelte/types/compiler/interfaces').Warning[] })}
131+
*/
132+
export function checkPreprocessDependencies(filename, dependencies) {
133+
/** @type {import('svelte/types/compiler/interfaces').Warning[]} */
134+
const warnings = [];
135+
136+
// to find self, we have to compare normalized filenames, but must keep the original values in `dependencies`
137+
// because otherwise file watching on windows doesn't work
138+
// so we track idx and filter by that in the end
139+
/** @type {number[]} */
140+
const selfIdx = [];
141+
const normalizedFullFilename = normalizePath(filename);
142+
const normalizedDeps = dependencies.map(normalizePath);
143+
for (let i = 0; i < normalizedDeps.length; i++) {
144+
if (normalizedDeps[i] === normalizedFullFilename) {
145+
selfIdx.push(i);
146+
}
147+
}
148+
const hasSelfDependency = selfIdx.length > 0;
149+
if (hasSelfDependency) {
150+
warnings.push({
151+
code: 'vite-plugin-svelte-preprocess-depends-on-self',
152+
message:
153+
'svelte.preprocess returned this file as a dependency of itself. This can be caused by an invalid configuration or importing generated code that depends on .svelte files (eg. tailwind base css)',
154+
filename
155+
});
156+
}
157+
158+
if (dependencies.length > 10) {
159+
warnings.push({
160+
code: 'vite-plugin-svelte-preprocess-many-dependencies',
161+
message: `svelte.preprocess depends on more than 10 external files which can cause slow builds and poor DX, try to reduce them. Found: ${dependencies.join(
162+
', '
163+
)}`,
164+
filename
165+
});
166+
}
167+
return {
168+
dependencies: hasSelfDependency
169+
? dependencies.filter((_, i) => !selfIdx.includes(i)) // remove self dependency
170+
: dependencies,
171+
warnings
172+
};
173+
}

0 commit comments

Comments
 (0)