zyzz 0.0.27 → 0.0.29
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/binding/wasi/wasi-worker.mjs +186 -0
- package/binding/wasi/zyzz.wasi.cjs +2302 -0
- package/binding/wasi/zyzz.wasm32-wasi.wasm +0 -0
- package/binding/zyzz.linux-x64-gnu.node +0 -0
- package/dist/babel/index.d.ts.map +1 -1
- package/dist/babel/index.js +2 -4
- package/dist/babel/index.js.map +1 -1
- package/dist/babel/internal/Compilation.d.ts +0 -1
- package/dist/babel/internal/Compilation.d.ts.map +1 -1
- package/dist/compiler/Graph.d.ts +14 -11
- package/dist/compiler/Graph.d.ts.map +1 -1
- package/dist/compiler/Graph.js +57 -1442
- package/dist/compiler/Graph.js.map +1 -1
- package/dist/compiler/Native.d.ts +7 -9
- package/dist/compiler/Native.d.ts.map +1 -1
- package/dist/compiler/Native.js +12 -716
- package/dist/compiler/Native.js.map +1 -1
- package/dist/compiler/Source.d.ts +122 -24
- package/dist/compiler/Source.d.ts.map +1 -1
- package/dist/compiler/Source.js +10 -1113
- package/dist/compiler/Source.js.map +1 -1
- package/dist/compiler/Transform.d.ts +4 -3
- package/dist/compiler/Transform.d.ts.map +1 -1
- package/dist/compiler/Transform.js +13 -958
- package/dist/compiler/Transform.js.map +1 -1
- package/dist/compiler/internal/AtRules.d.ts +5 -1
- package/dist/compiler/internal/AtRules.d.ts.map +1 -1
- package/dist/compiler/internal/AtRules.js +12 -106
- package/dist/compiler/internal/AtRules.js.map +1 -1
- package/dist/compiler/internal/Context.d.ts +11 -0
- package/dist/compiler/internal/Context.d.ts.map +1 -0
- package/dist/compiler/internal/Context.js +11 -0
- package/dist/compiler/internal/Context.js.map +1 -0
- package/dist/compiler/internal/Results.d.ts +148 -0
- package/dist/compiler/internal/Results.d.ts.map +1 -0
- package/dist/compiler/internal/Results.js +259 -0
- package/dist/compiler/internal/Results.js.map +1 -0
- package/dist/compiler/internal/Syntax.d.ts +0 -2
- package/dist/compiler/internal/Syntax.d.ts.map +1 -1
- package/dist/compiler/internal/Syntax.js +0 -2
- package/dist/compiler/internal/Syntax.js.map +1 -1
- package/dist/compiler/internal/Wire.d.ts +17 -0
- package/dist/compiler/internal/Wire.d.ts.map +1 -0
- package/dist/compiler/internal/Wire.js +795 -0
- package/dist/compiler/internal/Wire.js.map +1 -0
- package/dist/internal/Addon.d.ts +28 -0
- package/dist/internal/Addon.d.ts.map +1 -0
- package/dist/internal/Addon.js +87 -0
- package/dist/internal/Addon.js.map +1 -0
- package/dist/internal/Authoring.d.ts.map +1 -1
- package/dist/internal/Authoring.js +37 -7
- package/dist/internal/Authoring.js.map +1 -1
- package/dist/internal/Configuration.d.ts +6 -1
- package/dist/internal/Configuration.d.ts.map +1 -1
- package/dist/internal/Configuration.js.map +1 -1
- package/dist/internal/Literal.d.ts +5 -2
- package/dist/internal/Literal.d.ts.map +1 -1
- package/dist/internal/Literal.js +7 -2
- package/dist/internal/Literal.js.map +1 -1
- package/dist/internal/Theme.d.ts +4 -0
- package/dist/internal/Theme.d.ts.map +1 -1
- package/dist/internal/Theme.js.map +1 -1
- package/dist/internal/Token.d.ts +2 -1
- package/dist/internal/Token.d.ts.map +1 -1
- package/dist/internal/Token.js +2 -2
- package/dist/internal/Token.js.map +1 -1
- package/dist/internal/Vlq.d.ts +14 -0
- package/dist/internal/Vlq.d.ts.map +1 -0
- package/dist/internal/Vlq.js +47 -0
- package/dist/internal/Vlq.js.map +1 -0
- package/dist/internal/Wasm.d.ts +22 -0
- package/dist/internal/Wasm.d.ts.map +1 -0
- package/dist/internal/Wasm.js +83 -0
- package/dist/internal/Wasm.js.map +1 -0
- package/dist/metro/Graph.d.ts +0 -1
- package/dist/metro/Graph.d.ts.map +1 -1
- package/dist/metro/transformer.d.ts.map +1 -1
- package/dist/metro/transformer.js +0 -1
- package/dist/metro/transformer.js.map +1 -1
- package/dist/next/internal/Project.d.ts.map +1 -1
- package/dist/next/internal/Project.js +2 -5
- package/dist/next/internal/Project.js.map +1 -1
- package/dist/node/Host.d.ts.map +1 -1
- package/dist/node/Host.js +0 -2
- package/dist/node/Host.js.map +1 -1
- package/dist/node/internal/Contracts.d.ts.map +1 -1
- package/dist/node/internal/Contracts.js +3 -7
- package/dist/node/internal/Contracts.js.map +1 -1
- package/dist/node/internal/Snapshot.d.ts +0 -1
- package/dist/node/internal/Snapshot.d.ts.map +1 -1
- package/dist/node/internal/Snapshot.js +0 -6
- package/dist/node/internal/Snapshot.js.map +1 -1
- package/dist/runtime/Composition.d.ts +2 -3
- package/dist/runtime/Composition.d.ts.map +1 -1
- package/dist/runtime/Composition.js +51 -30
- package/dist/runtime/Composition.js.map +1 -1
- package/dist/runtime/Recipe.d.ts.map +1 -1
- package/dist/runtime/Recipe.js +16 -12
- package/dist/runtime/Recipe.js.map +1 -1
- package/dist/styleFunction.d.ts +11 -2
- package/dist/styleFunction.d.ts.map +1 -1
- package/dist/styleFunction.js +3 -1
- package/dist/styleFunction.js.map +1 -1
- package/dist/unplugin/index.d.ts.map +1 -1
- package/dist/unplugin/index.js +3 -6
- package/dist/unplugin/index.js.map +1 -1
- package/dist/vite/index.d.ts +7 -0
- package/dist/vite/index.d.ts.map +1 -1
- package/dist/vite/index.js +862 -216
- package/dist/vite/index.js.map +1 -1
- package/dist/web/Css.d.ts +8 -3
- package/dist/web/Css.d.ts.map +1 -1
- package/dist/web/Css.js +5 -721
- package/dist/web/Css.js.map +1 -1
- package/dist/web/internal/Block.d.ts +0 -2
- package/dist/web/internal/Block.d.ts.map +1 -1
- package/dist/web/internal/Block.js +1 -12
- package/dist/web/internal/Block.js.map +1 -1
- package/dist/web/internal/ClassName.d.ts +23 -18
- package/dist/web/internal/ClassName.d.ts.map +1 -1
- package/dist/web/internal/ClassName.js +26 -55
- package/dist/web/internal/ClassName.js.map +1 -1
- package/dist/web/internal/Contributions.d.ts +3 -5
- package/dist/web/internal/Contributions.d.ts.map +1 -1
- package/dist/web/internal/Contributions.js +0 -45
- package/dist/web/internal/Contributions.js.map +1 -1
- package/dist/web/internal/Engine.browser.d.ts +8 -0
- package/dist/web/internal/Engine.browser.d.ts.map +1 -0
- package/dist/web/internal/Engine.browser.js +42 -0
- package/dist/web/internal/Engine.browser.js.map +1 -0
- package/dist/web/internal/Engine.d.ts +9 -0
- package/dist/web/internal/Engine.d.ts.map +1 -0
- package/dist/web/internal/Engine.js +14 -0
- package/dist/web/internal/Engine.js.map +1 -0
- package/dist/web/internal/Themes.d.ts +1 -9
- package/dist/web/internal/Themes.d.ts.map +1 -1
- package/dist/web/internal/Themes.js +3 -221
- package/dist/web/internal/Themes.js.map +1 -1
- package/dist/web/internal/Wasm.generated.d.ts +4 -0
- package/dist/web/internal/Wasm.generated.d.ts.map +1 -0
- package/dist/web/internal/Wasm.generated.js +4 -0
- package/dist/web/internal/Wasm.generated.js.map +1 -0
- package/dist/web/internal/Wire.d.ts +19 -0
- package/dist/web/internal/Wire.d.ts.map +1 -0
- package/dist/web/internal/Wire.js +387 -0
- package/dist/web/internal/Wire.js.map +1 -0
- package/package.json +20 -1
- package/src/babel/index.ts +2 -5
- package/src/babel/internal/Compilation.ts +0 -1
- package/src/compiler/Graph.ts +89 -1930
- package/src/compiler/Native.ts +18 -871
- package/src/compiler/Source.ts +144 -1579
- package/src/compiler/Transform.ts +16 -1312
- package/src/compiler/internal/AtRules.ts +27 -115
- package/src/compiler/internal/Context.ts +11 -0
- package/src/compiler/internal/Results.ts +406 -0
- package/src/compiler/internal/Syntax.ts +0 -3
- package/src/compiler/internal/Wire.ts +1045 -0
- package/src/internal/Addon.ts +118 -0
- package/src/internal/Authoring.ts +53 -18
- package/src/internal/Configuration.ts +38 -1
- package/src/internal/Literal.ts +7 -2
- package/src/internal/Theme.ts +15 -0
- package/src/internal/Token.ts +2 -2
- package/src/internal/Vlq.ts +59 -0
- package/src/internal/Wasm.ts +111 -0
- package/src/metro/transformer.ts +0 -1
- package/src/next/internal/Project.ts +2 -9
- package/src/node/Host.ts +0 -2
- package/src/node/internal/Contracts.ts +3 -7
- package/src/node/internal/Snapshot.ts +0 -8
- package/src/runtime/Composition.ts +48 -25
- package/src/runtime/Recipe.ts +21 -14
- package/src/styleFunction.ts +31 -2
- package/src/unplugin/index.ts +6 -6
- package/src/vite/index.ts +1157 -241
- package/src/web/Css.ts +12 -908
- package/src/web/internal/Block.ts +0 -14
- package/src/web/internal/ClassName.ts +52 -85
- package/src/web/internal/Contributions.ts +3 -59
- package/src/web/internal/Engine.browser.ts +51 -0
- package/src/web/internal/Engine.ts +17 -0
- package/src/web/internal/Themes.ts +3 -279
- package/src/web/internal/Wasm.generated.ts +3 -0
- package/src/web/internal/Wire.ts +466 -0
- package/src/web/internal/wasm.d.ts +9 -0
- package/dist/compiler/internal/Applications.d.ts +0 -55
- package/dist/compiler/internal/Applications.d.ts.map +0 -1
- package/dist/compiler/internal/Applications.js +0 -352
- package/dist/compiler/internal/Applications.js.map +0 -1
- package/dist/compiler/internal/ColorProfiles.d.ts +0 -3
- package/dist/compiler/internal/ColorProfiles.d.ts.map +0 -1
- package/dist/compiler/internal/ColorProfiles.js +0 -84
- package/dist/compiler/internal/ColorProfiles.js.map +0 -1
- package/dist/compiler/internal/CompositionBindings.d.ts +0 -16
- package/dist/compiler/internal/CompositionBindings.d.ts.map +0 -1
- package/dist/compiler/internal/CompositionBindings.js +0 -89
- package/dist/compiler/internal/CompositionBindings.js.map +0 -1
- package/dist/compiler/internal/Compositions.d.ts +0 -37
- package/dist/compiler/internal/Compositions.d.ts.map +0 -1
- package/dist/compiler/internal/Compositions.js +0 -494
- package/dist/compiler/internal/Compositions.js.map +0 -1
- package/dist/compiler/internal/Configurations.d.ts +0 -26
- package/dist/compiler/internal/Configurations.d.ts.map +0 -1
- package/dist/compiler/internal/Configurations.js +0 -259
- package/dist/compiler/internal/Configurations.js.map +0 -1
- package/dist/compiler/internal/Contract.d.ts +0 -30
- package/dist/compiler/internal/Contract.d.ts.map +0 -1
- package/dist/compiler/internal/Contract.js +0 -753
- package/dist/compiler/internal/Contract.js.map +0 -1
- package/dist/compiler/internal/Contributions.d.ts +0 -54
- package/dist/compiler/internal/Contributions.d.ts.map +0 -1
- package/dist/compiler/internal/Contributions.js +0 -1151
- package/dist/compiler/internal/Contributions.js.map +0 -1
- package/dist/compiler/internal/Descriptors.d.ts +0 -15
- package/dist/compiler/internal/Descriptors.d.ts.map +0 -1
- package/dist/compiler/internal/Descriptors.js +0 -192
- package/dist/compiler/internal/Descriptors.js.map +0 -1
- package/dist/compiler/internal/Dynamic.d.ts +0 -14
- package/dist/compiler/internal/Dynamic.d.ts.map +0 -1
- package/dist/compiler/internal/Dynamic.js +0 -175
- package/dist/compiler/internal/Dynamic.js.map +0 -1
- package/dist/compiler/internal/Expression.d.ts +0 -19
- package/dist/compiler/internal/Expression.d.ts.map +0 -1
- package/dist/compiler/internal/Expression.js +0 -164
- package/dist/compiler/internal/Expression.js.map +0 -1
- package/dist/compiler/internal/Functions.d.ts +0 -5
- package/dist/compiler/internal/Functions.d.ts.map +0 -1
- package/dist/compiler/internal/Functions.js +0 -191
- package/dist/compiler/internal/Functions.js.map +0 -1
- package/dist/compiler/internal/Keyframes.d.ts +0 -5
- package/dist/compiler/internal/Keyframes.d.ts.map +0 -1
- package/dist/compiler/internal/Keyframes.js +0 -51
- package/dist/compiler/internal/Keyframes.js.map +0 -1
- package/dist/compiler/internal/Names.d.ts +0 -5
- package/dist/compiler/internal/Names.d.ts.map +0 -1
- package/dist/compiler/internal/Names.js +0 -37
- package/dist/compiler/internal/Names.js.map +0 -1
- package/dist/compiler/internal/NativeBindings.d.ts +0 -72
- package/dist/compiler/internal/NativeBindings.d.ts.map +0 -1
- package/dist/compiler/internal/NativeBindings.js +0 -171
- package/dist/compiler/internal/NativeBindings.js.map +0 -1
- package/dist/compiler/internal/NativeMedia.d.ts +0 -14
- package/dist/compiler/internal/NativeMedia.d.ts.map +0 -1
- package/dist/compiler/internal/NativeMedia.js +0 -287
- package/dist/compiler/internal/NativeMedia.js.map +0 -1
- package/dist/compiler/internal/NativeVars.d.ts +0 -28
- package/dist/compiler/internal/NativeVars.d.ts.map +0 -1
- package/dist/compiler/internal/NativeVars.js +0 -160
- package/dist/compiler/internal/NativeVars.js.map +0 -1
- package/dist/compiler/internal/PackedStyles.d.ts +0 -37
- package/dist/compiler/internal/PackedStyles.d.ts.map +0 -1
- package/dist/compiler/internal/PackedStyles.js +0 -344
- package/dist/compiler/internal/PackedStyles.js.map +0 -1
- package/dist/compiler/internal/Properties.d.ts +0 -5
- package/dist/compiler/internal/Properties.d.ts.map +0 -1
- package/dist/compiler/internal/Properties.js +0 -82
- package/dist/compiler/internal/Properties.js.map +0 -1
- package/dist/compiler/internal/RecipeConditions.d.ts +0 -41
- package/dist/compiler/internal/RecipeConditions.d.ts.map +0 -1
- package/dist/compiler/internal/RecipeConditions.js +0 -82
- package/dist/compiler/internal/RecipeConditions.js.map +0 -1
- package/dist/compiler/internal/RecipePayloads.d.ts +0 -31
- package/dist/compiler/internal/RecipePayloads.d.ts.map +0 -1
- package/dist/compiler/internal/RecipePayloads.js +0 -99
- package/dist/compiler/internal/RecipePayloads.js.map +0 -1
- package/dist/compiler/internal/Recipes.d.ts +0 -32
- package/dist/compiler/internal/Recipes.d.ts.map +0 -1
- package/dist/compiler/internal/Recipes.js +0 -339
- package/dist/compiler/internal/Recipes.js.map +0 -1
- package/dist/compiler/internal/Selectors.d.ts +0 -12
- package/dist/compiler/internal/Selectors.d.ts.map +0 -1
- package/dist/compiler/internal/Selectors.js +0 -268
- package/dist/compiler/internal/Selectors.js.map +0 -1
- package/dist/compiler/internal/Static.d.ts +0 -39
- package/dist/compiler/internal/Static.d.ts.map +0 -1
- package/dist/compiler/internal/Static.js +0 -534
- package/dist/compiler/internal/Static.js.map +0 -1
- package/dist/compiler/internal/Themes.d.ts +0 -190
- package/dist/compiler/internal/Themes.d.ts.map +0 -1
- package/dist/compiler/internal/Themes.js +0 -1577
- package/dist/compiler/internal/Themes.js.map +0 -1
- package/dist/compiler/internal/Vars.d.ts +0 -33
- package/dist/compiler/internal/Vars.d.ts.map +0 -1
- package/dist/compiler/internal/Vars.js +0 -387
- package/dist/compiler/internal/Vars.js.map +0 -1
- package/dist/compiler/internal/ViewTransitions.d.ts +0 -3
- package/dist/compiler/internal/ViewTransitions.d.ts.map +0 -1
- package/dist/compiler/internal/ViewTransitions.js +0 -68
- package/dist/compiler/internal/ViewTransitions.js.map +0 -1
- package/dist/internal/Cascade.d.ts +0 -74
- package/dist/internal/Cascade.d.ts.map +0 -1
- package/dist/internal/Cascade.js +0 -210
- package/dist/internal/Cascade.js.map +0 -1
- package/src/compiler/internal/Applications.ts +0 -554
- package/src/compiler/internal/ColorProfiles.ts +0 -93
- package/src/compiler/internal/CompositionBindings.ts +0 -120
- package/src/compiler/internal/Compositions.ts +0 -678
- package/src/compiler/internal/Configurations.ts +0 -349
- package/src/compiler/internal/Contract.ts +0 -1028
- package/src/compiler/internal/Contributions.ts +0 -1561
- package/src/compiler/internal/Descriptors.ts +0 -242
- package/src/compiler/internal/Dynamic.ts +0 -275
- package/src/compiler/internal/Expression.ts +0 -218
- package/src/compiler/internal/Functions.ts +0 -206
- package/src/compiler/internal/Keyframes.ts +0 -62
- package/src/compiler/internal/Names.ts +0 -48
- package/src/compiler/internal/NativeBindings.ts +0 -235
- package/src/compiler/internal/NativeMedia.ts +0 -342
- package/src/compiler/internal/NativeVars.ts +0 -231
- package/src/compiler/internal/PackedStyles.ts +0 -473
- package/src/compiler/internal/Properties.ts +0 -121
- package/src/compiler/internal/RecipeConditions.ts +0 -139
- package/src/compiler/internal/RecipePayloads.ts +0 -132
- package/src/compiler/internal/Recipes.ts +0 -531
- package/src/compiler/internal/Selectors.ts +0 -339
- package/src/compiler/internal/Static.ts +0 -784
- package/src/compiler/internal/Themes.ts +0 -2398
- package/src/compiler/internal/Vars.ts +0 -516
- package/src/compiler/internal/ViewTransitions.ts +0 -82
package/src/vite/index.ts
CHANGED
|
@@ -5,20 +5,30 @@
|
|
|
5
5
|
import * as Namespaces from '../compiler/internal/Namespaces.js'
|
|
6
6
|
import * as AtRules from '../compiler/internal/AtRules.js'
|
|
7
7
|
import * as Catalogs from '../compiler/internal/Catalogs.js'
|
|
8
|
+
import * as Results from '../compiler/internal/Results.js'
|
|
8
9
|
import * as Contracts from '../node/internal/Contracts.js'
|
|
9
10
|
import * as Mapping from '@jridgewell/gen-mapping'
|
|
10
11
|
import * as Lightning from 'lightningcss'
|
|
11
12
|
import * as Crypto from 'node:crypto'
|
|
13
|
+
import { existsSync } from 'node:fs'
|
|
12
14
|
import * as Fs from 'node:fs/promises'
|
|
13
15
|
import * as Path from 'node:path'
|
|
14
16
|
import * as Reset from '../node/Reset.js'
|
|
15
|
-
import
|
|
17
|
+
import * as Vlq from '../internal/Vlq.js'
|
|
18
|
+
import { createRequire, isBuiltin } from 'node:module'
|
|
16
19
|
import * as Parser from 'oxc-parser'
|
|
17
20
|
import * as Walker from 'oxc-walker'
|
|
18
21
|
import * as Snapshot from '../node/internal/Snapshot.js'
|
|
19
|
-
import * as Syntax from '../compiler/internal/Syntax.js'
|
|
20
22
|
import * as Scope from '../compiler/internal/Scope.js'
|
|
21
|
-
import type {
|
|
23
|
+
import type {
|
|
24
|
+
DevEnvironment,
|
|
25
|
+
Environment,
|
|
26
|
+
EnvironmentModuleNode,
|
|
27
|
+
Plugin,
|
|
28
|
+
Rollup,
|
|
29
|
+
UserConfig,
|
|
30
|
+
ViteDevServer,
|
|
31
|
+
} from 'vite'
|
|
22
32
|
import * as Graph from '../compiler/Graph.js'
|
|
23
33
|
import * as Source from '../compiler/Source.js'
|
|
24
34
|
import * as ThemeRules from '../web/internal/Themes.js'
|
|
@@ -51,7 +61,35 @@ export function zyzz(options: zyzz.Options = {}): Plugin {
|
|
|
51
61
|
const states = new WeakMap<Environment, Map<string, Entry>>()
|
|
52
62
|
const removed = new WeakMap<Environment, Set<string>>()
|
|
53
63
|
const reads = new WeakMap<Environment, Map<string, string>>()
|
|
64
|
+
const lookups = new WeakMap<Environment, Lookups>()
|
|
54
65
|
const compilers = new WeakMap<Environment, Graph.create.ReturnType>()
|
|
66
|
+
const projects = new WeakMap<Environment, Project>()
|
|
67
|
+
// The shared stylesheet each environment last loaded, which an edit compares against.
|
|
68
|
+
const servedShared = new WeakMap<Environment, string>()
|
|
69
|
+
// Watcher events advance an environment's generation, which scopes memoized whole-project work.
|
|
70
|
+
const generations = new WeakMap<Environment, number>()
|
|
71
|
+
let devServer: ViteDevServer | undefined
|
|
72
|
+
const watching = new Set<string>()
|
|
73
|
+
// Chokidar matches its ignore patterns on every add, and each compile watches its whole closure.
|
|
74
|
+
const watched = new Set<string>()
|
|
75
|
+
// Each compile reads the catalogs of every contract it saw, which rarely changes text.
|
|
76
|
+
const catalogReads = new Map<string, readonly Catalogs.Catalog[]>()
|
|
77
|
+
const dependencyChains = new Map<string, readonly (readonly unknown[])[]>()
|
|
78
|
+
const edgeMemos = new WeakMap<
|
|
79
|
+
Environment,
|
|
80
|
+
{ files: Map<string, Edges>; key: string }
|
|
81
|
+
>()
|
|
82
|
+
// A development entry's last output, reused until a watcher event or a recompiled graph.
|
|
83
|
+
const outputs = new WeakMap<
|
|
84
|
+
Entry,
|
|
85
|
+
{
|
|
86
|
+
allSources: boolean
|
|
87
|
+
code: string | undefined
|
|
88
|
+
generation: number
|
|
89
|
+
output: Awaited<ReturnType<typeof compileEntry>>
|
|
90
|
+
result: Graph.compile.ReturnType
|
|
91
|
+
}
|
|
92
|
+
>()
|
|
55
93
|
const packages = Contracts.create()
|
|
56
94
|
|
|
57
95
|
function compiler(environment: Environment) {
|
|
@@ -62,6 +100,168 @@ export function zyzz(options: zyzz.Options = {}): Plugin {
|
|
|
62
100
|
}
|
|
63
101
|
return value
|
|
64
102
|
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Watches a compile input from a hook. Vite checks the filesystem each time a file outside its
|
|
106
|
+
* root is watched, and every compile reads the same package files, so development watches
|
|
107
|
+
* each of those once.
|
|
108
|
+
*/
|
|
109
|
+
function watcher(context: { addWatchFile: (id: string) => void }) {
|
|
110
|
+
return (file: string) => {
|
|
111
|
+
if (devServer && !file.startsWith(`${devServer.config.root}/`)) {
|
|
112
|
+
if (watching.has(file)) return
|
|
113
|
+
|
|
114
|
+
watching.add(file)
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
context.addWatchFile(file)
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* The packed stylesheet dependency chains of a library contract. Every compile reads each
|
|
123
|
+
* contract it reaches, and design system contracts are large, so each text parses once.
|
|
124
|
+
*/
|
|
125
|
+
function stylesheetDependencies(id: string, contract: string) {
|
|
126
|
+
let value = dependencyChains.get(contract)
|
|
127
|
+
if (value) return value
|
|
128
|
+
|
|
129
|
+
const metadata = (() => {
|
|
130
|
+
try {
|
|
131
|
+
return JSON.parse(contract)
|
|
132
|
+
} catch (error) {
|
|
133
|
+
Graph.compile({ modules: {}, contracts: { [id]: contract } })
|
|
134
|
+
throw error
|
|
135
|
+
}
|
|
136
|
+
})()
|
|
137
|
+
|
|
138
|
+
value = Array.isArray(metadata?.stylesheets)
|
|
139
|
+
? (metadata.stylesheets as readonly { dependency?: unknown }[])
|
|
140
|
+
.map((section) => section?.dependency)
|
|
141
|
+
.filter((dependency): dependency is readonly unknown[] =>
|
|
142
|
+
Array.isArray(dependency),
|
|
143
|
+
)
|
|
144
|
+
: []
|
|
145
|
+
// Rebuilt libraries leave their earlier texts behind, so the cache stays bounded.
|
|
146
|
+
if (dependencyChains.size > 256) dependencyChains.clear()
|
|
147
|
+
dependencyChains.set(contract, value)
|
|
148
|
+
return value
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Each module's import edges in an environment, shared by every entry compile that walks the
|
|
153
|
+
* module. Added and removed files and dependency optimization change resolutions, so either
|
|
154
|
+
* starts over.
|
|
155
|
+
*/
|
|
156
|
+
function importEdges(environment: Environment) {
|
|
157
|
+
const metadata =
|
|
158
|
+
environment.mode === 'dev'
|
|
159
|
+
? (environment as DevEnvironment).depsOptimizer?.metadata
|
|
160
|
+
: undefined
|
|
161
|
+
const key = `${metadata?.browserHash}:${Object.keys(metadata?.discovered ?? {}).length}`
|
|
162
|
+
let value = edgeMemos.get(environment)
|
|
163
|
+
|
|
164
|
+
if (value?.key !== key) {
|
|
165
|
+
value = { files: new Map(), key }
|
|
166
|
+
edgeMemos.set(environment, value)
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
return value.files
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/** Adds a compile input to the development watcher once. */
|
|
173
|
+
function watch(server: ViteDevServer, file: string) {
|
|
174
|
+
if (watched.has(file)) return
|
|
175
|
+
|
|
176
|
+
watched.add(file)
|
|
177
|
+
server.watcher.add(file)
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
function read(contract: string) {
|
|
181
|
+
let value = catalogReads.get(contract)
|
|
182
|
+
|
|
183
|
+
if (!value) {
|
|
184
|
+
if (catalogReads.size > 256) catalogReads.clear()
|
|
185
|
+
|
|
186
|
+
value = Catalogs.read(contract)
|
|
187
|
+
catalogReads.set(contract, value)
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
return value
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
function project(environment: Environment) {
|
|
194
|
+
let value = projects.get(environment)
|
|
195
|
+
if (!value) {
|
|
196
|
+
value = {
|
|
197
|
+
compiler: Graph.create(),
|
|
198
|
+
contracts: Object.create(null),
|
|
199
|
+
fallback: Graph.create(),
|
|
200
|
+
imports: Object.create(null),
|
|
201
|
+
modules: Object.create(null),
|
|
202
|
+
outcome: undefined,
|
|
203
|
+
}
|
|
204
|
+
projects.set(environment, value)
|
|
205
|
+
}
|
|
206
|
+
return value
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Development merges every module a transform reaches into one graph per environment, so
|
|
211
|
+
* modules compile once per change instead of once per importer. A module's output depends only
|
|
212
|
+
* on its own import closure, so the merged graph returns the output a closure compile would.
|
|
213
|
+
* While some other module fails, the requested closure compiles alone and reports only its own
|
|
214
|
+
* errors, as before.
|
|
215
|
+
*/
|
|
216
|
+
function compileProject(
|
|
217
|
+
environment: Environment,
|
|
218
|
+
input: Graph.compile.Options,
|
|
219
|
+
id: string,
|
|
220
|
+
) {
|
|
221
|
+
const value = project(environment)
|
|
222
|
+
let changed = value.outcome === undefined
|
|
223
|
+
|
|
224
|
+
for (const [module, source] of Object.entries(input.modules))
|
|
225
|
+
if (value.modules[module] !== source) {
|
|
226
|
+
value.modules[module] = source
|
|
227
|
+
changed = true
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
for (const [module, resolutions] of Object.entries(input.imports ?? {}))
|
|
231
|
+
if (!same(value.imports[module], resolutions)) {
|
|
232
|
+
value.imports[module] = resolutions
|
|
233
|
+
changed = true
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
for (const [module, contract] of Object.entries(input.contracts ?? {}))
|
|
237
|
+
if (value.contracts[module] !== contract) {
|
|
238
|
+
value.contracts[module] = contract
|
|
239
|
+
changed = true
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
if (changed)
|
|
243
|
+
value.outcome = (() => {
|
|
244
|
+
try {
|
|
245
|
+
return {
|
|
246
|
+
result: value.compiler.compile({
|
|
247
|
+
...input,
|
|
248
|
+
contracts: value.contracts,
|
|
249
|
+
imports: value.imports,
|
|
250
|
+
modules: value.modules,
|
|
251
|
+
}),
|
|
252
|
+
}
|
|
253
|
+
} catch (error) {
|
|
254
|
+
return { error }
|
|
255
|
+
}
|
|
256
|
+
})()
|
|
257
|
+
|
|
258
|
+
const outcome = value.outcome!
|
|
259
|
+
|
|
260
|
+
if ('result' in outcome && Object.hasOwn(outcome.result.modules, id))
|
|
261
|
+
return outcome.result
|
|
262
|
+
|
|
263
|
+
return value.fallback.compile(input)
|
|
264
|
+
}
|
|
65
265
|
const discoveries = new WeakMap<Environment, Promise<Map<string, string>>>()
|
|
66
266
|
const contributionFiles = new WeakMap<Environment, Set<string>>()
|
|
67
267
|
const assets = new Map<string, string>()
|
|
@@ -71,8 +271,13 @@ export function zyzz(options: zyzz.Options = {}): Plugin {
|
|
|
71
271
|
const initializers = new WeakMap<Environment, Entry>()
|
|
72
272
|
const sourceEntrypoints = new Set<string>()
|
|
73
273
|
const identities = new Map<string, string>()
|
|
274
|
+
const exclusions = new Map<string, boolean>()
|
|
275
|
+
// Every compile checks each import against the source directories.
|
|
276
|
+
const roots = new Map<string, string | undefined>()
|
|
74
277
|
const lazyImports = new WeakMap<Parser.ParseResult, string[]>()
|
|
75
278
|
let directories: readonly string[]
|
|
279
|
+
let filter: (id: unknown) => boolean
|
|
280
|
+
let optimizeRuntime = false
|
|
76
281
|
let root: string
|
|
77
282
|
|
|
78
283
|
function snapshot(environment: Environment) {
|
|
@@ -149,12 +354,30 @@ export function zyzz(options: zyzz.Options = {}): Plugin {
|
|
|
149
354
|
Path.isAbsolute(id) &&
|
|
150
355
|
sourceRoot(id) !== undefined &&
|
|
151
356
|
/\.[cm]?[jt]sx?$/.test(id) &&
|
|
152
|
-
!/\.(?:d|test|test-d|bench|bench-d)\.[cm]?[jt]sx?$/.test(id)
|
|
357
|
+
!/\.(?:d|test|test-d|bench|bench-d)\.[cm]?[jt]sx?$/.test(id) &&
|
|
358
|
+
!excluded(id)
|
|
153
359
|
)
|
|
154
360
|
}
|
|
155
361
|
|
|
362
|
+
/** Matches excluded files inside source directories. Package files never match, so packed contracts stay readable. */
|
|
363
|
+
function excluded(id: string) {
|
|
364
|
+
const file = id.split(/[?#]/)[0]!
|
|
365
|
+
let value = exclusions.get(file)
|
|
366
|
+
|
|
367
|
+
// Vite's filter recompiles each glob per call, and every compile checks each import.
|
|
368
|
+
if (value === undefined) {
|
|
369
|
+
value =
|
|
370
|
+
Path.isAbsolute(file) && sourceRoot(file) !== undefined && !filter(file)
|
|
371
|
+
exclusions.set(file, value)
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
return value
|
|
375
|
+
}
|
|
376
|
+
|
|
156
377
|
function sourceRoot(file: string) {
|
|
157
|
-
|
|
378
|
+
if (roots.has(file)) return roots.get(file)
|
|
379
|
+
|
|
380
|
+
const root = directories.find((directory) => {
|
|
158
381
|
const relative = Path.relative(directory, file)
|
|
159
382
|
|
|
160
383
|
return (
|
|
@@ -164,6 +387,9 @@ export function zyzz(options: zyzz.Options = {}): Plugin {
|
|
|
164
387
|
!relative.split(Path.sep).includes('node_modules')
|
|
165
388
|
)
|
|
166
389
|
})
|
|
390
|
+
|
|
391
|
+
roots.set(file, root)
|
|
392
|
+
return root
|
|
167
393
|
}
|
|
168
394
|
|
|
169
395
|
function discover(environment: Environment, host: Host) {
|
|
@@ -355,6 +581,46 @@ export function zyzz(options: zyzz.Options = {}): Plugin {
|
|
|
355
581
|
event: string,
|
|
356
582
|
) {
|
|
357
583
|
reads.delete(environment)
|
|
584
|
+
generations.set(environment, (generations.get(environment) ?? 0) + 1)
|
|
585
|
+
|
|
586
|
+
const changed = entries(environment).get(file)
|
|
587
|
+
|
|
588
|
+
if (changed) changed.source = undefined
|
|
589
|
+
|
|
590
|
+
// An edit keeps every resolution. Adding or removing a file can change where a
|
|
591
|
+
// specifier resolves, and a contract derives again only when a file it read changes.
|
|
592
|
+
// Editors save through temporary files, which no specifier resolves to.
|
|
593
|
+
const resolvable =
|
|
594
|
+
event !== 'update' &&
|
|
595
|
+
/\.(?:[cm]?[jt]sx?|json|css|svelte|vue)$|(?:^|[/\\])package\.json$/.test(
|
|
596
|
+
file,
|
|
597
|
+
)
|
|
598
|
+
const cache = lookups.get(environment)
|
|
599
|
+
|
|
600
|
+
// Import edges derive from resolutions and module text, which each memo compares.
|
|
601
|
+
if (resolvable) edgeMemos.delete(environment)
|
|
602
|
+
|
|
603
|
+
if (cache) {
|
|
604
|
+
if (resolvable) cache.resolutions.clear()
|
|
605
|
+
|
|
606
|
+
for (const [key, files] of cache.read)
|
|
607
|
+
if (files.has(file)) {
|
|
608
|
+
cache.contracts.delete(key)
|
|
609
|
+
cache.read.delete(key)
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
if (event === 'delete') {
|
|
614
|
+
const value = projects.get(environment)
|
|
615
|
+
const id = sourceId(file)
|
|
616
|
+
|
|
617
|
+
if (value && Object.hasOwn(value.modules, id)) {
|
|
618
|
+
delete value.modules[id]
|
|
619
|
+
delete value.imports[id]
|
|
620
|
+
value.outcome = undefined
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
|
|
358
624
|
if (event === 'delete') {
|
|
359
625
|
if (entries(environment).has(file)) {
|
|
360
626
|
let files = removed.get(environment)
|
|
@@ -392,22 +658,127 @@ export function zyzz(options: zyzz.Options = {}): Plugin {
|
|
|
392
658
|
allSources = false,
|
|
393
659
|
everything = false,
|
|
394
660
|
) {
|
|
661
|
+
const generation = generations.get(entry.environment) ?? 0
|
|
662
|
+
const memo = outputs.get(entry)
|
|
663
|
+
const current = projects.get(entry.environment)?.outcome
|
|
664
|
+
|
|
665
|
+
// Without a watcher event the closure is unchanged, so a stylesheet load after its
|
|
666
|
+
// transform reuses the output while the merged graph has not recompiled.
|
|
667
|
+
if (
|
|
668
|
+
memo &&
|
|
669
|
+
!everything &&
|
|
670
|
+
memo.allSources === allSources &&
|
|
671
|
+
memo.generation === generation &&
|
|
672
|
+
(code === undefined || code === memo.code) &&
|
|
673
|
+
current &&
|
|
674
|
+
'result' in current &&
|
|
675
|
+
current.result === memo.result
|
|
676
|
+
) {
|
|
677
|
+
for (const file of entry.files) host.watch(file)
|
|
678
|
+
return memo.output
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
const output = await compileEntry(entry, host, code, allSources, everything)
|
|
682
|
+
const outcome = projects.get(entry.environment)?.outcome
|
|
683
|
+
|
|
684
|
+
// A concurrent compile can replace the merged result while this one renders, so only an
|
|
685
|
+
// output of the current result is kept.
|
|
686
|
+
if (
|
|
687
|
+
entry.environment.mode === 'dev' &&
|
|
688
|
+
!everything &&
|
|
689
|
+
outcome &&
|
|
690
|
+
'result' in outcome &&
|
|
691
|
+
outcome.result.modules === output.modules &&
|
|
692
|
+
generation === (generations.get(entry.environment) ?? 0)
|
|
693
|
+
)
|
|
694
|
+
outputs.set(entry, {
|
|
695
|
+
allSources,
|
|
696
|
+
code,
|
|
697
|
+
generation,
|
|
698
|
+
output,
|
|
699
|
+
result: outcome.result,
|
|
700
|
+
})
|
|
701
|
+
|
|
702
|
+
return output
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
async function compileEntry(
|
|
706
|
+
entry: Entry,
|
|
707
|
+
host: Host,
|
|
708
|
+
code?: string,
|
|
709
|
+
allSources = false,
|
|
710
|
+
everything = false,
|
|
711
|
+
) {
|
|
712
|
+
// Every compile visits the discovered project, so modules share lookups. Watcher events
|
|
713
|
+
// drop the resolutions and contracts a change can affect. Full-project compiles look up
|
|
714
|
+
// afresh, since a document must not trail the watcher.
|
|
715
|
+
const cache = (() => {
|
|
716
|
+
const fresh: Lookups = {
|
|
717
|
+
contracts: new Map(),
|
|
718
|
+
read: new Map(),
|
|
719
|
+
resolutions: new Map(),
|
|
720
|
+
}
|
|
721
|
+
if (everything) return fresh
|
|
722
|
+
|
|
723
|
+
let value = lookups.get(entry.environment)
|
|
724
|
+
if (!value) {
|
|
725
|
+
value = fresh
|
|
726
|
+
lookups.set(entry.environment, value)
|
|
727
|
+
}
|
|
728
|
+
return value
|
|
729
|
+
})()
|
|
730
|
+
|
|
731
|
+
// Full-project compiles walk afresh, as they look up afresh.
|
|
732
|
+
const memos = everything ? undefined : importEdges(entry.environment)
|
|
733
|
+
|
|
395
734
|
async function resolve(source: string, importer: string) {
|
|
396
735
|
if (isBuiltin(source)) return { id: source, external: true }
|
|
397
|
-
|
|
736
|
+
|
|
737
|
+
const key = `${importer}\0${source}`
|
|
738
|
+
let pending = cache.resolutions.get(key)
|
|
739
|
+
if (!pending) {
|
|
740
|
+
pending = host.resolve(source, importer)
|
|
741
|
+
cache.resolutions.set(key, pending)
|
|
742
|
+
pending.catch(() => cache.resolutions.delete(key))
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
const resolved = await pending
|
|
398
746
|
if (!resolved) return resolved
|
|
399
747
|
|
|
400
748
|
if (entry.environment.mode === 'dev') {
|
|
401
|
-
const
|
|
402
|
-
|
|
403
|
-
...entry.environment.depsOptimizer?.metadata.discovered,
|
|
404
|
-
}).find((item) => item.file === resolved.id.split('?')[0])
|
|
405
|
-
if (optimized?.src) return { ...resolved, id: optimized.src }
|
|
749
|
+
const source = optimized().get(resolved.id.split('?')[0]!)
|
|
750
|
+
if (source) return { ...resolved, id: source }
|
|
406
751
|
}
|
|
407
752
|
|
|
408
753
|
return { ...resolved, id: normalize(resolved.id) }
|
|
409
754
|
}
|
|
410
755
|
|
|
756
|
+
// Optimized dependency sources by bundled file, indexed once per compile rather than
|
|
757
|
+
// searched for every resolution.
|
|
758
|
+
let indexed: Map<string, string> | undefined
|
|
759
|
+
|
|
760
|
+
function optimized() {
|
|
761
|
+
if (indexed) return indexed
|
|
762
|
+
|
|
763
|
+
indexed = new Map()
|
|
764
|
+
|
|
765
|
+
const environment = entry.environment
|
|
766
|
+
const metadata =
|
|
767
|
+
environment.mode === 'dev'
|
|
768
|
+
? environment.depsOptimizer?.metadata
|
|
769
|
+
: undefined
|
|
770
|
+
|
|
771
|
+
// Discovered entries replace optimized ones of the same name, and the first entry
|
|
772
|
+
// bundling a file wins, as a search of the merged record finds it.
|
|
773
|
+
for (const item of Object.values({
|
|
774
|
+
...metadata?.optimized,
|
|
775
|
+
...metadata?.discovered,
|
|
776
|
+
}))
|
|
777
|
+
if (!indexed.has(item.file)) indexed.set(item.file, item.src ?? '')
|
|
778
|
+
|
|
779
|
+
return indexed
|
|
780
|
+
}
|
|
781
|
+
|
|
411
782
|
const imports: Record<
|
|
412
783
|
string,
|
|
413
784
|
Record<string, string | null>
|
|
@@ -416,15 +787,44 @@ export function zyzz(options: zyzz.Options = {}): Plugin {
|
|
|
416
787
|
const lazy: Record<string, ReadonlySet<string>> = Object.create(null)
|
|
417
788
|
const modules: Record<string, string> = Object.create(null)
|
|
418
789
|
const files = new Set<string>()
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
790
|
+
|
|
791
|
+
// A package contract derives from the files it reads and the resolutions
|
|
792
|
+
// above. A cached contract still makes this compile watch those files.
|
|
793
|
+
async function readContract(file: string, required = false) {
|
|
794
|
+
const key = `${required}\0${file}`
|
|
795
|
+
let pending = cache.contracts.get(key)
|
|
796
|
+
if (!pending) {
|
|
797
|
+
const read = new Set<string>()
|
|
798
|
+
|
|
799
|
+
pending = packages
|
|
800
|
+
.read(file, {
|
|
801
|
+
read: async (path) => {
|
|
802
|
+
const source = await snapshot(entry.environment).read(path)
|
|
803
|
+
read.add(path)
|
|
804
|
+
return source
|
|
805
|
+
},
|
|
806
|
+
required,
|
|
807
|
+
resolve: async (specifier, importer) =>
|
|
808
|
+
(await resolve(specifier, importer))?.id.split(/[?#]/)[0],
|
|
809
|
+
})
|
|
810
|
+
.then((contract) => {
|
|
811
|
+
cache.read.set(key, read)
|
|
812
|
+
return { contract, files: read }
|
|
813
|
+
})
|
|
814
|
+
cache.contracts.set(key, pending)
|
|
815
|
+
pending.catch(() => cache.contracts.delete(key))
|
|
816
|
+
}
|
|
817
|
+
|
|
818
|
+
const derived = await pending
|
|
819
|
+
|
|
820
|
+
for (const path of derived.files) {
|
|
821
|
+
if (files.has(path)) continue
|
|
822
|
+
|
|
823
|
+
files.add(path)
|
|
824
|
+
host.watch(path)
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
return derived.contract
|
|
428
828
|
}
|
|
429
829
|
|
|
430
830
|
async function visit(file: string, source?: string) {
|
|
@@ -439,16 +839,43 @@ export function zyzz(options: zyzz.Options = {}): Plugin {
|
|
|
439
839
|
cached = new Map()
|
|
440
840
|
reads.set(entry.environment, cached)
|
|
441
841
|
}
|
|
842
|
+
// Earlier plugins can rewrite a module before this one sees it, as router plugins drop
|
|
843
|
+
// server routes from client route trees. Its importers read the code Vite transformed, so
|
|
844
|
+
// every graph in the environment holds one version of each module.
|
|
442
845
|
// Full-project compilation must not reuse reads from concurrent module transforms.
|
|
443
846
|
const text =
|
|
444
847
|
source ??
|
|
848
|
+
(everything
|
|
849
|
+
? undefined
|
|
850
|
+
: entries(entry.environment).get(file)?.source) ??
|
|
445
851
|
(everything ? undefined : cached.get(file)) ??
|
|
446
852
|
(await snapshot(entry.environment).read(file))
|
|
447
853
|
if (!everything) cached.set(file, text)
|
|
448
854
|
|
|
449
855
|
modules[id] = text
|
|
450
856
|
|
|
857
|
+
const memo = memos?.get(file)
|
|
858
|
+
|
|
859
|
+
// Replaying the edges keeps the order in which modules and contracts join the compile.
|
|
860
|
+
if (memo?.text === text) {
|
|
861
|
+
imports[id] = { ...memo.resolutions }
|
|
862
|
+
|
|
863
|
+
for (const step of memo.steps) {
|
|
864
|
+
if (typeof step === 'string') {
|
|
865
|
+
await visit(step)
|
|
866
|
+
continue
|
|
867
|
+
}
|
|
868
|
+
|
|
869
|
+
const contract = await readContract(step.physical)
|
|
870
|
+
if (contract !== undefined) contracts[step.id] = contract
|
|
871
|
+
}
|
|
872
|
+
|
|
873
|
+
lazy[id] = memo.lazy
|
|
874
|
+
return
|
|
875
|
+
}
|
|
876
|
+
|
|
451
877
|
const resolutions: Record<string, string | null> = Object.create(null)
|
|
878
|
+
const steps: Edges['steps'][number][] = []
|
|
452
879
|
|
|
453
880
|
imports[id] = resolutions
|
|
454
881
|
|
|
@@ -519,15 +946,25 @@ export function zyzz(options: zyzz.Options = {}): Plugin {
|
|
|
519
946
|
) {
|
|
520
947
|
sourceEntrypoints.add(normalize(resolved.id))
|
|
521
948
|
resolutions[specifier] = sourceId(resolved.id)
|
|
949
|
+
steps.push(resolved.id)
|
|
522
950
|
await visit(resolved.id)
|
|
523
951
|
continue
|
|
524
952
|
}
|
|
953
|
+
|
|
954
|
+
// An excluded source stays a runtime import instead of deriving a package contract.
|
|
955
|
+
if (excluded(resolved.id)) {
|
|
956
|
+
resolutions[specifier] = null
|
|
957
|
+
continue
|
|
958
|
+
}
|
|
959
|
+
|
|
525
960
|
if (resolved.external || !eligible(resolved.id)) {
|
|
526
961
|
const physical = resolved.id.split('?')[0]!.split('#')[0]!
|
|
527
|
-
const
|
|
962
|
+
const readable =
|
|
528
963
|
Path.isAbsolute(physical) && /\.[cm]?[jt]sx?$/.test(physical)
|
|
529
|
-
|
|
530
|
-
|
|
964
|
+
|
|
965
|
+
if (readable) steps.push({ id: resolved.id, physical })
|
|
966
|
+
|
|
967
|
+
const contract = readable ? await readContract(physical) : undefined
|
|
531
968
|
|
|
532
969
|
if (contract !== undefined) {
|
|
533
970
|
contracts[resolved.id] = contract
|
|
@@ -540,6 +977,7 @@ export function zyzz(options: zyzz.Options = {}): Plugin {
|
|
|
540
977
|
}
|
|
541
978
|
|
|
542
979
|
resolutions[specifier] = sourceId(resolved.id)
|
|
980
|
+
steps.push(resolved.id)
|
|
543
981
|
await visit(resolved.id)
|
|
544
982
|
}
|
|
545
983
|
|
|
@@ -573,6 +1011,7 @@ export function zyzz(options: zyzz.Options = {}): Plugin {
|
|
|
573
1011
|
}
|
|
574
1012
|
|
|
575
1013
|
lazy[id] = targets
|
|
1014
|
+
memos?.set(file, { lazy: targets, resolutions, steps, text })
|
|
576
1015
|
}
|
|
577
1016
|
|
|
578
1017
|
await visit(entry.file, code)
|
|
@@ -648,7 +1087,11 @@ export function zyzz(options: zyzz.Options = {}): Plugin {
|
|
|
648
1087
|
continue
|
|
649
1088
|
|
|
650
1089
|
const resolved = await resolve(specifier, file)
|
|
651
|
-
if (
|
|
1090
|
+
if (
|
|
1091
|
+
!resolved ||
|
|
1092
|
+
(!resolved.external && eligible(resolved.id)) ||
|
|
1093
|
+
excluded(resolved.id)
|
|
1094
|
+
)
|
|
652
1095
|
continue
|
|
653
1096
|
|
|
654
1097
|
if (resource(specifier) || resource(resolved.id)) continue
|
|
@@ -657,7 +1100,7 @@ export function zyzz(options: zyzz.Options = {}): Plugin {
|
|
|
657
1100
|
if (!Path.isAbsolute(physical) || !/\.[cm]?[jt]sx?$/.test(physical))
|
|
658
1101
|
continue
|
|
659
1102
|
|
|
660
|
-
const contract = await
|
|
1103
|
+
const contract = await readContract(physical)
|
|
661
1104
|
if (contract === undefined) continue
|
|
662
1105
|
|
|
663
1106
|
contracts[resolved.id] = contract
|
|
@@ -685,22 +1128,10 @@ export function zyzz(options: zyzz.Options = {}): Plugin {
|
|
|
685
1128
|
|
|
686
1129
|
loaded.add(id)
|
|
687
1130
|
|
|
688
|
-
const
|
|
689
|
-
try {
|
|
690
|
-
return JSON.parse(contracts[id]!)
|
|
691
|
-
} catch (error) {
|
|
692
|
-
Graph.compile({ modules: {}, contracts: { [id]: contracts[id]! } })
|
|
693
|
-
throw error
|
|
694
|
-
}
|
|
695
|
-
})()
|
|
696
|
-
if (!Array.isArray(metadata?.stylesheets)) return
|
|
697
|
-
|
|
698
|
-
for (const section of metadata.stylesheets) {
|
|
699
|
-
if (!Array.isArray(section?.dependency)) continue
|
|
700
|
-
|
|
1131
|
+
for (const dependency of stylesheetDependencies(id, contracts[id]!)) {
|
|
701
1132
|
let owner = id
|
|
702
1133
|
|
|
703
|
-
for (const specifier of
|
|
1134
|
+
for (const specifier of dependency) {
|
|
704
1135
|
if (
|
|
705
1136
|
typeof specifier !== 'string' ||
|
|
706
1137
|
!specifier ||
|
|
@@ -715,9 +1146,9 @@ export function zyzz(options: zyzz.Options = {}): Plugin {
|
|
|
715
1146
|
imports[owner] ??= Object.create(null)
|
|
716
1147
|
imports[owner]![specifier] = target.id
|
|
717
1148
|
|
|
718
|
-
contracts[target.id] ??= (await
|
|
1149
|
+
contracts[target.id] ??= (await readContract(
|
|
719
1150
|
target.id.split(/[?#]/)[0]!,
|
|
720
|
-
|
|
1151
|
+
true,
|
|
721
1152
|
))!
|
|
722
1153
|
|
|
723
1154
|
await dependencies(target.id)
|
|
@@ -748,9 +1179,9 @@ export function zyzz(options: zyzz.Options = {}): Plugin {
|
|
|
748
1179
|
]),
|
|
749
1180
|
)
|
|
750
1181
|
|
|
751
|
-
const
|
|
1182
|
+
const input: Graph.compile.Options = {
|
|
1183
|
+
[Results.lean]: true,
|
|
752
1184
|
[ThemeRules.shared]: native ? undefined : 'all',
|
|
753
|
-
[Syntax.cache]: snapshot(entry.environment).programs(modules),
|
|
754
1185
|
compiler: options.compiler,
|
|
755
1186
|
reset: options.reset ? Reset.read() : undefined,
|
|
756
1187
|
native,
|
|
@@ -758,7 +1189,11 @@ export function zyzz(options: zyzz.Options = {}): Plugin {
|
|
|
758
1189
|
development: entry.environment.mode !== 'build',
|
|
759
1190
|
imports,
|
|
760
1191
|
modules,
|
|
761
|
-
}
|
|
1192
|
+
}
|
|
1193
|
+
const result =
|
|
1194
|
+
entry.environment.mode === 'dev' && !native && !everything
|
|
1195
|
+
? compileProject(entry.environment, input, sourceId(entry.file))
|
|
1196
|
+
: entry.compiler.compile(input)
|
|
762
1197
|
|
|
763
1198
|
if (native) {
|
|
764
1199
|
const output = result.modules[sourceId(entry.file)]!
|
|
@@ -772,6 +1207,7 @@ export function zyzz(options: zyzz.Options = {}): Plugin {
|
|
|
772
1207
|
configurations: new Map<string, Catalogs.Catalog>(),
|
|
773
1208
|
connections: staged,
|
|
774
1209
|
css: '',
|
|
1210
|
+
graphSharedCss: '',
|
|
775
1211
|
sharedCss: '',
|
|
776
1212
|
cssMap: map,
|
|
777
1213
|
sharedCssMap: map,
|
|
@@ -807,166 +1243,181 @@ export function zyzz(options: zyzz.Options = {}): Plugin {
|
|
|
807
1243
|
|
|
808
1244
|
const configurations = new Map<string, Catalogs.Catalog>()
|
|
809
1245
|
for (const [id, contract] of Object.entries(compiled))
|
|
810
|
-
for (const configuration of
|
|
1246
|
+
for (const configuration of read(contract)) {
|
|
811
1247
|
const key = `${id}\0${configuration.identity}`
|
|
812
1248
|
catalogs.set(key, configuration)
|
|
813
1249
|
configurations.set(key, configuration)
|
|
814
1250
|
}
|
|
815
1251
|
|
|
816
|
-
|
|
1252
|
+
// Development renders the shared stylesheet for its own request only; transforms and module
|
|
1253
|
+
// stylesheets read module outputs.
|
|
1254
|
+
async function renderShared() {
|
|
1255
|
+
const owners = new Map<string, string>()
|
|
817
1256
|
|
|
818
|
-
|
|
819
|
-
|
|
1257
|
+
for (const id of new Set(Object.values(result.sharedAssetOwners ?? {}))) {
|
|
1258
|
+
if (!Path.isAbsolute(id)) continue
|
|
820
1259
|
|
|
821
|
-
|
|
1260
|
+
let directory = Path.dirname(id.split(/[?#]/)[0]!)
|
|
822
1261
|
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
1262
|
+
for (;;) {
|
|
1263
|
+
try {
|
|
1264
|
+
await Fs.access(Path.join(directory, 'package.json'))
|
|
1265
|
+
owners.set(id, await Fs.realpath(directory))
|
|
1266
|
+
break
|
|
1267
|
+
} catch (error) {
|
|
1268
|
+
if ((error as NodeJS.ErrnoException).code !== 'ENOENT') throw error
|
|
1269
|
+
}
|
|
831
1270
|
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
1271
|
+
const parent = Path.dirname(directory)
|
|
1272
|
+
if (parent === directory)
|
|
1273
|
+
throw new Error('Packed assets require an owning package.json.')
|
|
835
1274
|
|
|
836
|
-
|
|
1275
|
+
directory = parent
|
|
1276
|
+
}
|
|
837
1277
|
}
|
|
838
|
-
}
|
|
839
1278
|
|
|
840
|
-
|
|
1279
|
+
const assetUrls = new Map<string, string>()
|
|
841
1280
|
|
|
842
|
-
|
|
843
|
-
|
|
1281
|
+
for (const [key, target] of Object.entries(result.sharedAssets ?? {})) {
|
|
1282
|
+
const raw = target.split(/[?#]/)[0]!
|
|
844
1283
|
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
1284
|
+
const identity = result.sharedAssetOwners?.[key]
|
|
1285
|
+
const path =
|
|
1286
|
+
sourceFile(decodeURIComponent(raw)) ??
|
|
1287
|
+
(Path.isAbsolute(raw) ? decodeURIComponent(raw) : undefined)
|
|
1288
|
+
if (!path) throw new Error('Asset path escapes the Vite graph.')
|
|
850
1289
|
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
1290
|
+
const asset = await (async () => {
|
|
1291
|
+
try {
|
|
1292
|
+
return { file: await Fs.realpath(path), package: false }
|
|
1293
|
+
} catch (error) {
|
|
1294
|
+
if (
|
|
1295
|
+
(error as NodeJS.ErrnoException).code !== 'ENOENT' ||
|
|
1296
|
+
!identity ||
|
|
1297
|
+
!sourceFile(identity)
|
|
1298
|
+
)
|
|
1299
|
+
throw error
|
|
1300
|
+
|
|
1301
|
+
const importer = sourceFile(identity)!
|
|
1302
|
+
const specifier = Path.relative(Path.dirname(importer), path)
|
|
1303
|
+
.split(Path.sep)
|
|
1304
|
+
.join('/')
|
|
1305
|
+
if (specifier.startsWith('.') || Path.isAbsolute(specifier))
|
|
1306
|
+
throw error
|
|
1307
|
+
const resolved = await host.resolve(specifier, importer)
|
|
1308
|
+
if (!resolved || resolved.external) throw error
|
|
1309
|
+
return {
|
|
1310
|
+
file: await Fs.realpath(resolved.id.split('?')[0]!),
|
|
1311
|
+
package: true,
|
|
1312
|
+
}
|
|
873
1313
|
}
|
|
874
|
-
}
|
|
875
|
-
|
|
876
|
-
const file = asset.file
|
|
877
|
-
|
|
878
|
-
const owner =
|
|
879
|
-
identity && sourceFile(identity)
|
|
880
|
-
? sourceRoot(sourceFile(identity)!)
|
|
881
|
-
: identity
|
|
882
|
-
? owners.get(identity)
|
|
883
|
-
: undefined
|
|
884
|
-
|
|
885
|
-
const relative = owner ? Path.relative(owner, file) : '..'
|
|
886
|
-
if (
|
|
887
|
-
!asset.package &&
|
|
888
|
-
(relative === '..' ||
|
|
889
|
-
relative.startsWith(`..${Path.sep}`) ||
|
|
890
|
-
Path.isAbsolute(relative))
|
|
891
|
-
)
|
|
892
|
-
throw new Error('Asset path escapes its owning package.')
|
|
1314
|
+
})()
|
|
1315
|
+
const file = asset.file
|
|
893
1316
|
|
|
894
|
-
|
|
895
|
-
|
|
1317
|
+
const owner =
|
|
1318
|
+
identity && sourceFile(identity)
|
|
1319
|
+
? sourceRoot(sourceFile(identity)!)
|
|
1320
|
+
: identity
|
|
1321
|
+
? owners.get(identity)
|
|
1322
|
+
: undefined
|
|
896
1323
|
|
|
897
|
-
|
|
1324
|
+
const relative = owner ? Path.relative(owner, file) : '..'
|
|
1325
|
+
if (
|
|
1326
|
+
!asset.package &&
|
|
1327
|
+
(relative === '..' ||
|
|
1328
|
+
relative.startsWith(`..${Path.sep}`) ||
|
|
1329
|
+
Path.isAbsolute(relative))
|
|
1330
|
+
)
|
|
1331
|
+
throw new Error('Asset path escapes its owning package.')
|
|
898
1332
|
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
url = await host.asset(file)
|
|
1333
|
+
host.watch(file)
|
|
1334
|
+
files.add(file)
|
|
902
1335
|
|
|
903
|
-
|
|
1336
|
+
let url: string
|
|
1337
|
+
|
|
1338
|
+
if (asset.package || /[?#%]/.test(file)) {
|
|
1339
|
+
if (entry.environment.mode === 'build') {
|
|
1340
|
+
url = await host.asset(file)
|
|
1341
|
+
|
|
1342
|
+
if (target.slice(raw.length))
|
|
1343
|
+
url += `$_${target.slice(raw.length)}__`
|
|
1344
|
+
} else {
|
|
1345
|
+
url = `/@zyzz/asset/${Crypto.hash('sha256', file)}/${encodeURIComponent(Path.basename(file))}`
|
|
1346
|
+
assets.set(url, file)
|
|
1347
|
+
url += target.slice(raw.length)
|
|
1348
|
+
}
|
|
904
1349
|
} else {
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
1350
|
+
// Vite reads `/@fs/` URLs with `decodeURI`, which keeps reserved escapes
|
|
1351
|
+
// such as `%40` in scoped package paths, so those characters stay raw.
|
|
1352
|
+
const pathname = encodeURI(file.replaceAll('\\', '/'))
|
|
1353
|
+
|
|
1354
|
+
url = `/@fs/${pathname}${target.slice(raw.length)}`
|
|
908
1355
|
}
|
|
909
|
-
} else {
|
|
910
|
-
// Vite reads `/@fs/` URLs with `decodeURI`, which keeps reserved escapes
|
|
911
|
-
// such as `%40` in scoped package paths, so those characters stay raw.
|
|
912
|
-
const pathname = encodeURI(file.replaceAll('\\', '/'))
|
|
913
1356
|
|
|
914
|
-
|
|
1357
|
+
assetUrls.set(target, url)
|
|
915
1358
|
}
|
|
916
1359
|
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
1360
|
+
const shared = !Object.keys(result.sharedAssets ?? {}).length
|
|
1361
|
+
? {
|
|
1362
|
+
code: new TextEncoder().encode(result.sharedCss ?? ''),
|
|
1363
|
+
map: new TextEncoder().encode(
|
|
1364
|
+
JSON.stringify(
|
|
1365
|
+
result.sharedCssMap ??
|
|
1366
|
+
Mapping.toEncodedMap(new Mapping.GenMapping()),
|
|
1367
|
+
),
|
|
1368
|
+
),
|
|
1369
|
+
}
|
|
1370
|
+
: AtRules.transform({
|
|
1371
|
+
filename: 'zyzz.shared.css',
|
|
1372
|
+
code: new TextEncoder().encode(result.sharedCss ?? ''),
|
|
1373
|
+
sourceMap: true,
|
|
1374
|
+
inputSourceMap: JSON.stringify(
|
|
925
1375
|
result.sharedCssMap ??
|
|
926
1376
|
Mapping.toEncodedMap(new Mapping.GenMapping()),
|
|
927
1377
|
),
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
const target = result.sharedAssets?.[rule.value.url]
|
|
942
|
-
if (target)
|
|
943
|
-
return AtRules.relocateImport(
|
|
944
|
-
rule.value,
|
|
945
|
-
assetUrls.get(target)!,
|
|
946
|
-
)
|
|
947
|
-
},
|
|
948
|
-
Url(url) {
|
|
949
|
-
const target = result.sharedAssets?.[url.url]
|
|
950
|
-
if (!target) return
|
|
1378
|
+
visitor: {
|
|
1379
|
+
Rule(rule) {
|
|
1380
|
+
if (rule.type !== 'import') return
|
|
1381
|
+
const target = result.sharedAssets?.[rule.value.url]
|
|
1382
|
+
if (target)
|
|
1383
|
+
return AtRules.relocateImport(
|
|
1384
|
+
rule.value,
|
|
1385
|
+
assetUrls.get(target)!,
|
|
1386
|
+
)
|
|
1387
|
+
},
|
|
1388
|
+
Url(url) {
|
|
1389
|
+
const target = result.sharedAssets?.[url.url]
|
|
1390
|
+
if (!target) return
|
|
951
1391
|
|
|
952
|
-
|
|
1392
|
+
return { ...url, url: assetUrls.get(target)! }
|
|
1393
|
+
},
|
|
953
1394
|
},
|
|
954
|
-
}
|
|
955
|
-
})
|
|
1395
|
+
})
|
|
956
1396
|
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
1397
|
+
const sharedMap = JSON.parse(
|
|
1398
|
+
new TextDecoder().decode(shared.map!),
|
|
1399
|
+
) as Mapping.EncodedSourceMap
|
|
960
1400
|
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
1401
|
+
sharedMap.sources = sharedMap.sources.map((source) =>
|
|
1402
|
+
source === null ? null : (sourceFile(source) ?? source),
|
|
1403
|
+
)
|
|
1404
|
+
|
|
1405
|
+
return { css: new TextDecoder().decode(shared.code), map: sharedMap }
|
|
1406
|
+
}
|
|
1407
|
+
|
|
1408
|
+
const sharedOutput =
|
|
1409
|
+
entry.environment.mode !== 'dev' || allSources
|
|
1410
|
+
? await renderShared()
|
|
1411
|
+
: {
|
|
1412
|
+
css: '',
|
|
1413
|
+
map: Mapping.toEncodedMap(new Mapping.GenMapping()),
|
|
1414
|
+
}
|
|
964
1415
|
|
|
965
1416
|
const output = result.modules[sourceId(entry.file)]!
|
|
966
1417
|
|
|
967
1418
|
entry.files = files
|
|
968
1419
|
|
|
969
|
-
|
|
1420
|
+
const value = {
|
|
970
1421
|
imports,
|
|
971
1422
|
modules: result.modules,
|
|
972
1423
|
code: output.code,
|
|
@@ -974,8 +1425,10 @@ export function zyzz(options: zyzz.Options = {}): Plugin {
|
|
|
974
1425
|
configurations,
|
|
975
1426
|
connections: staged,
|
|
976
1427
|
css: output.css,
|
|
977
|
-
|
|
978
|
-
|
|
1428
|
+
// Edits compare the graph's stylesheet, which precedes asset relocation.
|
|
1429
|
+
graphSharedCss: result.sharedCss ?? '',
|
|
1430
|
+
sharedCss: sharedOutput.css,
|
|
1431
|
+
sharedCssMap: sharedOutput.map,
|
|
979
1432
|
cssMap: {
|
|
980
1433
|
...output.cssMap,
|
|
981
1434
|
sources: output.cssMap.sources.map((source) =>
|
|
@@ -989,6 +1442,8 @@ export function zyzz(options: zyzz.Options = {}): Plugin {
|
|
|
989
1442
|
),
|
|
990
1443
|
},
|
|
991
1444
|
}
|
|
1445
|
+
|
|
1446
|
+
return value
|
|
992
1447
|
}
|
|
993
1448
|
|
|
994
1449
|
/** Compiles every discovered source once so index.html can inline each configuration's script before modules load. */
|
|
@@ -997,9 +1452,8 @@ export function zyzz(options: zyzz.Options = {}): Plugin {
|
|
|
997
1452
|
reads.delete(environment)
|
|
998
1453
|
const host: Host = {
|
|
999
1454
|
asset: async (file) => file,
|
|
1000
|
-
resolve: (
|
|
1001
|
-
|
|
1002
|
-
watch: (file) => server.watcher.add(file),
|
|
1455
|
+
resolve: resolver(environment),
|
|
1456
|
+
watch: (file) => watch(server, file),
|
|
1003
1457
|
}
|
|
1004
1458
|
const sources = await discover(environment, host)
|
|
1005
1459
|
let entry = initializers.get(environment)
|
|
@@ -1009,8 +1463,9 @@ export function zyzz(options: zyzz.Options = {}): Plugin {
|
|
|
1009
1463
|
const file = sources.keys().next().value
|
|
1010
1464
|
if (file === undefined) return { catalogs: new Map(), edges: new Map() }
|
|
1011
1465
|
|
|
1466
|
+
// Whole-project compiles keep their own cache beside the transforms' merged graph.
|
|
1012
1467
|
entry = {
|
|
1013
|
-
compiler:
|
|
1468
|
+
compiler: initializers.get(environment)?.compiler ?? Graph.create(),
|
|
1014
1469
|
environment,
|
|
1015
1470
|
file,
|
|
1016
1471
|
files: new Set([file]),
|
|
@@ -1186,13 +1641,165 @@ export function zyzz(options: zyzz.Options = {}): Plugin {
|
|
|
1186
1641
|
.map(([, configuration]) => configuration)
|
|
1187
1642
|
}
|
|
1188
1643
|
|
|
1644
|
+
/**
|
|
1645
|
+
* The modules an edit invalidates: those whose code or stylesheet differs from what Vite served.
|
|
1646
|
+
* A concurrent compile can already hold the edit, so outputs are not compared with each other.
|
|
1647
|
+
*/
|
|
1648
|
+
async function changes(
|
|
1649
|
+
environment: DevEnvironment,
|
|
1650
|
+
after: Graph.compile.ReturnType,
|
|
1651
|
+
served: Served,
|
|
1652
|
+
modules: readonly EnvironmentModuleNode[],
|
|
1653
|
+
timestamp: number,
|
|
1654
|
+
edited: string,
|
|
1655
|
+
deleted: string | undefined,
|
|
1656
|
+
) {
|
|
1657
|
+
// Portable build adapters share this module and do not require Vite.
|
|
1658
|
+
const { transformWithOxc } = await import('vite')
|
|
1659
|
+
const code = new Set<string>()
|
|
1660
|
+
const css = new Set<string>()
|
|
1661
|
+
|
|
1662
|
+
for (const [
|
|
1663
|
+
entry,
|
|
1664
|
+
{ code: current, css: stylesheet, imports },
|
|
1665
|
+
] of served.entries) {
|
|
1666
|
+
const id = sourceId(entry.file)
|
|
1667
|
+
const next = after.modules[id]
|
|
1668
|
+
|
|
1669
|
+
if (!next) continue
|
|
1670
|
+
|
|
1671
|
+
// A stylesheet Vite never loaded has no module to invalidate.
|
|
1672
|
+
if (stylesheet !== undefined && stylesheet !== next.css)
|
|
1673
|
+
css.add(entry.file)
|
|
1674
|
+
|
|
1675
|
+
// A stylesheet request can compile a module whose code was never transformed here.
|
|
1676
|
+
if (current === undefined) continue
|
|
1677
|
+
|
|
1678
|
+
if (imports !== JSON.stringify(projects.get(environment)?.imports[id])) {
|
|
1679
|
+
code.add(entry.file)
|
|
1680
|
+
continue
|
|
1681
|
+
}
|
|
1682
|
+
|
|
1683
|
+
if (current === next.code) continue
|
|
1684
|
+
|
|
1685
|
+
// Generated type assertions can change without changing runtime bindings.
|
|
1686
|
+
const [left, right] = await Promise.all([
|
|
1687
|
+
transformWithOxc(current, entry.file, { sourcemap: false }),
|
|
1688
|
+
transformWithOxc(next.code, entry.file, { sourcemap: false }),
|
|
1689
|
+
])
|
|
1690
|
+
|
|
1691
|
+
if (left.code !== right.code) code.add(entry.file)
|
|
1692
|
+
}
|
|
1693
|
+
|
|
1694
|
+
const stylesheets = new Set<string>()
|
|
1695
|
+
|
|
1696
|
+
if (deleted !== undefined) stylesheets.add(cssId(deleted))
|
|
1697
|
+
if (
|
|
1698
|
+
served.shared !== undefined &&
|
|
1699
|
+
served.shared !== (after.sharedCss ?? '')
|
|
1700
|
+
)
|
|
1701
|
+
stylesheets.add(sharedId)
|
|
1702
|
+
for (const file of css) stylesheets.add(cssId(file))
|
|
1703
|
+
|
|
1704
|
+
// Compiled modules the edit left unchanged skip Vite's own update; other modules, such as
|
|
1705
|
+
// plain JavaScript or assets, keep it.
|
|
1706
|
+
const affected = new Set(
|
|
1707
|
+
modules.filter((module) => {
|
|
1708
|
+
if (!module.id) return module.type !== 'asset'
|
|
1709
|
+
|
|
1710
|
+
const file = normalize(module.id)
|
|
1711
|
+
|
|
1712
|
+
return Object.hasOwn(after.modules, sourceId(file))
|
|
1713
|
+
? code.has(file)
|
|
1714
|
+
: true
|
|
1715
|
+
}),
|
|
1716
|
+
)
|
|
1717
|
+
|
|
1718
|
+
for (const file of code) {
|
|
1719
|
+
const module = environment.moduleGraph.getModuleById(file)
|
|
1720
|
+
if (!module) continue
|
|
1721
|
+
|
|
1722
|
+
environment.moduleGraph.invalidateModule(
|
|
1723
|
+
module,
|
|
1724
|
+
new Set(),
|
|
1725
|
+
timestamp,
|
|
1726
|
+
true,
|
|
1727
|
+
)
|
|
1728
|
+
affected.add(module)
|
|
1729
|
+
}
|
|
1730
|
+
|
|
1731
|
+
const sheets: EnvironmentModuleNode[] = []
|
|
1732
|
+
|
|
1733
|
+
// The edited module's stylesheet updates first, ahead of stylesheets other modules share.
|
|
1734
|
+
for (const id of [...stylesheets].sort(
|
|
1735
|
+
(left, right) =>
|
|
1736
|
+
Number(right === cssId(edited)) - Number(left === cssId(edited)),
|
|
1737
|
+
)) {
|
|
1738
|
+
const module = environment.moduleGraph.getModuleById(id)
|
|
1739
|
+
if (!module) continue
|
|
1740
|
+
|
|
1741
|
+
environment.moduleGraph.invalidateModule(
|
|
1742
|
+
module,
|
|
1743
|
+
new Set(),
|
|
1744
|
+
timestamp,
|
|
1745
|
+
true,
|
|
1746
|
+
)
|
|
1747
|
+
sheets.push(module)
|
|
1748
|
+
}
|
|
1749
|
+
|
|
1750
|
+
// A stylesheet accepts its own updates and only its module imports it, so it is never within
|
|
1751
|
+
// an import cycle. Vite proves that by walking every importer of the importing module, which
|
|
1752
|
+
// costs each stylesheet of a shared edit the whole graph, so stylesheet-only edits send the
|
|
1753
|
+
// same update directly. Edits that also change code keep Vite's single batched update.
|
|
1754
|
+
if (
|
|
1755
|
+
!affected.size &&
|
|
1756
|
+
sheets.length &&
|
|
1757
|
+
sheets.every((module) => module.isSelfAccepting)
|
|
1758
|
+
) {
|
|
1759
|
+
const updates = sheets.map((module) => {
|
|
1760
|
+
const path =
|
|
1761
|
+
module.url.startsWith('/') || module.url.startsWith('.')
|
|
1762
|
+
? module.url
|
|
1763
|
+
: `/@id/${module.url.replace('\0', '__x00__')}`
|
|
1764
|
+
|
|
1765
|
+
return {
|
|
1766
|
+
acceptedPath: path,
|
|
1767
|
+
explicitImportRequired: false,
|
|
1768
|
+
isWithinCircularImport: false,
|
|
1769
|
+
path,
|
|
1770
|
+
timestamp,
|
|
1771
|
+
type: 'js-update' as const,
|
|
1772
|
+
}
|
|
1773
|
+
})
|
|
1774
|
+
|
|
1775
|
+
environment.logger.info(
|
|
1776
|
+
`hmr update ${updates.map((update) => update.path).join(', ')}`,
|
|
1777
|
+
{ timestamp: true },
|
|
1778
|
+
)
|
|
1779
|
+
environment.hot.send({ type: 'update', updates })
|
|
1780
|
+
return []
|
|
1781
|
+
}
|
|
1782
|
+
|
|
1783
|
+
for (const module of sheets) affected.add(module)
|
|
1784
|
+
|
|
1785
|
+
return [...affected]
|
|
1786
|
+
}
|
|
1787
|
+
|
|
1189
1788
|
return {
|
|
1190
1789
|
buildStart() {
|
|
1790
|
+
edgeMemos.delete(this.environment)
|
|
1191
1791
|
reads.delete(this.environment)
|
|
1792
|
+
lookups.delete(this.environment)
|
|
1192
1793
|
},
|
|
1193
1794
|
config: {
|
|
1194
1795
|
order: 'post',
|
|
1195
|
-
handler(config) {
|
|
1796
|
+
handler(config, env) {
|
|
1797
|
+
// Ordered after other config hooks, so plugin-provided aliases are visible.
|
|
1798
|
+
optimizeRuntime =
|
|
1799
|
+
env.command === 'serve' &&
|
|
1800
|
+
options.compiler !== false &&
|
|
1801
|
+
installed(config)
|
|
1802
|
+
|
|
1196
1803
|
if (native) return
|
|
1197
1804
|
// Inline color-scheme changes cannot initialize Lightning's lowered helpers.
|
|
1198
1805
|
return {
|
|
@@ -1221,7 +1828,35 @@ export function zyzz(options: zyzz.Options = {}): Plugin {
|
|
|
1221
1828
|
}
|
|
1222
1829
|
},
|
|
1223
1830
|
},
|
|
1831
|
+
configEnvironment: {
|
|
1832
|
+
// Plugins without enforce settle their environment options first.
|
|
1833
|
+
order: 'post',
|
|
1834
|
+
handler(name, config) {
|
|
1835
|
+
if (!optimizeRuntime) return
|
|
1836
|
+
|
|
1837
|
+
const optimizeDeps = config.optimizeDeps ?? {}
|
|
1838
|
+
const consumer =
|
|
1839
|
+
config.consumer ?? (name === 'client' ? 'client' : 'server')
|
|
1840
|
+
|
|
1841
|
+
// Vite defaults server environments to noDiscovery. An include list there
|
|
1842
|
+
// would create an explicit optimizer that otherwise never exists.
|
|
1843
|
+
if (optimizeDeps.noDiscovery ?? consumer === 'server') return
|
|
1844
|
+
if (
|
|
1845
|
+
optimizeDeps.include?.includes(runtime) ||
|
|
1846
|
+
optimizeDeps.exclude?.some((id) => id === 'zyzz' || id === runtime)
|
|
1847
|
+
)
|
|
1848
|
+
return
|
|
1849
|
+
|
|
1850
|
+
// Vite scans authored source, so the runtime import that compilation
|
|
1851
|
+
// adds first appears while a request transforms a module. Discovering
|
|
1852
|
+
// it then re-runs the optimizer, and modules loaded before the re-run
|
|
1853
|
+
// can keep a separate copy of a shared dependency such as React.
|
|
1854
|
+
return { optimizeDeps: { include: [runtime] } }
|
|
1855
|
+
},
|
|
1856
|
+
},
|
|
1224
1857
|
configureServer(server) {
|
|
1858
|
+
devServer = server
|
|
1859
|
+
|
|
1225
1860
|
// Directory watches belong to the server, not module import dependencies.
|
|
1226
1861
|
server.watcher.add(directories.slice(1))
|
|
1227
1862
|
|
|
@@ -1257,6 +1892,15 @@ export function zyzz(options: zyzz.Options = {}): Plugin {
|
|
|
1257
1892
|
}),
|
|
1258
1893
|
)),
|
|
1259
1894
|
]
|
|
1895
|
+
|
|
1896
|
+
// Portable build adapters share this module and do not require Vite.
|
|
1897
|
+
const { createFilter } = await import('vite')
|
|
1898
|
+
const patterns = [...configFiles, ...(options.exclude ?? [])]
|
|
1899
|
+
|
|
1900
|
+
filter = createFilter(null, patterns, { resolve: root })
|
|
1901
|
+
exclusions.clear()
|
|
1902
|
+
roots.clear()
|
|
1903
|
+
|
|
1260
1904
|
if (native) return
|
|
1261
1905
|
const lightning = (config.css.lightningcss ??= {})
|
|
1262
1906
|
lightning.include =
|
|
@@ -1348,10 +1992,65 @@ export function zyzz(options: zyzz.Options = {}): Plugin {
|
|
|
1348
1992
|
},
|
|
1349
1993
|
},
|
|
1350
1994
|
async watchChange(file, change) {
|
|
1995
|
+
// A removed file leaves the watcher, so a later compile that reads it again adds it again.
|
|
1996
|
+
if (change.event === 'delete') watched.delete(file)
|
|
1997
|
+
|
|
1351
1998
|
await updateDiscovery(this.environment, file, change.event)
|
|
1352
1999
|
},
|
|
1353
2000
|
async hotUpdate({ file, modules, timestamp, type, server }) {
|
|
1354
2001
|
const state = entries(this.environment)
|
|
2002
|
+
const before = projects.get(this.environment)?.outcome
|
|
2003
|
+
// Concurrent transforms update entries while this compiles, so the served output is read now.
|
|
2004
|
+
const served: Served = {
|
|
2005
|
+
entries: new Map(
|
|
2006
|
+
[...state.values()].map((entry) => [
|
|
2007
|
+
entry,
|
|
2008
|
+
{ code: entry.code, css: entry.css, imports: entry.imports },
|
|
2009
|
+
]),
|
|
2010
|
+
),
|
|
2011
|
+
shared: servedShared.get(this.environment),
|
|
2012
|
+
}
|
|
2013
|
+
|
|
2014
|
+
// The merged development graph compares module outputs before and after the edit, so
|
|
2015
|
+
// only modules whose code or stylesheet changed update.
|
|
2016
|
+
if (!native && before && 'result' in before) {
|
|
2017
|
+
await updateDiscovery(this.environment, file, type)
|
|
2018
|
+
|
|
2019
|
+
// The edited module's own entry, or one whose closure reads it, merges its new source.
|
|
2020
|
+
// A contribution source no module imports joins every closure.
|
|
2021
|
+
const first =
|
|
2022
|
+
state.get(file) ??
|
|
2023
|
+
[...state.values()].find((entry) => entry.files.has(file)) ??
|
|
2024
|
+
(eager(file, this.environment)
|
|
2025
|
+
? state.values().next().value
|
|
2026
|
+
: undefined)
|
|
2027
|
+
if (!first && !removed.get(this.environment)?.has(file)) return modules
|
|
2028
|
+
|
|
2029
|
+
const compiled =
|
|
2030
|
+
first && type === 'update' && eligible(file)
|
|
2031
|
+
? await compile(first, {
|
|
2032
|
+
resolve: resolver(this.environment),
|
|
2033
|
+
watch: (file) => watch(server, file),
|
|
2034
|
+
asset: async (file) => file,
|
|
2035
|
+
}).then(
|
|
2036
|
+
() => true,
|
|
2037
|
+
() => false,
|
|
2038
|
+
)
|
|
2039
|
+
: false
|
|
2040
|
+
const after = projects.get(this.environment)?.outcome
|
|
2041
|
+
|
|
2042
|
+
if (compiled && after && 'result' in after)
|
|
2043
|
+
return await changes(
|
|
2044
|
+
this.environment,
|
|
2045
|
+
after.result,
|
|
2046
|
+
served,
|
|
2047
|
+
modules,
|
|
2048
|
+
timestamp,
|
|
2049
|
+
file,
|
|
2050
|
+
type === 'delete' ? file : undefined,
|
|
2051
|
+
)
|
|
2052
|
+
}
|
|
2053
|
+
|
|
1355
2054
|
const previous = [...state.values()].map((entry) => ({
|
|
1356
2055
|
code: entry.code,
|
|
1357
2056
|
file: entry.file,
|
|
@@ -1370,11 +2069,8 @@ export function zyzz(options: zyzz.Options = {}): Plugin {
|
|
|
1370
2069
|
? await compile(
|
|
1371
2070
|
first,
|
|
1372
2071
|
{
|
|
1373
|
-
resolve: (
|
|
1374
|
-
|
|
1375
|
-
watch: (file) => {
|
|
1376
|
-
server.watcher.add(file)
|
|
1377
|
-
},
|
|
2072
|
+
resolve: resolver(this.environment),
|
|
2073
|
+
watch: (file) => watch(server, file),
|
|
1378
2074
|
asset: async (file) => file,
|
|
1379
2075
|
},
|
|
1380
2076
|
undefined,
|
|
@@ -1454,19 +2150,49 @@ export function zyzz(options: zyzz.Options = {}): Plugin {
|
|
|
1454
2150
|
id === sharedId
|
|
1455
2151
|
? undefined
|
|
1456
2152
|
: decodeURIComponent(id.slice(prefix.length, -4))
|
|
1457
|
-
|
|
2153
|
+
let entry =
|
|
1458
2154
|
file === undefined
|
|
1459
2155
|
? entries(this.environment).values().next().value
|
|
1460
2156
|
: entries(this.environment).get(file)
|
|
1461
2157
|
// A pruned JavaScript module can leave its stylesheet loaded in the browser.
|
|
1462
2158
|
if (!entry && file && removed.get(this.environment)?.has(file)) return ''
|
|
2159
|
+
|
|
2160
|
+
// Server rendering links the stylesheets of modules this environment has not transformed
|
|
2161
|
+
// yet, so a development request compiles the module where the browser loads it.
|
|
2162
|
+
if (!entry && this.environment.mode === 'dev') {
|
|
2163
|
+
const anchor =
|
|
2164
|
+
file ??
|
|
2165
|
+
(
|
|
2166
|
+
await discover(this.environment, {
|
|
2167
|
+
asset: async (file) => file,
|
|
2168
|
+
resolve: resolver(this.environment),
|
|
2169
|
+
watch: watcher(this),
|
|
2170
|
+
})
|
|
2171
|
+
)
|
|
2172
|
+
.keys()
|
|
2173
|
+
.next().value
|
|
2174
|
+
|
|
2175
|
+
if (anchor !== undefined && eligible(anchor)) {
|
|
2176
|
+
entry = {
|
|
2177
|
+
compiler: compiler(this.environment),
|
|
2178
|
+
environment: this.environment,
|
|
2179
|
+
file: anchor,
|
|
2180
|
+
files: new Set([anchor]),
|
|
2181
|
+
}
|
|
2182
|
+
entries(this.environment).set(anchor, entry)
|
|
2183
|
+
}
|
|
2184
|
+
}
|
|
2185
|
+
|
|
1463
2186
|
if (!entry) throw new Error(`Unknown Zyzz stylesheet: ${file}`)
|
|
1464
2187
|
|
|
1465
2188
|
const output = await compile(
|
|
1466
2189
|
entry,
|
|
1467
2190
|
{
|
|
1468
|
-
resolve:
|
|
1469
|
-
|
|
2191
|
+
resolve:
|
|
2192
|
+
this.environment.mode === 'dev'
|
|
2193
|
+
? resolver(this.environment)
|
|
2194
|
+
: (source, importer) => this.resolve(source, importer),
|
|
2195
|
+
watch: watcher(this),
|
|
1470
2196
|
asset: async (file) => {
|
|
1471
2197
|
const reference = this.emitFile({
|
|
1472
2198
|
type: 'asset',
|
|
@@ -1494,12 +2220,19 @@ export function zyzz(options: zyzz.Options = {}): Plugin {
|
|
|
1494
2220
|
'-zyzz-fpv-000000000',
|
|
1495
2221
|
)
|
|
1496
2222
|
: css
|
|
1497
|
-
if (id === sharedId)
|
|
2223
|
+
if (id === sharedId) {
|
|
2224
|
+
servedShared.set(this.environment, output.graphSharedCss)
|
|
1498
2225
|
return {
|
|
1499
2226
|
code: transport(output.sharedCss),
|
|
1500
2227
|
map: JSON.stringify(output.sharedCssMap),
|
|
1501
2228
|
}
|
|
1502
|
-
|
|
2229
|
+
}
|
|
2230
|
+
|
|
2231
|
+
entry.css = output.css
|
|
2232
|
+
return {
|
|
2233
|
+
code: transport(output.css),
|
|
2234
|
+
map: JSON.stringify(output.cssMap),
|
|
2235
|
+
}
|
|
1503
2236
|
},
|
|
1504
2237
|
name: 'zyzz',
|
|
1505
2238
|
resolveId(id) {
|
|
@@ -1524,11 +2257,16 @@ export function zyzz(options: zyzz.Options = {}): Plugin {
|
|
|
1524
2257
|
removed.get(this.environment)?.delete(id)
|
|
1525
2258
|
}
|
|
1526
2259
|
|
|
2260
|
+
entry.source = code
|
|
2261
|
+
|
|
1527
2262
|
const output = await compile(
|
|
1528
2263
|
entry,
|
|
1529
2264
|
{
|
|
1530
|
-
resolve:
|
|
1531
|
-
|
|
2265
|
+
resolve:
|
|
2266
|
+
this.environment.mode === 'dev'
|
|
2267
|
+
? resolver(this.environment)
|
|
2268
|
+
: (source, importer) => this.resolve(source, importer),
|
|
2269
|
+
watch: watcher(this),
|
|
1532
2270
|
asset: async (file) => {
|
|
1533
2271
|
const reference = this.emitFile({
|
|
1534
2272
|
type: 'asset',
|
|
@@ -1550,64 +2288,29 @@ export function zyzz(options: zyzz.Options = {}): Plugin {
|
|
|
1550
2288
|
|
|
1551
2289
|
// Keep the CSS dependency even when the current graph has no live rules.
|
|
1552
2290
|
// Later edits can introduce styles without changing this import boundary.
|
|
1553
|
-
const
|
|
1554
|
-
sourceType: 'module',
|
|
1555
|
-
})
|
|
1556
|
-
let offset = output.code.startsWith('#!')
|
|
1557
|
-
? output.code.indexOf('\n') + 1
|
|
1558
|
-
: 0
|
|
1559
|
-
|
|
1560
|
-
for (const node of parsed.program.body) {
|
|
1561
|
-
if (node.type !== 'ExpressionStatement' || !node.directive) break
|
|
1562
|
-
|
|
1563
|
-
offset = node.end
|
|
1564
|
-
}
|
|
1565
|
-
|
|
2291
|
+
const offset = prologue(output.code)
|
|
1566
2292
|
const sharedImport = `\nimport ${JSON.stringify(sharedId)};\n`
|
|
1567
|
-
const map = Mapping.fromMap(JSON.stringify(output.map))
|
|
1568
2293
|
// The inserted dependency shifts only generated positions after the prologue.
|
|
1569
2294
|
const before = output.code.slice(0, offset)
|
|
1570
2295
|
const insertionLine = before.split('\n').length
|
|
1571
2296
|
const insertionColumn = before.length - (before.lastIndexOf('\n') + 1)
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
generated.line > insertionLine ||
|
|
1579
|
-
(generated.line === insertionLine &&
|
|
1580
|
-
generated.column >= insertionColumn)
|
|
1581
|
-
) {
|
|
1582
|
-
if (generated.line === insertionLine)
|
|
1583
|
-
generated.column -= insertionColumn
|
|
1584
|
-
|
|
1585
|
-
generated.line += 2
|
|
1586
|
-
}
|
|
1587
|
-
|
|
1588
|
-
if (mapping.source !== undefined && mapping.original !== undefined) {
|
|
1589
|
-
const location = {
|
|
1590
|
-
generated,
|
|
1591
|
-
original: mapping.original,
|
|
1592
|
-
source: mapping.source,
|
|
1593
|
-
}
|
|
1594
|
-
|
|
1595
|
-
if (mapping.name === undefined) Mapping.addMapping(shifted, location)
|
|
1596
|
-
else Mapping.addMapping(shifted, { ...location, name: mapping.name })
|
|
1597
|
-
} else Mapping.addMapping(shifted, { generated })
|
|
1598
|
-
}
|
|
1599
|
-
|
|
1600
|
-
for (const [index, source] of output.map.sources.entries())
|
|
1601
|
-
if (source !== null)
|
|
1602
|
-
Mapping.setSourceContent(
|
|
1603
|
-
shifted,
|
|
1604
|
-
source,
|
|
1605
|
-
output.map.sourcesContent?.[index] ?? null,
|
|
1606
|
-
)
|
|
2297
|
+
// A build compiles a fixed project, so an empty module sheet stays empty. Importing it
|
|
2298
|
+
// would link an empty stylesheet from every chunk that holds no styled module.
|
|
2299
|
+
const stylesheetImport =
|
|
2300
|
+
this.environment.mode === 'build' && !output.css.trim()
|
|
2301
|
+
? ''
|
|
2302
|
+
: `\nimport ${JSON.stringify(cssId(id))};`
|
|
1607
2303
|
|
|
1608
2304
|
return {
|
|
1609
|
-
code: `${before}${sharedImport}${output.code.slice(offset)}
|
|
1610
|
-
map: JSON.stringify(
|
|
2305
|
+
code: `${before}${sharedImport}${output.code.slice(offset)}${stylesheetImport}`,
|
|
2306
|
+
map: JSON.stringify({
|
|
2307
|
+
...output.map,
|
|
2308
|
+
mappings: insert(
|
|
2309
|
+
output.map.mappings,
|
|
2310
|
+
insertionLine - 1,
|
|
2311
|
+
insertionColumn,
|
|
2312
|
+
),
|
|
2313
|
+
}),
|
|
1611
2314
|
}
|
|
1612
2315
|
},
|
|
1613
2316
|
transformIndexHtml: {
|
|
@@ -1629,8 +2332,7 @@ export function zyzz(options: zyzz.Options = {}): Plugin {
|
|
|
1629
2332
|
return await documentCatalogs(
|
|
1630
2333
|
html,
|
|
1631
2334
|
context.filename,
|
|
1632
|
-
(
|
|
1633
|
-
environment.pluginContainer.resolveId(source, importer),
|
|
2335
|
+
resolver(environment),
|
|
1634
2336
|
state,
|
|
1635
2337
|
)
|
|
1636
2338
|
})()
|
|
@@ -1645,13 +2347,25 @@ export function zyzz(options: zyzz.Options = {}): Plugin {
|
|
|
1645
2347
|
}
|
|
1646
2348
|
}
|
|
1647
2349
|
|
|
2350
|
+
/** One module's import edges: its resolutions and, in order, its visits and contract reads. */
|
|
2351
|
+
type Edges = {
|
|
2352
|
+
lazy: ReadonlySet<string>
|
|
2353
|
+
resolutions: Readonly<Record<string, string | null>>
|
|
2354
|
+
steps: readonly (string | { id: string; physical: string })[]
|
|
2355
|
+
text: string
|
|
2356
|
+
}
|
|
2357
|
+
|
|
1648
2358
|
type Entry = {
|
|
1649
2359
|
code?: string
|
|
1650
|
-
imports?: string
|
|
1651
|
-
environment: Environment
|
|
1652
2360
|
compiler: Graph.create.ReturnType
|
|
2361
|
+
/** The stylesheet Vite last loaded for this module. */
|
|
2362
|
+
css?: string | undefined
|
|
2363
|
+
environment: Environment
|
|
1653
2364
|
file: string
|
|
1654
2365
|
files: Set<string>
|
|
2366
|
+
imports?: string
|
|
2367
|
+
/** The code Vite last passed to the transform, until a watcher event changes the file. */
|
|
2368
|
+
source?: string | undefined
|
|
1655
2369
|
}
|
|
1656
2370
|
|
|
1657
2371
|
type Host = {
|
|
@@ -1666,7 +2380,202 @@ type Host = {
|
|
|
1666
2380
|
watch: (file: string) => void
|
|
1667
2381
|
}
|
|
1668
2382
|
|
|
2383
|
+
type Lookups = {
|
|
2384
|
+
contracts: Map<
|
|
2385
|
+
string,
|
|
2386
|
+
Promise<{ contract: string | undefined; files: ReadonlySet<string> }>
|
|
2387
|
+
>
|
|
2388
|
+
/** Files each settled contract read, so an edit to one drops only its contracts. */
|
|
2389
|
+
read: Map<string, ReadonlySet<string>>
|
|
2390
|
+
resolutions: Map<string, ReturnType<Host['resolve']>>
|
|
2391
|
+
}
|
|
2392
|
+
|
|
2393
|
+
/** One development environment's merged source graph and its last compilation. */
|
|
2394
|
+
type Project = {
|
|
2395
|
+
compiler: Graph.create.ReturnType
|
|
2396
|
+
contracts: Record<string, string>
|
|
2397
|
+
/** Compiles a closure alone while the merged graph fails. */
|
|
2398
|
+
fallback: Graph.create.ReturnType
|
|
2399
|
+
imports: Record<string, Record<string, string | null>>
|
|
2400
|
+
modules: Record<string, string>
|
|
2401
|
+
outcome:
|
|
2402
|
+
| { readonly error: unknown }
|
|
2403
|
+
| { readonly result: Graph.compile.ReturnType }
|
|
2404
|
+
| undefined
|
|
2405
|
+
}
|
|
2406
|
+
|
|
2407
|
+
/** What an environment served when an edit arrived. */
|
|
2408
|
+
type Served = {
|
|
2409
|
+
entries: ReadonlyMap<
|
|
2410
|
+
Entry,
|
|
2411
|
+
{
|
|
2412
|
+
code: string | undefined
|
|
2413
|
+
css: string | undefined
|
|
2414
|
+
imports: string | undefined
|
|
2415
|
+
}
|
|
2416
|
+
>
|
|
2417
|
+
shared: string | undefined
|
|
2418
|
+
}
|
|
2419
|
+
|
|
2420
|
+
/**
|
|
2421
|
+
* The end of a module's hashbang and directive prologue, where an added import keeps directives
|
|
2422
|
+
* first. Source without a leading string literal skips parsing.
|
|
2423
|
+
*/
|
|
2424
|
+
function prologue(code: string) {
|
|
2425
|
+
let index = code.startsWith('#!') ? code.indexOf('\n') + 1 : 0
|
|
2426
|
+
const start = index
|
|
2427
|
+
|
|
2428
|
+
for (;;) {
|
|
2429
|
+
while (index < code.length && /\s/.test(code[index]!)) index++
|
|
2430
|
+
|
|
2431
|
+
if (code.startsWith('//', index)) {
|
|
2432
|
+
const end = code.indexOf('\n', index)
|
|
2433
|
+
index = end === -1 ? code.length : end
|
|
2434
|
+
} else if (code.startsWith('/*', index)) {
|
|
2435
|
+
const end = code.indexOf('*/', index + 2)
|
|
2436
|
+
index = end === -1 ? code.length : end + 2
|
|
2437
|
+
} else break
|
|
2438
|
+
}
|
|
2439
|
+
|
|
2440
|
+
if (code[index] !== "'" && code[index] !== '"') return start
|
|
2441
|
+
|
|
2442
|
+
let offset = start
|
|
2443
|
+
const { program } = Parser.parseSync('source.tsx', code, {
|
|
2444
|
+
sourceType: 'module',
|
|
2445
|
+
})
|
|
2446
|
+
|
|
2447
|
+
for (const node of program.body) {
|
|
2448
|
+
if (node.type !== 'ExpressionStatement' || !node.directive) break
|
|
2449
|
+
|
|
2450
|
+
offset = node.end
|
|
2451
|
+
}
|
|
2452
|
+
|
|
2453
|
+
return offset
|
|
2454
|
+
}
|
|
2455
|
+
|
|
2456
|
+
/**
|
|
2457
|
+
* Moves encoded mappings for two lines inserted at a generated position. Segments at or past
|
|
2458
|
+
* `column` on `line` start the line after the insertion, and every later line moves down by two.
|
|
2459
|
+
* Other fields stay relative to the segment before them, which keeps its order.
|
|
2460
|
+
*/
|
|
2461
|
+
function insert(mappings: string, line: number, column: number) {
|
|
2462
|
+
const lines = mappings.split(';')
|
|
2463
|
+
const text = lines[line]
|
|
2464
|
+
|
|
2465
|
+
if (text === undefined) return mappings
|
|
2466
|
+
|
|
2467
|
+
let generated = 0
|
|
2468
|
+
let split = -1
|
|
2469
|
+
let position = 0
|
|
2470
|
+
const segments = text ? text.split(',') : []
|
|
2471
|
+
|
|
2472
|
+
for (const [index, segment] of segments.entries()) {
|
|
2473
|
+
const [delta] = Vlq.decode(segment)
|
|
2474
|
+
|
|
2475
|
+
generated += delta!
|
|
2476
|
+
|
|
2477
|
+
if (generated >= column) {
|
|
2478
|
+
split = index
|
|
2479
|
+
position = generated
|
|
2480
|
+
break
|
|
2481
|
+
}
|
|
2482
|
+
}
|
|
2483
|
+
|
|
2484
|
+
if (split === -1) {
|
|
2485
|
+
lines.splice(line + 1, 0, '', '')
|
|
2486
|
+
return lines.join(';')
|
|
2487
|
+
}
|
|
2488
|
+
|
|
2489
|
+
const moved = segments.slice(split)
|
|
2490
|
+
const fields = Vlq.decode(moved[0]!)
|
|
2491
|
+
|
|
2492
|
+
fields[0] = position - column
|
|
2493
|
+
moved[0] = Vlq.encode(fields)
|
|
2494
|
+
lines.splice(line, 1, segments.slice(0, split).join(','), '', moved.join(','))
|
|
2495
|
+
|
|
2496
|
+
return lines.join(';')
|
|
2497
|
+
}
|
|
2498
|
+
|
|
2499
|
+
/** Whether two import resolution records hold the same entries. */
|
|
2500
|
+
function same(
|
|
2501
|
+
left: Readonly<Record<string, string | null>> | undefined,
|
|
2502
|
+
right: Readonly<Record<string, string | null>>,
|
|
2503
|
+
) {
|
|
2504
|
+
if (!left) return false
|
|
2505
|
+
|
|
2506
|
+
const keys = Object.keys(right)
|
|
2507
|
+
if (Object.keys(left).length !== keys.length) return false
|
|
2508
|
+
|
|
2509
|
+
return keys.every((key) => left[key] === right[key])
|
|
2510
|
+
}
|
|
2511
|
+
|
|
2512
|
+
/**
|
|
2513
|
+
* Whether `zyzz/runtime` resolves inside node_modules from the Vite root. Vite
|
|
2514
|
+
* optimizes a discovered import only there, so linked and aliased copies stay
|
|
2515
|
+
* source modules beside the other entrypoints.
|
|
2516
|
+
*/
|
|
2517
|
+
function installed(config: UserConfig) {
|
|
2518
|
+
const aliases = config.resolve?.alias ?? {}
|
|
2519
|
+
const entries = Array.isArray(aliases)
|
|
2520
|
+
? aliases
|
|
2521
|
+
: Object.entries(aliases).map(([find, replacement]) => ({
|
|
2522
|
+
find,
|
|
2523
|
+
replacement,
|
|
2524
|
+
}))
|
|
2525
|
+
|
|
2526
|
+
// Matches Vite's alias semantics: a string entry covers its subpaths.
|
|
2527
|
+
if (
|
|
2528
|
+
entries.some((entry) =>
|
|
2529
|
+
typeof entry.find === 'string'
|
|
2530
|
+
? runtime === entry.find || runtime.startsWith(`${entry.find}/`)
|
|
2531
|
+
: entry.find.test(runtime),
|
|
2532
|
+
)
|
|
2533
|
+
)
|
|
2534
|
+
return false
|
|
2535
|
+
|
|
2536
|
+
try {
|
|
2537
|
+
const require = createRequire(
|
|
2538
|
+
Path.join(Path.resolve(config.root ?? ''), 'package.json'),
|
|
2539
|
+
)
|
|
2540
|
+
|
|
2541
|
+
// Vite keeps a symlinked package at its node_modules path, which Node dereferences.
|
|
2542
|
+
if (config.resolve?.preserveSymlinks)
|
|
2543
|
+
return (require.resolve.paths('zyzz') ?? []).some((directory) =>
|
|
2544
|
+
existsSync(Path.join(directory, 'zyzz/package.json')),
|
|
2545
|
+
)
|
|
2546
|
+
|
|
2547
|
+
return require.resolve(runtime).split(Path.sep).includes('node_modules')
|
|
2548
|
+
} catch {
|
|
2549
|
+
return false
|
|
2550
|
+
}
|
|
2551
|
+
}
|
|
2552
|
+
|
|
2553
|
+
// Vite forwards `scan` to `resolveId` hooks but leaves it out of its public types.
|
|
2554
|
+
type ScanOptions = NonNullable<
|
|
2555
|
+
Parameters<DevEnvironment['pluginContainer']['resolveId']>[2]
|
|
2556
|
+
> & { scan: boolean }
|
|
2557
|
+
|
|
2558
|
+
const scan: ScanOptions = { scan: true }
|
|
2559
|
+
|
|
2560
|
+
/**
|
|
2561
|
+
* Resolves imports read from source before other plugins transform their
|
|
2562
|
+
* importers. Marking them as scans, as Vite's dependency scanner does, keeps the
|
|
2563
|
+
* optimizer from discovering their dependencies and lets plugins tell them apart
|
|
2564
|
+
* from imports that reach the module graph.
|
|
2565
|
+
*/
|
|
2566
|
+
function resolver(environment: DevEnvironment): Host['resolve'] {
|
|
2567
|
+
return (source, importer) =>
|
|
2568
|
+
environment.pluginContainer.resolveId(source, importer, scan)
|
|
2569
|
+
}
|
|
2570
|
+
|
|
2571
|
+
// Vite and Vitest load their own configuration modules, which application code never imports.
|
|
2572
|
+
const configFiles = [
|
|
2573
|
+
'**/vite.config.*',
|
|
2574
|
+
'**/vitest.config.*',
|
|
2575
|
+
'**/vitest.workspace.*',
|
|
2576
|
+
]
|
|
1669
2577
|
const prefix = '\0zyzz:'
|
|
2578
|
+
const runtime = 'zyzz/runtime'
|
|
1670
2579
|
const sharedId = `${prefix}shared.css`
|
|
1671
2580
|
|
|
1672
2581
|
function cssId(file: string) {
|
|
@@ -1679,6 +2588,13 @@ export declare namespace zyzz {
|
|
|
1679
2588
|
type Options = {
|
|
1680
2589
|
/** False retains authored calls and requires explicit identities where needed. */
|
|
1681
2590
|
readonly compiler?: boolean | undefined
|
|
2591
|
+
/**
|
|
2592
|
+
* Source modules left out of discovery and transforms. Globs resolve against the
|
|
2593
|
+
* Vite root unless they start with `**`, and regular expressions test absolute paths.
|
|
2594
|
+
* Imports of excluded modules stay runtime imports. Vite and Vitest configuration
|
|
2595
|
+
* modules are always excluded.
|
|
2596
|
+
*/
|
|
2597
|
+
readonly exclude?: readonly (RegExp | string)[] | undefined
|
|
1682
2598
|
/** Additional source directories, absolute or relative to the Vite root. */
|
|
1683
2599
|
readonly include?: readonly string[] | undefined
|
|
1684
2600
|
/** Native context captured at creation. Disables CSS delivery and initialization scripts. */
|