-
-
Notifications
You must be signed in to change notification settings - Fork 2.3k
/
vite.ts
96 lines (87 loc) · 3.63 KB
/
vite.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
import type { ModuleLoader, ModuleNode } from '../../module-loader/index';
import npath from 'path';
import { SUPPORTED_MARKDOWN_FILE_EXTENSIONS } from '../../constants.js';
import { unwrapId } from '../../util.js';
import { isCSSRequest } from './util.js';
/**
* List of file extensions signalling we can (and should) SSR ahead-of-time
* See usage below
*/
const fileExtensionsToSSR = new Set(['.astro', '.mdoc', ...SUPPORTED_MARKDOWN_FILE_EXTENSIONS]);
const STRIP_QUERY_PARAMS_REGEX = /\?.*$/;
const ASTRO_PROPAGATED_ASSET_REGEX = /\?astroPropagatedAssets/;
/** recursively crawl the module graph to get all style files imported by parent id */
export async function* crawlGraph(
loader: ModuleLoader,
_id: string,
isRootFile: boolean,
scanned = new Set<string>()
): AsyncGenerator<ModuleNode, void, unknown> {
const id = unwrapId(_id);
const importedModules = new Set<ModuleNode>();
const moduleEntriesForId = isRootFile
? // "getModulesByFile" pulls from a delayed module cache (fun implementation detail),
// So we can get up-to-date info on initial server load.
// Needed for slower CSS preprocessing like Tailwind
loader.getModulesByFile(id) ?? new Set()
: // For non-root files, we're safe to pull from "getModuleById" based on testing.
// TODO: Find better invalidation strat to use "getModuleById" in all cases!
new Set([loader.getModuleById(id)]);
// Collect all imported modules for the module(s).
for (const entry of moduleEntriesForId) {
// Handle this in case an module entries weren't found for ID
// This seems possible with some virtual IDs (ex: `astro:markdown/*.md`)
if (!entry) {
continue;
}
if (id === entry.id) {
scanned.add(id);
const entryIsStyle = isCSSRequest(id);
for (const importedModule of entry.importedModules) {
// some dynamically imported modules are *not* server rendered in time
// to only SSR modules that we can safely transform, we check against
// a list of file extensions based on our built-in vite plugins
if (importedModule.id) {
// Strip special query params like "?content".
// NOTE: Cannot use `new URL()` here because not all IDs will be valid paths.
// For example, `virtual:image-loader` if you don't have the plugin installed.
const importedModulePathname = importedModule.id.replace(STRIP_QUERY_PARAMS_REGEX, '');
// If the entry is a style, skip any modules that are not also styles.
// Tools like Tailwind might add HMR dependencies as `importedModules`
// but we should skip them--they aren't really imported. Without this,
// every hoisted script in the project is added to every page!
if (entryIsStyle && !isCSSRequest(importedModulePathname)) {
continue;
}
const isFileTypeNeedingSSR = fileExtensionsToSSR.has(
npath.extname(importedModulePathname)
);
if (
isFileTypeNeedingSSR &&
// Should not SSR a module with ?astroPropagatedAssets
!ASTRO_PROPAGATED_ASSET_REGEX.test(importedModule.id)
) {
const mod = loader.getModuleById(importedModule.id);
if (!mod?.ssrModule) {
try {
await loader.import(importedModule.id);
} catch {
/** Likely an out-of-date module entry! Silently continue. */
}
}
}
}
importedModules.add(importedModule);
}
}
}
// scan imported modules for CSS imports & add them to our collection.
// Then, crawl that file to follow and scan all deep imports as well.
for (const importedModule of importedModules) {
if (!importedModule.id || scanned.has(importedModule.id)) {
continue;
}
yield importedModule;
yield* crawlGraph(loader, importedModule.id, false, scanned);
}
}