Skip to content

Commit d96c5b8

Browse files
committed
fix: simplify style collection further and properly handle dynamic imports via transformResult
1 parent f594c2f commit d96c5b8

2 files changed

Lines changed: 37 additions & 81 deletions

File tree

packages/start/src/config/manifest.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
1-
import { PluginOption } from "vite";
1+
import { PluginOption, ViteDevServer } from "vite";
22

3+
import { findStylesInModuleGraph } from "../server/collect-styles.ts";
34
import { VIRTUAL_MODULES } from "./constants.ts";
45
import { SolidStartOptions } from "./index.ts";
5-
import { findStylesInModuleGraph } from "../server/collect-styles.ts";
66

77
export function manifest(start: SolidStartOptions): PluginOption {
8+
let devServer: ViteDevServer = undefined!;
89
return {
910
name: "solid-start:manifest-plugin",
1011
enforce: "pre",
12+
configureServer(server) { devServer = server },
1113
async resolveId(id) {
1214
if (id === VIRTUAL_MODULES.clientViteManifest)
1315
return `\0${VIRTUAL_MODULES.clientViteManifest}`;
@@ -63,10 +65,12 @@ export function manifest(start: SolidStartOptions): PluginOption {
6365
throw new Error("Missing id to get assets.");
6466
}
6567

68+
// Client env does not have css dependencies in mod.transformResult
69+
// Aalways use ssr env instead, to prevent hydration mismatches
70+
const env = devServer.environments['ssr']
6671
const styles = await findStylesInModuleGraph(
67-
this.environment,
72+
env,
6873
id,
69-
target === "ssr",
7074
);
7175

7276
const cssAssets = Object.entries(styles).map(([key, value]) => `{

packages/start/src/server/collect-styles.ts

Lines changed: 29 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,9 @@ import path from "node:path";
22
import { resolve } from "pathe";
33
import type { DevEnvironment, EnvironmentModuleNode } from "vite";
44

5-
const prepareTransformResult = async (vite: DevEnvironment, module: EnvironmentModuleNode) => {
6-
if (module.transformResult || !module.id) return;
7-
8-
await vite.transformRequest(module.id).catch(() => {});
9-
};
10-
115
async function getViteModuleNode(
126
vite: DevEnvironment,
137
file: string,
14-
ssr = false,
158
) {
169
let nodePath = file;
1710
let node = vite.moduleGraph.getModuleById(file);
@@ -34,38 +27,36 @@ async function getViteModuleNode(
3427
node = vite.moduleGraph.getModuleById(nodePath);
3528
}
3629

37-
if (!node) return;
38-
39-
await prepareTransformResult(vite, node);
40-
4130
return node;
4231
}
4332

4433
async function findModuleDependencies(
45-
vite: DevEnvironment,
46-
module: EnvironmentModuleNode,
47-
ssr = false,
34+
vite: DevEnvironment,
35+
file: string,
4836
deps: Set<EnvironmentModuleNode>,
37+
crawledFiles = new Set<string>()
4938
) {
50-
async function add(module: EnvironmentModuleNode) {
51-
if (!deps.has(module)) {
52-
deps.add(module);
53-
await findModuleDependencies(vite, module, ssr, deps);
54-
}
55-
}
56-
57-
async function addByUrl(url: string, ssr: boolean) {
58-
const node = await getViteModuleNode(vite, url, ssr);
59-
60-
if (node) await add(node);
61-
}
39+
crawledFiles.add(file);
40+
const module = await getViteModuleNode(vite, file);
41+
if (!module?.id || deps.has(module)) return;
6242

43+
deps.add(module);
44+
6345
if (module.url.endsWith(".css") || module.url.includes("node_modules")) return;
6446

65-
if (ssr) await prepareTransformResult(vite, module);
66-
67-
for (const mod of module.importedModules) {
68-
await addByUrl(mod.url, ssr);
47+
if (!module.transformResult) {
48+
await vite.transformRequest(module.id).catch(() => {});
49+
}
50+
if (!module.transformResult?.deps) return;
51+
52+
// Relying on module.transformResult.deps instead of module.importedModules because:
53+
// transformResult properly separates imports into deps and dynamicDeps, importedModules doesn't
54+
// Style crawling has to skip dynamic imports as such modules load their styles themselves
55+
for (const dep of module.transformResult.deps) {
56+
if (crawledFiles.has(dep)) {
57+
continue;
58+
}
59+
await findModuleDependencies(vite, dep, deps, crawledFiles);
6960
}
7061
}
7162

@@ -79,61 +70,22 @@ const cssModulesRegExp = new RegExp(`\\.module${cssFileRegExp.source}`);
7970
const isCssFile = (file: string) => cssFileRegExp.test(file);
8071
export const isCssModulesFile = (file: string) => cssModulesRegExp.test(file);
8172

82-
// https://github.com/remix-run/remix/blob/65326e39099f3b2285d83aecfe734ba35f668396/packages/remix-dev/vite/styles.ts#L29
83-
const cssUrlParamsWithoutSideEffects = ["url", "inline", "raw", "inline-css"];
84-
export const isCssUrlWithoutSideEffects = (url: string) => {
85-
const queryString = url.split("?")[1];
86-
87-
if (!queryString) {
88-
return false;
89-
}
90-
91-
const params = new URLSearchParams(queryString);
92-
for (const paramWithoutSideEffects of cssUrlParamsWithoutSideEffects) {
93-
if (
94-
// Parameter is blank and not explicitly set, i.e. "?url", not "?url="
95-
params.get(paramWithoutSideEffects) === "" &&
96-
!url.includes(`?${paramWithoutSideEffects}=`) &&
97-
!url.includes(`&${paramWithoutSideEffects}=`)
98-
) {
99-
return true;
100-
}
101-
}
102-
103-
return false;
104-
};
105-
106-
async function findFilesDepedencies(
107-
vite: DevEnvironment,
108-
files: Array<string>,
109-
ssr = false,
110-
deps = new Set<EnvironmentModuleNode>(),
111-
) {
112-
for (const file of files) {
113-
try {
114-
const node = await getViteModuleNode(vite, file, ssr);
115-
if (node) await findModuleDependencies(vite, node, ssr, deps);
116-
} catch (e) {
117-
console.error(e);
118-
}
119-
}
120-
121-
return deps;
122-
}
123-
12473
export async function findStylesInModuleGraph(
125-
vite: DevEnvironment,
74+
vite: DevEnvironment,
12675
id: string,
127-
ssr = false,
12876
) {
12977
const absolute = path.resolve(process.cwd(), id);
78+
const dependencies = new Set<EnvironmentModuleNode>();
13079

131-
const dependencies = await findFilesDepedencies(vite, [absolute], ssr);
80+
try {
81+
await findModuleDependencies(vite, absolute, dependencies);
82+
} catch (e) {
83+
console.error(e);
84+
}
13285

13386
const styles: Record<string, any> = {};
134-
13587
for (const dep of dependencies) {
136-
if (isCssFile(dep.url) && dep.id) {
88+
if (dep.id && isCssFile(dep.url)) {
13789
styles[dep.id] = dep.url;
13890
}
13991
}

0 commit comments

Comments
 (0)