zyzz 0.0.28 → 0.0.30
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 -1267
- 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 -961
- 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/Literal.d.ts +4 -1
- package/dist/internal/Literal.d.ts.map +1 -1
- package/dist/internal/Literal.js +4 -2
- package/dist/internal/Literal.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/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.map +1 -1
- package/dist/vite/index.js +696 -201
- 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 -1803
- package/src/compiler/Transform.ts +16 -1315
- 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/Literal.ts +4 -2
- 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/unplugin/index.ts +6 -6
- package/src/vite/index.ts +922 -221
- 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 -393
- 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 -13
- package/dist/compiler/internal/Selectors.d.ts.map +0 -1
- package/dist/compiler/internal/Selectors.js +0 -280
- 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 -610
- 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 -353
- 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/dist/vite/index.js
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
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';
|
|
@@ -13,11 +14,11 @@ import { existsSync } from 'node:fs';
|
|
|
13
14
|
import * as Fs from 'node:fs/promises';
|
|
14
15
|
import * as Path from 'node:path';
|
|
15
16
|
import * as Reset from '../node/Reset.js';
|
|
17
|
+
import * as Vlq from '../internal/Vlq.js';
|
|
16
18
|
import { createRequire, isBuiltin } from 'node:module';
|
|
17
19
|
import * as Parser from 'oxc-parser';
|
|
18
20
|
import * as Walker from 'oxc-walker';
|
|
19
21
|
import * as Snapshot from '../node/internal/Snapshot.js';
|
|
20
|
-
import * as Syntax from '../compiler/internal/Syntax.js';
|
|
21
22
|
import * as Scope from '../compiler/internal/Scope.js';
|
|
22
23
|
import * as Graph from '../compiler/Graph.js';
|
|
23
24
|
import * as Source from '../compiler/Source.js';
|
|
@@ -46,6 +47,21 @@ export function zyzz(options = {}) {
|
|
|
46
47
|
const reads = new WeakMap();
|
|
47
48
|
const lookups = new WeakMap();
|
|
48
49
|
const compilers = new WeakMap();
|
|
50
|
+
const projects = new WeakMap();
|
|
51
|
+
// The shared stylesheet each environment last loaded, which an edit compares against.
|
|
52
|
+
const servedShared = new WeakMap();
|
|
53
|
+
// Watcher events advance an environment's generation, which scopes memoized whole-project work.
|
|
54
|
+
const generations = new WeakMap();
|
|
55
|
+
let devServer;
|
|
56
|
+
const watching = new Set();
|
|
57
|
+
// Chokidar matches its ignore patterns on every add, and each compile watches its whole closure.
|
|
58
|
+
const watched = new Set();
|
|
59
|
+
// Each compile reads the catalogs of every contract it saw, which rarely changes text.
|
|
60
|
+
const catalogReads = new Map();
|
|
61
|
+
const dependencyChains = new Map();
|
|
62
|
+
const edgeMemos = new WeakMap();
|
|
63
|
+
// A development entry's last output, reused until a watcher event or a recompiled graph.
|
|
64
|
+
const outputs = new WeakMap();
|
|
49
65
|
const packages = Contracts.create();
|
|
50
66
|
function compiler(environment) {
|
|
51
67
|
let value = compilers.get(environment);
|
|
@@ -55,6 +71,144 @@ export function zyzz(options = {}) {
|
|
|
55
71
|
}
|
|
56
72
|
return value;
|
|
57
73
|
}
|
|
74
|
+
/**
|
|
75
|
+
* Watches a compile input from a hook. Vite checks the filesystem each time a file outside its
|
|
76
|
+
* root is watched, and every compile reads the same package files, so development watches
|
|
77
|
+
* each of those once.
|
|
78
|
+
*/
|
|
79
|
+
function watcher(context) {
|
|
80
|
+
return (file) => {
|
|
81
|
+
if (devServer && !file.startsWith(`${devServer.config.root}/`)) {
|
|
82
|
+
if (watching.has(file))
|
|
83
|
+
return;
|
|
84
|
+
watching.add(file);
|
|
85
|
+
}
|
|
86
|
+
context.addWatchFile(file);
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* The packed stylesheet dependency chains of a library contract. Every compile reads each
|
|
91
|
+
* contract it reaches, and design system contracts are large, so each text parses once.
|
|
92
|
+
*/
|
|
93
|
+
function stylesheetDependencies(id, contract) {
|
|
94
|
+
let value = dependencyChains.get(contract);
|
|
95
|
+
if (value)
|
|
96
|
+
return value;
|
|
97
|
+
const metadata = (() => {
|
|
98
|
+
try {
|
|
99
|
+
return JSON.parse(contract);
|
|
100
|
+
}
|
|
101
|
+
catch (error) {
|
|
102
|
+
Graph.compile({ modules: {}, contracts: { [id]: contract } });
|
|
103
|
+
throw error;
|
|
104
|
+
}
|
|
105
|
+
})();
|
|
106
|
+
value = Array.isArray(metadata?.stylesheets)
|
|
107
|
+
? metadata.stylesheets
|
|
108
|
+
.map((section) => section?.dependency)
|
|
109
|
+
.filter((dependency) => Array.isArray(dependency))
|
|
110
|
+
: [];
|
|
111
|
+
// Rebuilt libraries leave their earlier texts behind, so the cache stays bounded.
|
|
112
|
+
if (dependencyChains.size > 256)
|
|
113
|
+
dependencyChains.clear();
|
|
114
|
+
dependencyChains.set(contract, value);
|
|
115
|
+
return value;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Each module's import edges in an environment, shared by every entry compile that walks the
|
|
119
|
+
* module. Added and removed files and dependency optimization change resolutions, so either
|
|
120
|
+
* starts over.
|
|
121
|
+
*/
|
|
122
|
+
function importEdges(environment) {
|
|
123
|
+
const metadata = environment.mode === 'dev'
|
|
124
|
+
? environment.depsOptimizer?.metadata
|
|
125
|
+
: undefined;
|
|
126
|
+
const key = `${metadata?.browserHash}:${Object.keys(metadata?.discovered ?? {}).length}`;
|
|
127
|
+
let value = edgeMemos.get(environment);
|
|
128
|
+
if (value?.key !== key) {
|
|
129
|
+
value = { files: new Map(), key };
|
|
130
|
+
edgeMemos.set(environment, value);
|
|
131
|
+
}
|
|
132
|
+
return value.files;
|
|
133
|
+
}
|
|
134
|
+
/** Adds a compile input to the development watcher once. */
|
|
135
|
+
function watch(server, file) {
|
|
136
|
+
if (watched.has(file))
|
|
137
|
+
return;
|
|
138
|
+
watched.add(file);
|
|
139
|
+
server.watcher.add(file);
|
|
140
|
+
}
|
|
141
|
+
function read(contract) {
|
|
142
|
+
let value = catalogReads.get(contract);
|
|
143
|
+
if (!value) {
|
|
144
|
+
if (catalogReads.size > 256)
|
|
145
|
+
catalogReads.clear();
|
|
146
|
+
value = Catalogs.read(contract);
|
|
147
|
+
catalogReads.set(contract, value);
|
|
148
|
+
}
|
|
149
|
+
return value;
|
|
150
|
+
}
|
|
151
|
+
function project(environment) {
|
|
152
|
+
let value = projects.get(environment);
|
|
153
|
+
if (!value) {
|
|
154
|
+
value = {
|
|
155
|
+
compiler: Graph.create(),
|
|
156
|
+
contracts: Object.create(null),
|
|
157
|
+
fallback: Graph.create(),
|
|
158
|
+
imports: Object.create(null),
|
|
159
|
+
modules: Object.create(null),
|
|
160
|
+
outcome: undefined,
|
|
161
|
+
};
|
|
162
|
+
projects.set(environment, value);
|
|
163
|
+
}
|
|
164
|
+
return value;
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Development merges every module a transform reaches into one graph per environment, so
|
|
168
|
+
* modules compile once per change instead of once per importer. A module's output depends only
|
|
169
|
+
* on its own import closure, so the merged graph returns the output a closure compile would.
|
|
170
|
+
* While some other module fails, the requested closure compiles alone and reports only its own
|
|
171
|
+
* errors, as before.
|
|
172
|
+
*/
|
|
173
|
+
function compileProject(environment, input, id) {
|
|
174
|
+
const value = project(environment);
|
|
175
|
+
let changed = value.outcome === undefined;
|
|
176
|
+
for (const [module, source] of Object.entries(input.modules))
|
|
177
|
+
if (value.modules[module] !== source) {
|
|
178
|
+
value.modules[module] = source;
|
|
179
|
+
changed = true;
|
|
180
|
+
}
|
|
181
|
+
for (const [module, resolutions] of Object.entries(input.imports ?? {}))
|
|
182
|
+
if (!same(value.imports[module], resolutions)) {
|
|
183
|
+
value.imports[module] = resolutions;
|
|
184
|
+
changed = true;
|
|
185
|
+
}
|
|
186
|
+
for (const [module, contract] of Object.entries(input.contracts ?? {}))
|
|
187
|
+
if (value.contracts[module] !== contract) {
|
|
188
|
+
value.contracts[module] = contract;
|
|
189
|
+
changed = true;
|
|
190
|
+
}
|
|
191
|
+
if (changed)
|
|
192
|
+
value.outcome = (() => {
|
|
193
|
+
try {
|
|
194
|
+
return {
|
|
195
|
+
result: value.compiler.compile({
|
|
196
|
+
...input,
|
|
197
|
+
contracts: value.contracts,
|
|
198
|
+
imports: value.imports,
|
|
199
|
+
modules: value.modules,
|
|
200
|
+
}),
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
catch (error) {
|
|
204
|
+
return { error };
|
|
205
|
+
}
|
|
206
|
+
})();
|
|
207
|
+
const outcome = value.outcome;
|
|
208
|
+
if ('result' in outcome && Object.hasOwn(outcome.result.modules, id))
|
|
209
|
+
return outcome.result;
|
|
210
|
+
return value.fallback.compile(input);
|
|
211
|
+
}
|
|
58
212
|
const discoveries = new WeakMap();
|
|
59
213
|
const contributionFiles = new WeakMap();
|
|
60
214
|
const assets = new Map();
|
|
@@ -65,6 +219,8 @@ export function zyzz(options = {}) {
|
|
|
65
219
|
const sourceEntrypoints = new Set();
|
|
66
220
|
const identities = new Map();
|
|
67
221
|
const exclusions = new Map();
|
|
222
|
+
// Every compile checks each import against the source directories.
|
|
223
|
+
const roots = new Map();
|
|
68
224
|
const lazyImports = new WeakMap();
|
|
69
225
|
let directories;
|
|
70
226
|
let filter;
|
|
@@ -146,13 +302,17 @@ export function zyzz(options = {}) {
|
|
|
146
302
|
return value;
|
|
147
303
|
}
|
|
148
304
|
function sourceRoot(file) {
|
|
149
|
-
|
|
305
|
+
if (roots.has(file))
|
|
306
|
+
return roots.get(file);
|
|
307
|
+
const root = directories.find((directory) => {
|
|
150
308
|
const relative = Path.relative(directory, file);
|
|
151
309
|
return (relative !== '..' &&
|
|
152
310
|
!relative.startsWith(`..${Path.sep}`) &&
|
|
153
311
|
!Path.isAbsolute(relative) &&
|
|
154
312
|
!relative.split(Path.sep).includes('node_modules'));
|
|
155
313
|
});
|
|
314
|
+
roots.set(file, root);
|
|
315
|
+
return root;
|
|
156
316
|
}
|
|
157
317
|
function discover(environment, host) {
|
|
158
318
|
let pending = discoveries.get(environment);
|
|
@@ -293,7 +453,37 @@ export function zyzz(options = {}) {
|
|
|
293
453
|
}
|
|
294
454
|
async function updateDiscovery(environment, file, event) {
|
|
295
455
|
reads.delete(environment);
|
|
296
|
-
|
|
456
|
+
generations.set(environment, (generations.get(environment) ?? 0) + 1);
|
|
457
|
+
const changed = entries(environment).get(file);
|
|
458
|
+
if (changed)
|
|
459
|
+
changed.source = undefined;
|
|
460
|
+
// An edit keeps every resolution. Adding or removing a file can change where a
|
|
461
|
+
// specifier resolves, and a contract derives again only when a file it read changes.
|
|
462
|
+
// Editors save through temporary files, which no specifier resolves to.
|
|
463
|
+
const resolvable = event !== 'update' &&
|
|
464
|
+
/\.(?:[cm]?[jt]sx?|json|css|svelte|vue)$|(?:^|[/\\])package\.json$/.test(file);
|
|
465
|
+
const cache = lookups.get(environment);
|
|
466
|
+
// Import edges derive from resolutions and module text, which each memo compares.
|
|
467
|
+
if (resolvable)
|
|
468
|
+
edgeMemos.delete(environment);
|
|
469
|
+
if (cache) {
|
|
470
|
+
if (resolvable)
|
|
471
|
+
cache.resolutions.clear();
|
|
472
|
+
for (const [key, files] of cache.read)
|
|
473
|
+
if (files.has(file)) {
|
|
474
|
+
cache.contracts.delete(key);
|
|
475
|
+
cache.read.delete(key);
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
if (event === 'delete') {
|
|
479
|
+
const value = projects.get(environment);
|
|
480
|
+
const id = sourceId(file);
|
|
481
|
+
if (value && Object.hasOwn(value.modules, id)) {
|
|
482
|
+
delete value.modules[id];
|
|
483
|
+
delete value.imports[id];
|
|
484
|
+
value.outcome = undefined;
|
|
485
|
+
}
|
|
486
|
+
}
|
|
297
487
|
if (event === 'delete') {
|
|
298
488
|
if (entries(environment).has(file)) {
|
|
299
489
|
let files = removed.get(environment);
|
|
@@ -323,10 +513,52 @@ export function zyzz(options = {}) {
|
|
|
323
513
|
}
|
|
324
514
|
}
|
|
325
515
|
async function compile(entry, host, code, allSources = false, everything = false) {
|
|
326
|
-
|
|
327
|
-
|
|
516
|
+
const generation = generations.get(entry.environment) ?? 0;
|
|
517
|
+
const memo = outputs.get(entry);
|
|
518
|
+
const current = projects.get(entry.environment)?.outcome;
|
|
519
|
+
// Without a watcher event the closure is unchanged, so a stylesheet load after its
|
|
520
|
+
// transform reuses the output while the merged graph has not recompiled.
|
|
521
|
+
if (memo &&
|
|
522
|
+
!everything &&
|
|
523
|
+
memo.allSources === allSources &&
|
|
524
|
+
memo.generation === generation &&
|
|
525
|
+
(code === undefined || code === memo.code) &&
|
|
526
|
+
current &&
|
|
527
|
+
'result' in current &&
|
|
528
|
+
current.result === memo.result) {
|
|
529
|
+
for (const file of entry.files)
|
|
530
|
+
host.watch(file);
|
|
531
|
+
return memo.output;
|
|
532
|
+
}
|
|
533
|
+
const output = await compileEntry(entry, host, code, allSources, everything);
|
|
534
|
+
const outcome = projects.get(entry.environment)?.outcome;
|
|
535
|
+
// A concurrent compile can replace the merged result while this one renders, so only an
|
|
536
|
+
// output of the current result is kept.
|
|
537
|
+
if (entry.environment.mode === 'dev' &&
|
|
538
|
+
!everything &&
|
|
539
|
+
outcome &&
|
|
540
|
+
'result' in outcome &&
|
|
541
|
+
outcome.result.modules === output.modules &&
|
|
542
|
+
generation === (generations.get(entry.environment) ?? 0))
|
|
543
|
+
outputs.set(entry, {
|
|
544
|
+
allSources,
|
|
545
|
+
code,
|
|
546
|
+
generation,
|
|
547
|
+
output,
|
|
548
|
+
result: outcome.result,
|
|
549
|
+
});
|
|
550
|
+
return output;
|
|
551
|
+
}
|
|
552
|
+
async function compileEntry(entry, host, code, allSources = false, everything = false) {
|
|
553
|
+
// Every compile visits the discovered project, so modules share lookups. Watcher events
|
|
554
|
+
// drop the resolutions and contracts a change can affect. Full-project compiles look up
|
|
555
|
+
// afresh, since a document must not trail the watcher.
|
|
328
556
|
const cache = (() => {
|
|
329
|
-
const fresh = {
|
|
557
|
+
const fresh = {
|
|
558
|
+
contracts: new Map(),
|
|
559
|
+
read: new Map(),
|
|
560
|
+
resolutions: new Map(),
|
|
561
|
+
};
|
|
330
562
|
if (everything)
|
|
331
563
|
return fresh;
|
|
332
564
|
let value = lookups.get(entry.environment);
|
|
@@ -336,6 +568,8 @@ export function zyzz(options = {}) {
|
|
|
336
568
|
}
|
|
337
569
|
return value;
|
|
338
570
|
})();
|
|
571
|
+
// Full-project compiles walk afresh, as they look up afresh.
|
|
572
|
+
const memos = everything ? undefined : importEdges(entry.environment);
|
|
339
573
|
async function resolve(source, importer) {
|
|
340
574
|
if (isBuiltin(source))
|
|
341
575
|
return { id: source, external: true };
|
|
@@ -350,15 +584,33 @@ export function zyzz(options = {}) {
|
|
|
350
584
|
if (!resolved)
|
|
351
585
|
return resolved;
|
|
352
586
|
if (entry.environment.mode === 'dev') {
|
|
353
|
-
const
|
|
354
|
-
|
|
355
|
-
...
|
|
356
|
-
}).find((item) => item.file === resolved.id.split('?')[0]);
|
|
357
|
-
if (optimized?.src)
|
|
358
|
-
return { ...resolved, id: optimized.src };
|
|
587
|
+
const source = optimized().get(resolved.id.split('?')[0]);
|
|
588
|
+
if (source)
|
|
589
|
+
return { ...resolved, id: source };
|
|
359
590
|
}
|
|
360
591
|
return { ...resolved, id: normalize(resolved.id) };
|
|
361
592
|
}
|
|
593
|
+
// Optimized dependency sources by bundled file, indexed once per compile rather than
|
|
594
|
+
// searched for every resolution.
|
|
595
|
+
let indexed;
|
|
596
|
+
function optimized() {
|
|
597
|
+
if (indexed)
|
|
598
|
+
return indexed;
|
|
599
|
+
indexed = new Map();
|
|
600
|
+
const environment = entry.environment;
|
|
601
|
+
const metadata = environment.mode === 'dev'
|
|
602
|
+
? environment.depsOptimizer?.metadata
|
|
603
|
+
: undefined;
|
|
604
|
+
// Discovered entries replace optimized ones of the same name, and the first entry
|
|
605
|
+
// bundling a file wins, as a search of the merged record finds it.
|
|
606
|
+
for (const item of Object.values({
|
|
607
|
+
...metadata?.optimized,
|
|
608
|
+
...metadata?.discovered,
|
|
609
|
+
}))
|
|
610
|
+
if (!indexed.has(item.file))
|
|
611
|
+
indexed.set(item.file, item.src ?? '');
|
|
612
|
+
return indexed;
|
|
613
|
+
}
|
|
362
614
|
const imports = Object.create(null);
|
|
363
615
|
const contracts = Object.create(null);
|
|
364
616
|
const lazy = Object.create(null);
|
|
@@ -381,7 +633,10 @@ export function zyzz(options = {}) {
|
|
|
381
633
|
required,
|
|
382
634
|
resolve: async (specifier, importer) => (await resolve(specifier, importer))?.id.split(/[?#]/)[0],
|
|
383
635
|
})
|
|
384
|
-
.then((contract) =>
|
|
636
|
+
.then((contract) => {
|
|
637
|
+
cache.read.set(key, read);
|
|
638
|
+
return { contract, files: read };
|
|
639
|
+
});
|
|
385
640
|
cache.contracts.set(key, pending);
|
|
386
641
|
pending.catch(() => cache.contracts.delete(key));
|
|
387
642
|
}
|
|
@@ -405,14 +660,37 @@ export function zyzz(options = {}) {
|
|
|
405
660
|
cached = new Map();
|
|
406
661
|
reads.set(entry.environment, cached);
|
|
407
662
|
}
|
|
663
|
+
// Earlier plugins can rewrite a module before this one sees it, as router plugins drop
|
|
664
|
+
// server routes from client route trees. Its importers read the code Vite transformed, so
|
|
665
|
+
// every graph in the environment holds one version of each module.
|
|
408
666
|
// Full-project compilation must not reuse reads from concurrent module transforms.
|
|
409
667
|
const text = source ??
|
|
668
|
+
(everything
|
|
669
|
+
? undefined
|
|
670
|
+
: entries(entry.environment).get(file)?.source) ??
|
|
410
671
|
(everything ? undefined : cached.get(file)) ??
|
|
411
672
|
(await snapshot(entry.environment).read(file));
|
|
412
673
|
if (!everything)
|
|
413
674
|
cached.set(file, text);
|
|
414
675
|
modules[id] = text;
|
|
676
|
+
const memo = memos?.get(file);
|
|
677
|
+
// Replaying the edges keeps the order in which modules and contracts join the compile.
|
|
678
|
+
if (memo?.text === text) {
|
|
679
|
+
imports[id] = { ...memo.resolutions };
|
|
680
|
+
for (const step of memo.steps) {
|
|
681
|
+
if (typeof step === 'string') {
|
|
682
|
+
await visit(step);
|
|
683
|
+
continue;
|
|
684
|
+
}
|
|
685
|
+
const contract = await readContract(step.physical);
|
|
686
|
+
if (contract !== undefined)
|
|
687
|
+
contracts[step.id] = contract;
|
|
688
|
+
}
|
|
689
|
+
lazy[id] = memo.lazy;
|
|
690
|
+
return;
|
|
691
|
+
}
|
|
415
692
|
const resolutions = Object.create(null);
|
|
693
|
+
const steps = [];
|
|
416
694
|
imports[id] = resolutions;
|
|
417
695
|
const parsed = snapshot(entry.environment).parse({
|
|
418
696
|
moduleId: id,
|
|
@@ -461,6 +739,7 @@ export function zyzz(options = {}) {
|
|
|
461
739
|
/[/\\]src[/\\]default\.[cm]?ts$/.test(resolved.id)) {
|
|
462
740
|
sourceEntrypoints.add(normalize(resolved.id));
|
|
463
741
|
resolutions[specifier] = sourceId(resolved.id);
|
|
742
|
+
steps.push(resolved.id);
|
|
464
743
|
await visit(resolved.id);
|
|
465
744
|
continue;
|
|
466
745
|
}
|
|
@@ -471,9 +750,10 @@ export function zyzz(options = {}) {
|
|
|
471
750
|
}
|
|
472
751
|
if (resolved.external || !eligible(resolved.id)) {
|
|
473
752
|
const physical = resolved.id.split('?')[0].split('#')[0];
|
|
474
|
-
const
|
|
475
|
-
|
|
476
|
-
:
|
|
753
|
+
const readable = Path.isAbsolute(physical) && /\.[cm]?[jt]sx?$/.test(physical);
|
|
754
|
+
if (readable)
|
|
755
|
+
steps.push({ id: resolved.id, physical });
|
|
756
|
+
const contract = readable ? await readContract(physical) : undefined;
|
|
477
757
|
if (contract !== undefined) {
|
|
478
758
|
contracts[resolved.id] = contract;
|
|
479
759
|
resolutions[specifier] = resolved.id;
|
|
@@ -483,6 +763,7 @@ export function zyzz(options = {}) {
|
|
|
483
763
|
continue;
|
|
484
764
|
}
|
|
485
765
|
resolutions[specifier] = sourceId(resolved.id);
|
|
766
|
+
steps.push(resolved.id);
|
|
486
767
|
await visit(resolved.id);
|
|
487
768
|
}
|
|
488
769
|
// Lazy imports stay outside this compile but scope the documents that load them.
|
|
@@ -510,6 +791,7 @@ export function zyzz(options = {}) {
|
|
|
510
791
|
targets.add(eligible(resolved.id) ? sourceId(resolved.id) : resolved.id);
|
|
511
792
|
}
|
|
512
793
|
lazy[id] = targets;
|
|
794
|
+
memos?.set(file, { lazy: targets, resolutions, steps, text });
|
|
513
795
|
}
|
|
514
796
|
await visit(entry.file, code);
|
|
515
797
|
const connected = new Set(files);
|
|
@@ -593,22 +875,9 @@ export function zyzz(options = {}) {
|
|
|
593
875
|
if (loaded.has(id))
|
|
594
876
|
return;
|
|
595
877
|
loaded.add(id);
|
|
596
|
-
const
|
|
597
|
-
try {
|
|
598
|
-
return JSON.parse(contracts[id]);
|
|
599
|
-
}
|
|
600
|
-
catch (error) {
|
|
601
|
-
Graph.compile({ modules: {}, contracts: { [id]: contracts[id] } });
|
|
602
|
-
throw error;
|
|
603
|
-
}
|
|
604
|
-
})();
|
|
605
|
-
if (!Array.isArray(metadata?.stylesheets))
|
|
606
|
-
return;
|
|
607
|
-
for (const section of metadata.stylesheets) {
|
|
608
|
-
if (!Array.isArray(section?.dependency))
|
|
609
|
-
continue;
|
|
878
|
+
for (const dependency of stylesheetDependencies(id, contracts[id])) {
|
|
610
879
|
let owner = id;
|
|
611
|
-
for (const specifier of
|
|
880
|
+
for (const specifier of dependency) {
|
|
612
881
|
if (typeof specifier !== 'string' ||
|
|
613
882
|
!specifier ||
|
|
614
883
|
specifier.includes('\0'))
|
|
@@ -639,9 +908,9 @@ export function zyzz(options = {}) {
|
|
|
639
908
|
...Object.values(resolutions).filter((target) => target !== null),
|
|
640
909
|
...(lazy[id] ?? []),
|
|
641
910
|
]));
|
|
642
|
-
const
|
|
911
|
+
const input = {
|
|
912
|
+
[Results.lean]: true,
|
|
643
913
|
[ThemeRules.shared]: native ? undefined : 'all',
|
|
644
|
-
[Syntax.cache]: snapshot(entry.environment).programs(modules),
|
|
645
914
|
compiler: options.compiler,
|
|
646
915
|
reset: options.reset ? Reset.read() : undefined,
|
|
647
916
|
native,
|
|
@@ -649,7 +918,10 @@ export function zyzz(options = {}) {
|
|
|
649
918
|
development: entry.environment.mode !== 'build',
|
|
650
919
|
imports,
|
|
651
920
|
modules,
|
|
652
|
-
}
|
|
921
|
+
};
|
|
922
|
+
const result = entry.environment.mode === 'dev' && !native && !everything
|
|
923
|
+
? compileProject(entry.environment, input, sourceId(entry.file))
|
|
924
|
+
: entry.compiler.compile(input);
|
|
653
925
|
if (native) {
|
|
654
926
|
const output = result.modules[sourceId(entry.file)];
|
|
655
927
|
entry.files = files;
|
|
@@ -662,6 +934,7 @@ export function zyzz(options = {}) {
|
|
|
662
934
|
configurations: new Map(),
|
|
663
935
|
connections: staged,
|
|
664
936
|
css: '',
|
|
937
|
+
graphSharedCss: '',
|
|
665
938
|
sharedCss: '',
|
|
666
939
|
cssMap: map,
|
|
667
940
|
sharedCssMap: map,
|
|
@@ -689,132 +962,143 @@ export function zyzz(options = {}) {
|
|
|
689
962
|
catalogs.delete(key);
|
|
690
963
|
const configurations = new Map();
|
|
691
964
|
for (const [id, contract] of Object.entries(compiled))
|
|
692
|
-
for (const configuration of
|
|
965
|
+
for (const configuration of read(contract)) {
|
|
693
966
|
const key = `${id}\0${configuration.identity}`;
|
|
694
967
|
catalogs.set(key, configuration);
|
|
695
968
|
configurations.set(key, configuration);
|
|
696
969
|
}
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
970
|
+
// Development renders the shared stylesheet for its own request only; transforms and module
|
|
971
|
+
// stylesheets read module outputs.
|
|
972
|
+
async function renderShared() {
|
|
973
|
+
const owners = new Map();
|
|
974
|
+
for (const id of new Set(Object.values(result.sharedAssetOwners ?? {}))) {
|
|
975
|
+
if (!Path.isAbsolute(id))
|
|
976
|
+
continue;
|
|
977
|
+
let directory = Path.dirname(id.split(/[?#]/)[0]);
|
|
978
|
+
for (;;) {
|
|
979
|
+
try {
|
|
980
|
+
await Fs.access(Path.join(directory, 'package.json'));
|
|
981
|
+
owners.set(id, await Fs.realpath(directory));
|
|
982
|
+
break;
|
|
983
|
+
}
|
|
984
|
+
catch (error) {
|
|
985
|
+
if (error.code !== 'ENOENT')
|
|
986
|
+
throw error;
|
|
987
|
+
}
|
|
988
|
+
const parent = Path.dirname(directory);
|
|
989
|
+
if (parent === directory)
|
|
990
|
+
throw new Error('Packed assets require an owning package.json.');
|
|
991
|
+
directory = parent;
|
|
711
992
|
}
|
|
712
|
-
const parent = Path.dirname(directory);
|
|
713
|
-
if (parent === directory)
|
|
714
|
-
throw new Error('Packed assets require an owning package.json.');
|
|
715
|
-
directory = parent;
|
|
716
993
|
}
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
.
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
}
|
|
748
|
-
}
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
994
|
+
const assetUrls = new Map();
|
|
995
|
+
for (const [key, target] of Object.entries(result.sharedAssets ?? {})) {
|
|
996
|
+
const raw = target.split(/[?#]/)[0];
|
|
997
|
+
const identity = result.sharedAssetOwners?.[key];
|
|
998
|
+
const path = sourceFile(decodeURIComponent(raw)) ??
|
|
999
|
+
(Path.isAbsolute(raw) ? decodeURIComponent(raw) : undefined);
|
|
1000
|
+
if (!path)
|
|
1001
|
+
throw new Error('Asset path escapes the Vite graph.');
|
|
1002
|
+
const asset = await (async () => {
|
|
1003
|
+
try {
|
|
1004
|
+
return { file: await Fs.realpath(path), package: false };
|
|
1005
|
+
}
|
|
1006
|
+
catch (error) {
|
|
1007
|
+
if (error.code !== 'ENOENT' ||
|
|
1008
|
+
!identity ||
|
|
1009
|
+
!sourceFile(identity))
|
|
1010
|
+
throw error;
|
|
1011
|
+
const importer = sourceFile(identity);
|
|
1012
|
+
const specifier = Path.relative(Path.dirname(importer), path)
|
|
1013
|
+
.split(Path.sep)
|
|
1014
|
+
.join('/');
|
|
1015
|
+
if (specifier.startsWith('.') || Path.isAbsolute(specifier))
|
|
1016
|
+
throw error;
|
|
1017
|
+
const resolved = await host.resolve(specifier, importer);
|
|
1018
|
+
if (!resolved || resolved.external)
|
|
1019
|
+
throw error;
|
|
1020
|
+
return {
|
|
1021
|
+
file: await Fs.realpath(resolved.id.split('?')[0]),
|
|
1022
|
+
package: true,
|
|
1023
|
+
};
|
|
1024
|
+
}
|
|
1025
|
+
})();
|
|
1026
|
+
const file = asset.file;
|
|
1027
|
+
const owner = identity && sourceFile(identity)
|
|
1028
|
+
? sourceRoot(sourceFile(identity))
|
|
1029
|
+
: identity
|
|
1030
|
+
? owners.get(identity)
|
|
1031
|
+
: undefined;
|
|
1032
|
+
const relative = owner ? Path.relative(owner, file) : '..';
|
|
1033
|
+
if (!asset.package &&
|
|
1034
|
+
(relative === '..' ||
|
|
1035
|
+
relative.startsWith(`..${Path.sep}`) ||
|
|
1036
|
+
Path.isAbsolute(relative)))
|
|
1037
|
+
throw new Error('Asset path escapes its owning package.');
|
|
1038
|
+
host.watch(file);
|
|
1039
|
+
files.add(file);
|
|
1040
|
+
let url;
|
|
1041
|
+
if (asset.package || /[?#%]/.test(file)) {
|
|
1042
|
+
if (entry.environment.mode === 'build') {
|
|
1043
|
+
url = await host.asset(file);
|
|
1044
|
+
if (target.slice(raw.length))
|
|
1045
|
+
url += `$_${target.slice(raw.length)}__`;
|
|
1046
|
+
}
|
|
1047
|
+
else {
|
|
1048
|
+
url = `/@zyzz/asset/${Crypto.hash('sha256', file)}/${encodeURIComponent(Path.basename(file))}`;
|
|
1049
|
+
assets.set(url, file);
|
|
1050
|
+
url += target.slice(raw.length);
|
|
1051
|
+
}
|
|
770
1052
|
}
|
|
771
1053
|
else {
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
1054
|
+
// Vite reads `/@fs/` URLs with `decodeURI`, which keeps reserved escapes
|
|
1055
|
+
// such as `%40` in scoped package paths, so those characters stay raw.
|
|
1056
|
+
const pathname = encodeURI(file.replaceAll('\\', '/'));
|
|
1057
|
+
url = `/@fs/${pathname}${target.slice(raw.length)}`;
|
|
775
1058
|
}
|
|
1059
|
+
assetUrls.set(target, url);
|
|
776
1060
|
}
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
return AtRules.relocateImport(rule.value, assetUrls.get(target));
|
|
804
|
-
},
|
|
805
|
-
Url(url) {
|
|
806
|
-
const target = result.sharedAssets?.[url.url];
|
|
807
|
-
if (!target)
|
|
808
|
-
return;
|
|
809
|
-
return { ...url, url: assetUrls.get(target) };
|
|
1061
|
+
const shared = !Object.keys(result.sharedAssets ?? {}).length
|
|
1062
|
+
? {
|
|
1063
|
+
code: new TextEncoder().encode(result.sharedCss ?? ''),
|
|
1064
|
+
map: new TextEncoder().encode(JSON.stringify(result.sharedCssMap ??
|
|
1065
|
+
Mapping.toEncodedMap(new Mapping.GenMapping()))),
|
|
1066
|
+
}
|
|
1067
|
+
: AtRules.transform({
|
|
1068
|
+
filename: 'zyzz.shared.css',
|
|
1069
|
+
code: new TextEncoder().encode(result.sharedCss ?? ''),
|
|
1070
|
+
sourceMap: true,
|
|
1071
|
+
inputSourceMap: JSON.stringify(result.sharedCssMap ??
|
|
1072
|
+
Mapping.toEncodedMap(new Mapping.GenMapping())),
|
|
1073
|
+
visitor: {
|
|
1074
|
+
Rule(rule) {
|
|
1075
|
+
if (rule.type !== 'import')
|
|
1076
|
+
return;
|
|
1077
|
+
const target = result.sharedAssets?.[rule.value.url];
|
|
1078
|
+
if (target)
|
|
1079
|
+
return AtRules.relocateImport(rule.value, assetUrls.get(target));
|
|
1080
|
+
},
|
|
1081
|
+
Url(url) {
|
|
1082
|
+
const target = result.sharedAssets?.[url.url];
|
|
1083
|
+
if (!target)
|
|
1084
|
+
return;
|
|
1085
|
+
return { ...url, url: assetUrls.get(target) };
|
|
1086
|
+
},
|
|
810
1087
|
},
|
|
811
|
-
}
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
1088
|
+
});
|
|
1089
|
+
const sharedMap = JSON.parse(new TextDecoder().decode(shared.map));
|
|
1090
|
+
sharedMap.sources = sharedMap.sources.map((source) => source === null ? null : (sourceFile(source) ?? source));
|
|
1091
|
+
return { css: new TextDecoder().decode(shared.code), map: sharedMap };
|
|
1092
|
+
}
|
|
1093
|
+
const sharedOutput = entry.environment.mode !== 'dev' || allSources
|
|
1094
|
+
? await renderShared()
|
|
1095
|
+
: {
|
|
1096
|
+
css: '',
|
|
1097
|
+
map: Mapping.toEncodedMap(new Mapping.GenMapping()),
|
|
1098
|
+
};
|
|
815
1099
|
const output = result.modules[sourceId(entry.file)];
|
|
816
1100
|
entry.files = files;
|
|
817
|
-
|
|
1101
|
+
const value = {
|
|
818
1102
|
imports,
|
|
819
1103
|
modules: result.modules,
|
|
820
1104
|
code: output.code,
|
|
@@ -822,8 +1106,10 @@ export function zyzz(options = {}) {
|
|
|
822
1106
|
configurations,
|
|
823
1107
|
connections: staged,
|
|
824
1108
|
css: output.css,
|
|
825
|
-
|
|
826
|
-
|
|
1109
|
+
// Edits compare the graph's stylesheet, which precedes asset relocation.
|
|
1110
|
+
graphSharedCss: result.sharedCss ?? '',
|
|
1111
|
+
sharedCss: sharedOutput.css,
|
|
1112
|
+
sharedCssMap: sharedOutput.map,
|
|
827
1113
|
cssMap: {
|
|
828
1114
|
...output.cssMap,
|
|
829
1115
|
sources: output.cssMap.sources.map((source) => source === null ? null : (sourceFile(source) ?? source)),
|
|
@@ -833,16 +1119,16 @@ export function zyzz(options = {}) {
|
|
|
833
1119
|
sources: output.map.sources.map((source) => source === null ? null : (sourceFile(source) ?? source)),
|
|
834
1120
|
},
|
|
835
1121
|
};
|
|
1122
|
+
return value;
|
|
836
1123
|
}
|
|
837
1124
|
/** Compiles every discovered source once so index.html can inline each configuration's script before modules load. */
|
|
838
1125
|
async function initializations(server) {
|
|
839
1126
|
const environment = server.environments.client;
|
|
840
1127
|
reads.delete(environment);
|
|
841
|
-
lookups.delete(environment);
|
|
842
1128
|
const host = {
|
|
843
1129
|
asset: async (file) => file,
|
|
844
1130
|
resolve: resolver(environment),
|
|
845
|
-
watch: (file) => server
|
|
1131
|
+
watch: (file) => watch(server, file),
|
|
846
1132
|
};
|
|
847
1133
|
const sources = await discover(environment, host);
|
|
848
1134
|
let entry = initializers.get(environment);
|
|
@@ -851,8 +1137,9 @@ export function zyzz(options = {}) {
|
|
|
851
1137
|
const file = sources.keys().next().value;
|
|
852
1138
|
if (file === undefined)
|
|
853
1139
|
return { catalogs: new Map(), edges: new Map() };
|
|
1140
|
+
// Whole-project compiles keep their own cache beside the transforms' merged graph.
|
|
854
1141
|
entry = {
|
|
855
|
-
compiler:
|
|
1142
|
+
compiler: initializers.get(environment)?.compiler ?? Graph.create(),
|
|
856
1143
|
environment,
|
|
857
1144
|
file,
|
|
858
1145
|
files: new Set([file]),
|
|
@@ -976,8 +1263,105 @@ export function zyzz(options = {}) {
|
|
|
976
1263
|
.filter(([key]) => contracts.has(key.split('\0')[0]))
|
|
977
1264
|
.map(([, configuration]) => configuration);
|
|
978
1265
|
}
|
|
1266
|
+
/**
|
|
1267
|
+
* The modules an edit invalidates: those whose code or stylesheet differs from what Vite served.
|
|
1268
|
+
* A concurrent compile can already hold the edit, so outputs are not compared with each other.
|
|
1269
|
+
*/
|
|
1270
|
+
async function changes(environment, after, served, modules, timestamp, edited, deleted) {
|
|
1271
|
+
// Portable build adapters share this module and do not require Vite.
|
|
1272
|
+
const { transformWithOxc } = await import('vite');
|
|
1273
|
+
const code = new Set();
|
|
1274
|
+
const css = new Set();
|
|
1275
|
+
for (const [entry, { code: current, css: stylesheet, imports },] of served.entries) {
|
|
1276
|
+
const id = sourceId(entry.file);
|
|
1277
|
+
const next = after.modules[id];
|
|
1278
|
+
if (!next)
|
|
1279
|
+
continue;
|
|
1280
|
+
// A stylesheet Vite never loaded has no module to invalidate.
|
|
1281
|
+
if (stylesheet !== undefined && stylesheet !== next.css)
|
|
1282
|
+
css.add(entry.file);
|
|
1283
|
+
// A stylesheet request can compile a module whose code was never transformed here.
|
|
1284
|
+
if (current === undefined)
|
|
1285
|
+
continue;
|
|
1286
|
+
if (imports !== JSON.stringify(projects.get(environment)?.imports[id])) {
|
|
1287
|
+
code.add(entry.file);
|
|
1288
|
+
continue;
|
|
1289
|
+
}
|
|
1290
|
+
if (current === next.code)
|
|
1291
|
+
continue;
|
|
1292
|
+
// Generated type assertions can change without changing runtime bindings.
|
|
1293
|
+
const [left, right] = await Promise.all([
|
|
1294
|
+
transformWithOxc(current, entry.file, { sourcemap: false }),
|
|
1295
|
+
transformWithOxc(next.code, entry.file, { sourcemap: false }),
|
|
1296
|
+
]);
|
|
1297
|
+
if (left.code !== right.code)
|
|
1298
|
+
code.add(entry.file);
|
|
1299
|
+
}
|
|
1300
|
+
const stylesheets = new Set();
|
|
1301
|
+
if (deleted !== undefined)
|
|
1302
|
+
stylesheets.add(cssId(deleted));
|
|
1303
|
+
if (served.shared !== undefined &&
|
|
1304
|
+
served.shared !== (after.sharedCss ?? ''))
|
|
1305
|
+
stylesheets.add(sharedId);
|
|
1306
|
+
for (const file of css)
|
|
1307
|
+
stylesheets.add(cssId(file));
|
|
1308
|
+
// Compiled modules the edit left unchanged skip Vite's own update; other modules, such as
|
|
1309
|
+
// plain JavaScript or assets, keep it.
|
|
1310
|
+
const affected = new Set(modules.filter((module) => {
|
|
1311
|
+
if (!module.id)
|
|
1312
|
+
return module.type !== 'asset';
|
|
1313
|
+
const file = normalize(module.id);
|
|
1314
|
+
return Object.hasOwn(after.modules, sourceId(file))
|
|
1315
|
+
? code.has(file)
|
|
1316
|
+
: true;
|
|
1317
|
+
}));
|
|
1318
|
+
for (const file of code) {
|
|
1319
|
+
const module = environment.moduleGraph.getModuleById(file);
|
|
1320
|
+
if (!module)
|
|
1321
|
+
continue;
|
|
1322
|
+
environment.moduleGraph.invalidateModule(module, new Set(), timestamp, true);
|
|
1323
|
+
affected.add(module);
|
|
1324
|
+
}
|
|
1325
|
+
const sheets = [];
|
|
1326
|
+
// The edited module's stylesheet updates first, ahead of stylesheets other modules share.
|
|
1327
|
+
for (const id of [...stylesheets].sort((left, right) => Number(right === cssId(edited)) - Number(left === cssId(edited)))) {
|
|
1328
|
+
const module = environment.moduleGraph.getModuleById(id);
|
|
1329
|
+
if (!module)
|
|
1330
|
+
continue;
|
|
1331
|
+
environment.moduleGraph.invalidateModule(module, new Set(), timestamp, true);
|
|
1332
|
+
sheets.push(module);
|
|
1333
|
+
}
|
|
1334
|
+
// A stylesheet accepts its own updates and only its module imports it, so it is never within
|
|
1335
|
+
// an import cycle. Vite proves that by walking every importer of the importing module, which
|
|
1336
|
+
// costs each stylesheet of a shared edit the whole graph, so stylesheet-only edits send the
|
|
1337
|
+
// same update directly. Edits that also change code keep Vite's single batched update.
|
|
1338
|
+
if (!affected.size &&
|
|
1339
|
+
sheets.length &&
|
|
1340
|
+
sheets.every((module) => module.isSelfAccepting)) {
|
|
1341
|
+
const updates = sheets.map((module) => {
|
|
1342
|
+
const path = module.url.startsWith('/') || module.url.startsWith('.')
|
|
1343
|
+
? module.url
|
|
1344
|
+
: `/@id/${module.url.replace('\0', '__x00__')}`;
|
|
1345
|
+
return {
|
|
1346
|
+
acceptedPath: path,
|
|
1347
|
+
explicitImportRequired: false,
|
|
1348
|
+
isWithinCircularImport: false,
|
|
1349
|
+
path,
|
|
1350
|
+
timestamp,
|
|
1351
|
+
type: 'js-update',
|
|
1352
|
+
};
|
|
1353
|
+
});
|
|
1354
|
+
environment.logger.info(`hmr update ${updates.map((update) => update.path).join(', ')}`, { timestamp: true });
|
|
1355
|
+
environment.hot.send({ type: 'update', updates });
|
|
1356
|
+
return [];
|
|
1357
|
+
}
|
|
1358
|
+
for (const module of sheets)
|
|
1359
|
+
affected.add(module);
|
|
1360
|
+
return [...affected];
|
|
1361
|
+
}
|
|
979
1362
|
return {
|
|
980
1363
|
buildStart() {
|
|
1364
|
+
edgeMemos.delete(this.environment);
|
|
981
1365
|
reads.delete(this.environment);
|
|
982
1366
|
lookups.delete(this.environment);
|
|
983
1367
|
},
|
|
@@ -1040,6 +1424,7 @@ export function zyzz(options = {}) {
|
|
|
1040
1424
|
},
|
|
1041
1425
|
},
|
|
1042
1426
|
configureServer(server) {
|
|
1427
|
+
devServer = server;
|
|
1043
1428
|
// Directory watches belong to the server, not module import dependencies.
|
|
1044
1429
|
server.watcher.add(directories.slice(1));
|
|
1045
1430
|
server.middlewares.use((request, response, next) => {
|
|
@@ -1072,6 +1457,7 @@ export function zyzz(options = {}) {
|
|
|
1072
1457
|
const patterns = [...configFiles, ...(options.exclude ?? [])];
|
|
1073
1458
|
filter = createFilter(null, patterns, { resolve: root });
|
|
1074
1459
|
exclusions.clear();
|
|
1460
|
+
roots.clear();
|
|
1075
1461
|
if (native)
|
|
1076
1462
|
return;
|
|
1077
1463
|
const lightning = (config.css.lightningcss ??= {});
|
|
@@ -1134,10 +1520,46 @@ export function zyzz(options = {}) {
|
|
|
1134
1520
|
},
|
|
1135
1521
|
},
|
|
1136
1522
|
async watchChange(file, change) {
|
|
1523
|
+
// A removed file leaves the watcher, so a later compile that reads it again adds it again.
|
|
1524
|
+
if (change.event === 'delete')
|
|
1525
|
+
watched.delete(file);
|
|
1137
1526
|
await updateDiscovery(this.environment, file, change.event);
|
|
1138
1527
|
},
|
|
1139
1528
|
async hotUpdate({ file, modules, timestamp, type, server }) {
|
|
1140
1529
|
const state = entries(this.environment);
|
|
1530
|
+
const before = projects.get(this.environment)?.outcome;
|
|
1531
|
+
// Concurrent transforms update entries while this compiles, so the served output is read now.
|
|
1532
|
+
const served = {
|
|
1533
|
+
entries: new Map([...state.values()].map((entry) => [
|
|
1534
|
+
entry,
|
|
1535
|
+
{ code: entry.code, css: entry.css, imports: entry.imports },
|
|
1536
|
+
])),
|
|
1537
|
+
shared: servedShared.get(this.environment),
|
|
1538
|
+
};
|
|
1539
|
+
// The merged development graph compares module outputs before and after the edit, so
|
|
1540
|
+
// only modules whose code or stylesheet changed update.
|
|
1541
|
+
if (!native && before && 'result' in before) {
|
|
1542
|
+
await updateDiscovery(this.environment, file, type);
|
|
1543
|
+
// The edited module's own entry, or one whose closure reads it, merges its new source.
|
|
1544
|
+
// A contribution source no module imports joins every closure.
|
|
1545
|
+
const first = state.get(file) ??
|
|
1546
|
+
[...state.values()].find((entry) => entry.files.has(file)) ??
|
|
1547
|
+
(eager(file, this.environment)
|
|
1548
|
+
? state.values().next().value
|
|
1549
|
+
: undefined);
|
|
1550
|
+
if (!first && !removed.get(this.environment)?.has(file))
|
|
1551
|
+
return modules;
|
|
1552
|
+
const compiled = first && type === 'update' && eligible(file)
|
|
1553
|
+
? await compile(first, {
|
|
1554
|
+
resolve: resolver(this.environment),
|
|
1555
|
+
watch: (file) => watch(server, file),
|
|
1556
|
+
asset: async (file) => file,
|
|
1557
|
+
}).then(() => true, () => false)
|
|
1558
|
+
: false;
|
|
1559
|
+
const after = projects.get(this.environment)?.outcome;
|
|
1560
|
+
if (compiled && after && 'result' in after)
|
|
1561
|
+
return await changes(this.environment, after.result, served, modules, timestamp, file, type === 'delete' ? file : undefined);
|
|
1562
|
+
}
|
|
1141
1563
|
const previous = [...state.values()].map((entry) => ({
|
|
1142
1564
|
code: entry.code,
|
|
1143
1565
|
file: entry.file,
|
|
@@ -1151,9 +1573,7 @@ export function zyzz(options = {}) {
|
|
|
1151
1573
|
const output = first && type === 'update' && eligible(file)
|
|
1152
1574
|
? await compile(first, {
|
|
1153
1575
|
resolve: resolver(this.environment),
|
|
1154
|
-
watch: (file) =>
|
|
1155
|
-
server.watcher.add(file);
|
|
1156
|
-
},
|
|
1576
|
+
watch: (file) => watch(server, file),
|
|
1157
1577
|
asset: async (file) => file,
|
|
1158
1578
|
}, undefined, true, true).catch(() => undefined)
|
|
1159
1579
|
: undefined;
|
|
@@ -1214,19 +1634,40 @@ export function zyzz(options = {}) {
|
|
|
1214
1634
|
const file = id === sharedId
|
|
1215
1635
|
? undefined
|
|
1216
1636
|
: decodeURIComponent(id.slice(prefix.length, -4));
|
|
1217
|
-
|
|
1637
|
+
let entry = file === undefined
|
|
1218
1638
|
? entries(this.environment).values().next().value
|
|
1219
1639
|
: entries(this.environment).get(file);
|
|
1220
1640
|
// A pruned JavaScript module can leave its stylesheet loaded in the browser.
|
|
1221
1641
|
if (!entry && file && removed.get(this.environment)?.has(file))
|
|
1222
1642
|
return '';
|
|
1643
|
+
// Server rendering links the stylesheets of modules this environment has not transformed
|
|
1644
|
+
// yet, so a development request compiles the module where the browser loads it.
|
|
1645
|
+
if (!entry && this.environment.mode === 'dev') {
|
|
1646
|
+
const anchor = file ??
|
|
1647
|
+
(await discover(this.environment, {
|
|
1648
|
+
asset: async (file) => file,
|
|
1649
|
+
resolve: resolver(this.environment),
|
|
1650
|
+
watch: watcher(this),
|
|
1651
|
+
}))
|
|
1652
|
+
.keys()
|
|
1653
|
+
.next().value;
|
|
1654
|
+
if (anchor !== undefined && eligible(anchor)) {
|
|
1655
|
+
entry = {
|
|
1656
|
+
compiler: compiler(this.environment),
|
|
1657
|
+
environment: this.environment,
|
|
1658
|
+
file: anchor,
|
|
1659
|
+
files: new Set([anchor]),
|
|
1660
|
+
};
|
|
1661
|
+
entries(this.environment).set(anchor, entry);
|
|
1662
|
+
}
|
|
1663
|
+
}
|
|
1223
1664
|
if (!entry)
|
|
1224
1665
|
throw new Error(`Unknown Zyzz stylesheet: ${file}`);
|
|
1225
1666
|
const output = await compile(entry, {
|
|
1226
1667
|
resolve: this.environment.mode === 'dev'
|
|
1227
1668
|
? resolver(this.environment)
|
|
1228
1669
|
: (source, importer) => this.resolve(source, importer),
|
|
1229
|
-
watch: (
|
|
1670
|
+
watch: watcher(this),
|
|
1230
1671
|
asset: async (file) => {
|
|
1231
1672
|
const reference = this.emitFile({
|
|
1232
1673
|
type: 'asset',
|
|
@@ -1240,12 +1681,18 @@ export function zyzz(options = {}) {
|
|
|
1240
1681
|
const transport = (css) => this.environment.config.command === 'build'
|
|
1241
1682
|
? AtRules.rename(AtRules.rename(Namespaces.protect(css), 'font-feature-values', '-zyzz-ffv-000000000'), 'font-palette-values', '-zyzz-fpv-000000000')
|
|
1242
1683
|
: css;
|
|
1243
|
-
if (id === sharedId)
|
|
1684
|
+
if (id === sharedId) {
|
|
1685
|
+
servedShared.set(this.environment, output.graphSharedCss);
|
|
1244
1686
|
return {
|
|
1245
1687
|
code: transport(output.sharedCss),
|
|
1246
1688
|
map: JSON.stringify(output.sharedCssMap),
|
|
1247
1689
|
};
|
|
1248
|
-
|
|
1690
|
+
}
|
|
1691
|
+
entry.css = output.css;
|
|
1692
|
+
return {
|
|
1693
|
+
code: transport(output.css),
|
|
1694
|
+
map: JSON.stringify(output.cssMap),
|
|
1695
|
+
};
|
|
1249
1696
|
},
|
|
1250
1697
|
name: 'zyzz',
|
|
1251
1698
|
resolveId(id) {
|
|
@@ -1268,11 +1715,12 @@ export function zyzz(options = {}) {
|
|
|
1268
1715
|
state.set(id, entry);
|
|
1269
1716
|
removed.get(this.environment)?.delete(id);
|
|
1270
1717
|
}
|
|
1718
|
+
entry.source = code;
|
|
1271
1719
|
const output = await compile(entry, {
|
|
1272
1720
|
resolve: this.environment.mode === 'dev'
|
|
1273
1721
|
? resolver(this.environment)
|
|
1274
1722
|
: (source, importer) => this.resolve(source, importer),
|
|
1275
|
-
watch: (
|
|
1723
|
+
watch: watcher(this),
|
|
1276
1724
|
asset: async (file) => {
|
|
1277
1725
|
const reference = this.emitFile({
|
|
1278
1726
|
type: 'asset',
|
|
@@ -1289,53 +1737,23 @@ export function zyzz(options = {}) {
|
|
|
1289
1737
|
return { code: output.code, map: JSON.stringify(output.map) };
|
|
1290
1738
|
// Keep the CSS dependency even when the current graph has no live rules.
|
|
1291
1739
|
// Later edits can introduce styles without changing this import boundary.
|
|
1292
|
-
const
|
|
1293
|
-
sourceType: 'module',
|
|
1294
|
-
});
|
|
1295
|
-
let offset = output.code.startsWith('#!')
|
|
1296
|
-
? output.code.indexOf('\n') + 1
|
|
1297
|
-
: 0;
|
|
1298
|
-
for (const node of parsed.program.body) {
|
|
1299
|
-
if (node.type !== 'ExpressionStatement' || !node.directive)
|
|
1300
|
-
break;
|
|
1301
|
-
offset = node.end;
|
|
1302
|
-
}
|
|
1740
|
+
const offset = prologue(output.code);
|
|
1303
1741
|
const sharedImport = `\nimport ${JSON.stringify(sharedId)};\n`;
|
|
1304
|
-
const map = Mapping.fromMap(JSON.stringify(output.map));
|
|
1305
1742
|
// The inserted dependency shifts only generated positions after the prologue.
|
|
1306
1743
|
const before = output.code.slice(0, offset);
|
|
1307
1744
|
const insertionLine = before.split('\n').length;
|
|
1308
1745
|
const insertionColumn = before.length - (before.lastIndexOf('\n') + 1);
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
generated.column >= insertionColumn)) {
|
|
1315
|
-
if (generated.line === insertionLine)
|
|
1316
|
-
generated.column -= insertionColumn;
|
|
1317
|
-
generated.line += 2;
|
|
1318
|
-
}
|
|
1319
|
-
if (mapping.source !== undefined && mapping.original !== undefined) {
|
|
1320
|
-
const location = {
|
|
1321
|
-
generated,
|
|
1322
|
-
original: mapping.original,
|
|
1323
|
-
source: mapping.source,
|
|
1324
|
-
};
|
|
1325
|
-
if (mapping.name === undefined)
|
|
1326
|
-
Mapping.addMapping(shifted, location);
|
|
1327
|
-
else
|
|
1328
|
-
Mapping.addMapping(shifted, { ...location, name: mapping.name });
|
|
1329
|
-
}
|
|
1330
|
-
else
|
|
1331
|
-
Mapping.addMapping(shifted, { generated });
|
|
1332
|
-
}
|
|
1333
|
-
for (const [index, source] of output.map.sources.entries())
|
|
1334
|
-
if (source !== null)
|
|
1335
|
-
Mapping.setSourceContent(shifted, source, output.map.sourcesContent?.[index] ?? null);
|
|
1746
|
+
// A build compiles a fixed project, so an empty module sheet stays empty. Importing it
|
|
1747
|
+
// would link an empty stylesheet from every chunk that holds no styled module.
|
|
1748
|
+
const stylesheetImport = this.environment.mode === 'build' && !output.css.trim()
|
|
1749
|
+
? ''
|
|
1750
|
+
: `\nimport ${JSON.stringify(cssId(id))};`;
|
|
1336
1751
|
return {
|
|
1337
|
-
code: `${before}${sharedImport}${output.code.slice(offset)}
|
|
1338
|
-
map: JSON.stringify(
|
|
1752
|
+
code: `${before}${sharedImport}${output.code.slice(offset)}${stylesheetImport}`,
|
|
1753
|
+
map: JSON.stringify({
|
|
1754
|
+
...output.map,
|
|
1755
|
+
mappings: insert(output.map.mappings, insertionLine - 1, insertionColumn),
|
|
1756
|
+
}),
|
|
1339
1757
|
};
|
|
1340
1758
|
},
|
|
1341
1759
|
transformIndexHtml: {
|
|
@@ -1363,6 +1781,83 @@ export function zyzz(options = {}) {
|
|
|
1363
1781
|
},
|
|
1364
1782
|
};
|
|
1365
1783
|
}
|
|
1784
|
+
/**
|
|
1785
|
+
* The end of a module's hashbang and directive prologue, where an added import keeps directives
|
|
1786
|
+
* first. Source without a leading string literal skips parsing.
|
|
1787
|
+
*/
|
|
1788
|
+
function prologue(code) {
|
|
1789
|
+
let index = code.startsWith('#!') ? code.indexOf('\n') + 1 : 0;
|
|
1790
|
+
const start = index;
|
|
1791
|
+
for (;;) {
|
|
1792
|
+
while (index < code.length && /\s/.test(code[index]))
|
|
1793
|
+
index++;
|
|
1794
|
+
if (code.startsWith('//', index)) {
|
|
1795
|
+
const end = code.indexOf('\n', index);
|
|
1796
|
+
index = end === -1 ? code.length : end;
|
|
1797
|
+
}
|
|
1798
|
+
else if (code.startsWith('/*', index)) {
|
|
1799
|
+
const end = code.indexOf('*/', index + 2);
|
|
1800
|
+
index = end === -1 ? code.length : end + 2;
|
|
1801
|
+
}
|
|
1802
|
+
else
|
|
1803
|
+
break;
|
|
1804
|
+
}
|
|
1805
|
+
if (code[index] !== "'" && code[index] !== '"')
|
|
1806
|
+
return start;
|
|
1807
|
+
let offset = start;
|
|
1808
|
+
const { program } = Parser.parseSync('source.tsx', code, {
|
|
1809
|
+
sourceType: 'module',
|
|
1810
|
+
});
|
|
1811
|
+
for (const node of program.body) {
|
|
1812
|
+
if (node.type !== 'ExpressionStatement' || !node.directive)
|
|
1813
|
+
break;
|
|
1814
|
+
offset = node.end;
|
|
1815
|
+
}
|
|
1816
|
+
return offset;
|
|
1817
|
+
}
|
|
1818
|
+
/**
|
|
1819
|
+
* Moves encoded mappings for two lines inserted at a generated position. Segments at or past
|
|
1820
|
+
* `column` on `line` start the line after the insertion, and every later line moves down by two.
|
|
1821
|
+
* Other fields stay relative to the segment before them, which keeps its order.
|
|
1822
|
+
*/
|
|
1823
|
+
function insert(mappings, line, column) {
|
|
1824
|
+
const lines = mappings.split(';');
|
|
1825
|
+
const text = lines[line];
|
|
1826
|
+
if (text === undefined)
|
|
1827
|
+
return mappings;
|
|
1828
|
+
let generated = 0;
|
|
1829
|
+
let split = -1;
|
|
1830
|
+
let position = 0;
|
|
1831
|
+
const segments = text ? text.split(',') : [];
|
|
1832
|
+
for (const [index, segment] of segments.entries()) {
|
|
1833
|
+
const [delta] = Vlq.decode(segment);
|
|
1834
|
+
generated += delta;
|
|
1835
|
+
if (generated >= column) {
|
|
1836
|
+
split = index;
|
|
1837
|
+
position = generated;
|
|
1838
|
+
break;
|
|
1839
|
+
}
|
|
1840
|
+
}
|
|
1841
|
+
if (split === -1) {
|
|
1842
|
+
lines.splice(line + 1, 0, '', '');
|
|
1843
|
+
return lines.join(';');
|
|
1844
|
+
}
|
|
1845
|
+
const moved = segments.slice(split);
|
|
1846
|
+
const fields = Vlq.decode(moved[0]);
|
|
1847
|
+
fields[0] = position - column;
|
|
1848
|
+
moved[0] = Vlq.encode(fields);
|
|
1849
|
+
lines.splice(line, 1, segments.slice(0, split).join(','), '', moved.join(','));
|
|
1850
|
+
return lines.join(';');
|
|
1851
|
+
}
|
|
1852
|
+
/** Whether two import resolution records hold the same entries. */
|
|
1853
|
+
function same(left, right) {
|
|
1854
|
+
if (!left)
|
|
1855
|
+
return false;
|
|
1856
|
+
const keys = Object.keys(right);
|
|
1857
|
+
if (Object.keys(left).length !== keys.length)
|
|
1858
|
+
return false;
|
|
1859
|
+
return keys.every((key) => left[key] === right[key]);
|
|
1860
|
+
}
|
|
1366
1861
|
/**
|
|
1367
1862
|
* Whether `zyzz/runtime` resolves inside node_modules from the Vite root. Vite
|
|
1368
1863
|
* optimizes a discovered import only there, so linked and aliased copies stay
|