@master/css-vite 0.0.0-site.1793659883.g69c9aebcf628
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/README.md +348 -0
- package/dist/common.d.ts +14 -0
- package/dist/common.js +26 -0
- package/dist/core.d.ts +23 -0
- package/dist/core.js +165 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +1 -0
- package/dist/internal/src/emitted-globals-module.js +12 -0
- package/dist/internal/src/manifest-facade.js +68 -0
- package/dist/internal/src/manifest-loader.js +33 -0
- package/dist/internal/src/manifest-module.js +58 -0
- package/dist/internal/src/manifest-virtual-module.js +123 -0
- package/dist/internal/src/node.js +22 -0
- package/dist/internal/src/program-module.js +50 -0
- package/dist/internal/src/project.js +10 -0
- package/dist/internal/src/runtime-bootstrap.js +80 -0
- package/dist/internal/src/style-module.js +3 -0
- package/dist/modes/pre-render.d.ts +5 -0
- package/dist/modes/pre-render.js +6 -0
- package/dist/modes/progressive.d.ts +5 -0
- package/dist/modes/progressive.js +12 -0
- package/dist/modes/runtime.d.ts +5 -0
- package/dist/modes/runtime.js +17 -0
- package/dist/modes/static.d.ts +5 -0
- package/dist/modes/static.js +5 -0
- package/dist/options.d.ts +20 -0
- package/dist/options.js +23 -0
- package/dist/plugins/avoid-fouc.d.ts +5 -0
- package/dist/plugins/avoid-fouc.js +48 -0
- package/dist/plugins/build-stylesheet-recovery.d.ts +5 -0
- package/dist/plugins/build-stylesheet-recovery.js +26 -0
- package/dist/plugins/context.d.ts +5 -0
- package/dist/plugins/context.js +12 -0
- package/dist/plugins/dev-stylesheet.d.ts +4 -0
- package/dist/plugins/dev-stylesheet.js +63 -0
- package/dist/plugins/emitted-globals-virtual-module.d.ts +14 -0
- package/dist/plugins/emitted-globals-virtual-module.js +167 -0
- package/dist/plugins/inject-runtime.d.ts +5 -0
- package/dist/plugins/inject-runtime.js +51 -0
- package/dist/plugins/inline-stylesheet.d.ts +5 -0
- package/dist/plugins/inline-stylesheet.js +197 -0
- package/dist/plugins/local-styles.d.ts +5 -0
- package/dist/plugins/local-styles.js +214 -0
- package/dist/plugins/manifest-loader.d.ts +4 -0
- package/dist/plugins/manifest-loader.js +102 -0
- package/dist/plugins/manifest-virtual-module.d.ts +4 -0
- package/dist/plugins/manifest-virtual-module.js +70 -0
- package/dist/plugins/pre-render.d.ts +5 -0
- package/dist/plugins/pre-render.js +224 -0
- package/dist/plugins/program-preload.d.ts +5 -0
- package/dist/plugins/program-preload.js +37 -0
- package/dist/plugins/runtime-bootstrap.d.ts +3 -0
- package/dist/plugins/runtime-bootstrap.js +14 -0
- package/dist/plugins/runtime-preload.d.ts +4 -0
- package/dist/plugins/runtime-preload.js +38 -0
- package/dist/plugins/sass-source.d.ts +5 -0
- package/dist/plugins/sass-source.js +176 -0
- package/dist/plugins/scanner.d.ts +5 -0
- package/dist/plugins/scanner.js +24 -0
- package/dist/plugins/style-entry-build.d.ts +5 -0
- package/dist/plugins/style-entry-build.js +121 -0
- package/dist/plugins/style-entry-hmr.d.ts +6 -0
- package/dist/plugins/style-entry-hmr.js +78 -0
- package/dist/plugins/style-entry.d.ts +5 -0
- package/dist/plugins/style-entry.js +89 -0
- package/dist/plugins/stylesheet-recovery.d.ts +5 -0
- package/dist/plugins/stylesheet-recovery.js +70 -0
- package/dist/plugins/usage-graph.d.ts +5 -0
- package/dist/plugins/usage-graph.js +48 -0
- package/dist/preset/src/default-manifest.js +15913 -0
- package/dist/utils/build-import-resolver.d.ts +29 -0
- package/dist/utils/build-import-resolver.js +101 -0
- package/dist/utils/build-sass-source.d.ts +38 -0
- package/dist/utils/build-sass-source.js +225 -0
- package/dist/utils/build-stylesheet-delivery.d.ts +12 -0
- package/dist/utils/build-stylesheet-delivery.js +130 -0
- package/dist/utils/build-watch-recovery.d.ts +10 -0
- package/dist/utils/build-watch-recovery.js +119 -0
- package/dist/utils/coalesced-task.d.ts +3 -0
- package/dist/utils/coalesced-task.js +25 -0
- package/dist/utils/dev-module-refresh.d.ts +9 -0
- package/dist/utils/dev-module-refresh.js +17 -0
- package/dist/utils/dev-stylesheet-delivery.d.ts +21 -0
- package/dist/utils/dev-stylesheet-delivery.js +98 -0
- package/dist/utils/environment-closing.d.ts +3 -0
- package/dist/utils/environment-closing.js +28 -0
- package/dist/utils/extracted-css.d.ts +4 -0
- package/dist/utils/extracted-css.js +34 -0
- package/dist/utils/failed-dependency-reconciliation.d.ts +15 -0
- package/dist/utils/failed-dependency-reconciliation.js +150 -0
- package/dist/utils/failed-stylesheet-dependencies.d.ts +16 -0
- package/dist/utils/failed-stylesheet-dependencies.js +92 -0
- package/dist/utils/html.d.ts +8 -0
- package/dist/utils/html.js +36 -0
- package/dist/utils/inline-stylesheet.d.ts +37 -0
- package/dist/utils/inline-stylesheet.js +129 -0
- package/dist/utils/local-stylesheet.d.ts +10 -0
- package/dist/utils/local-stylesheet.js +25 -0
- package/dist/utils/manifest-recovery.d.ts +11 -0
- package/dist/utils/manifest-recovery.js +77 -0
- package/dist/utils/module-sources.d.ts +26 -0
- package/dist/utils/module-sources.js +131 -0
- package/dist/utils/path.d.ts +5 -0
- package/dist/utils/path.js +27 -0
- package/dist/utils/recovery-error.d.ts +3 -0
- package/dist/utils/recovery-error.js +17 -0
- package/dist/utils/register-style-source.d.ts +4 -0
- package/dist/utils/register-style-source.js +23 -0
- package/dist/utils/sass-diagnostics.d.ts +4 -0
- package/dist/utils/sass-diagnostics.js +109 -0
- package/dist/utils/sass-proxy-access.d.ts +4 -0
- package/dist/utils/sass-proxy-access.js +28 -0
- package/dist/utils/sass-source-markers.d.ts +8 -0
- package/dist/utils/sass-source-markers.js +50 -0
- package/dist/utils/scanner-context.d.ts +12 -0
- package/dist/utils/scanner-context.js +100 -0
- package/dist/utils/scoped-plugins.d.ts +4 -0
- package/dist/utils/scoped-plugins.js +81 -0
- package/dist/utils/write-file.d.ts +3 -0
- package/dist/utils/write-file.js +9 -0
- package/package.json +62 -0
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
// src/utils/coalesced-task.ts
|
|
2
|
+
/** Keep one active operation and collapse pending events into its latest follow-up. */
|
|
3
|
+
function createCoalescedTask(work, onError) {
|
|
4
|
+
let running;
|
|
5
|
+
let dirty = false;
|
|
6
|
+
return function schedule() {
|
|
7
|
+
dirty = true;
|
|
8
|
+
if (!running) running = Promise.resolve().then(async () => {
|
|
9
|
+
try {
|
|
10
|
+
while (dirty) {
|
|
11
|
+
dirty = false;
|
|
12
|
+
try {
|
|
13
|
+
await work();
|
|
14
|
+
} catch (error) {
|
|
15
|
+
onError(error);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
} finally {
|
|
19
|
+
running = void 0;
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
return running;
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
export { createCoalescedTask };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { DevEnvironment, ViteDevServer } from "vite";
|
|
2
|
+
/**
|
|
3
|
+
* Refresh a module whose generated content changed without a source edit.
|
|
4
|
+
* Browsers take an HMR update. A server module that cannot accept the update is
|
|
5
|
+
* only invalidated, so its runner refetches it on the next import: a program
|
|
6
|
+
* reload would restart the runner under requests that are still rendering.
|
|
7
|
+
*/
|
|
8
|
+
declare function refreshGeneratedModule(server: ViteDevServer, id: string, accepts?: (environment: DevEnvironment) => boolean): Promise<void>;
|
|
9
|
+
export { refreshGeneratedModule };
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
// src/utils/dev-module-refresh.ts
|
|
2
|
+
/**
|
|
3
|
+
* Refresh a module whose generated content changed without a source edit.
|
|
4
|
+
* Browsers take an HMR update. A server module that cannot accept the update is
|
|
5
|
+
* only invalidated, so its runner refetches it on the next import: a program
|
|
6
|
+
* reload would restart the runner under requests that are still rendering.
|
|
7
|
+
*/
|
|
8
|
+
async function refreshGeneratedModule(server, id, accepts = () => true) {
|
|
9
|
+
await Promise.all(Object.values(server.environments).map(async (environment) => {
|
|
10
|
+
if (!accepts(environment)) return;
|
|
11
|
+
const module = environment.moduleGraph.getModuleById(id);
|
|
12
|
+
if (!module) return;
|
|
13
|
+
if (environment.config.consumer === "client" || module.isSelfAccepting) return environment.reloadModule(module);
|
|
14
|
+
for (const each of module.file && environment.moduleGraph.getModulesByFile(module.file) || [module]) environment.moduleGraph.invalidateModule(each);
|
|
15
|
+
}));
|
|
16
|
+
}
|
|
17
|
+
export { refreshGeneratedModule };
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { MasterCSSStylesheetComposition, MasterCSSStylesheetDeliveryOptions } from "@master/css-compiler/stylesheet";
|
|
2
|
+
import { MasterCSSVitePluginContext } from "../core.js";
|
|
3
|
+
interface DevStylesheetState {
|
|
4
|
+
delivery?: MasterCSSStylesheetDeliveryOptions;
|
|
5
|
+
origin: string;
|
|
6
|
+
prefix: string;
|
|
7
|
+
stylesheets: Map<string, string>;
|
|
8
|
+
resources: Map<string, {
|
|
9
|
+
file: string;
|
|
10
|
+
source: string;
|
|
11
|
+
}>;
|
|
12
|
+
resourceDir?: string;
|
|
13
|
+
}
|
|
14
|
+
declare function devStylesheetState(context: MasterCSSVitePluginContext): DevStylesheetState;
|
|
15
|
+
declare function clearDevStylesheets(context: MasterCSSVitePluginContext): void;
|
|
16
|
+
/** A separate import keeps generated selectors and keyframes outside SFC scoping. */
|
|
17
|
+
declare function publishDevGlobalStylesheet(context: MasterCSSVitePluginContext, css: string): string;
|
|
18
|
+
/** Give Vite external URLs while its CSS pipeline runs; the post hook makes them same-origin. */
|
|
19
|
+
declare function getDevStylesheetDelivery(context: MasterCSSVitePluginContext): MasterCSSStylesheetDeliveryOptions | undefined;
|
|
20
|
+
declare function publishDevStylesheets(context: MasterCSSVitePluginContext, result: MasterCSSStylesheetComposition, slotCSSRule: string): string;
|
|
21
|
+
export { clearDevStylesheets, devStylesheetState, getDevStylesheetDelivery, publishDevGlobalStylesheet, publishDevStylesheets };
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { toAssetHref } from "./html.js";
|
|
2
|
+
import { createHash, randomUUID } from "node:crypto";
|
|
3
|
+
import { mkdirSync, mkdtempSync, readFileSync, realpathSync, rmSync, writeFileSync } from "node:fs";
|
|
4
|
+
import { basename, join } from "node:path";
|
|
5
|
+
import { createCompilerSync } from "@master/css-compiler/node";
|
|
6
|
+
// src/utils/dev-stylesheet-delivery.ts
|
|
7
|
+
const states = /* @__PURE__ */ new WeakMap();
|
|
8
|
+
function digest(source) {
|
|
9
|
+
return createHash("sha256").update(source).digest("hex").slice(0, 20);
|
|
10
|
+
}
|
|
11
|
+
function devStylesheetState(context) {
|
|
12
|
+
let state = states.get(context);
|
|
13
|
+
if (!state) {
|
|
14
|
+
const token = randomUUID();
|
|
15
|
+
state = {
|
|
16
|
+
origin: `https://master-css-dev-${token}.invalid`,
|
|
17
|
+
prefix: toAssetHref(`_master-css/dev/${token}/`, context.config?.base),
|
|
18
|
+
stylesheets: /* @__PURE__ */ new Map(),
|
|
19
|
+
resources: /* @__PURE__ */ new Map()
|
|
20
|
+
};
|
|
21
|
+
states.set(context, state);
|
|
22
|
+
}
|
|
23
|
+
return state;
|
|
24
|
+
}
|
|
25
|
+
function clearDevStylesheets(context) {
|
|
26
|
+
const directory = states.get(context)?.resourceDir;
|
|
27
|
+
if (directory) rmSync(directory, {
|
|
28
|
+
recursive: true,
|
|
29
|
+
force: true
|
|
30
|
+
});
|
|
31
|
+
states.delete(context);
|
|
32
|
+
}
|
|
33
|
+
/** A separate import keeps generated selectors and keyframes outside SFC scoping. */
|
|
34
|
+
function publishDevGlobalStylesheet(context, css) {
|
|
35
|
+
const state = devStylesheetState(context);
|
|
36
|
+
const path = state.prefix + `globals-${digest(css)}.css`;
|
|
37
|
+
state.stylesheets.set(path, css.replaceAll(state.origin, ""));
|
|
38
|
+
return `@import ${JSON.stringify(state.origin + path)};`;
|
|
39
|
+
}
|
|
40
|
+
/** Give Vite external URLs while its CSS pipeline runs; the post hook makes them same-origin. */
|
|
41
|
+
function getDevStylesheetDelivery(context) {
|
|
42
|
+
if (context.config?.command !== "serve") return;
|
|
43
|
+
const state = devStylesheetState(context), base = state.origin + state.prefix;
|
|
44
|
+
return state.delivery ??= {
|
|
45
|
+
entryURL: base + "entry.css",
|
|
46
|
+
stylesheetURL: (file, variant) => base + `source-${digest(variant ?? file)}.css`,
|
|
47
|
+
resourceURL: (source) => {
|
|
48
|
+
const content = readFileSync(source);
|
|
49
|
+
const href = base + `resource/${digest(source + "\0" + digest(content))}/${encodeURIComponent(basename(source))}`;
|
|
50
|
+
const key = new URL(href).pathname;
|
|
51
|
+
if (!state.resources.has(key)) {
|
|
52
|
+
if (!state.resourceDir) {
|
|
53
|
+
const cache = join(context.config.root, "node_modules", ".master-css");
|
|
54
|
+
mkdirSync(cache, { recursive: true });
|
|
55
|
+
state.resourceDir = realpathSync.native(mkdtempSync(join(cache, "master-css-vite-resources-")));
|
|
56
|
+
}
|
|
57
|
+
const file = join(state.resourceDir, digest(href) + "-" + basename(source).replace(/[^a-zA-Z0-9._-]/g, "_"));
|
|
58
|
+
writeFileSync(file, content);
|
|
59
|
+
state.resources.set(key, {
|
|
60
|
+
file,
|
|
61
|
+
source
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
return href;
|
|
65
|
+
},
|
|
66
|
+
resolveNodePackageImports: true
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
function publishDevStylesheets(context, result, slotCSSRule) {
|
|
70
|
+
const delivery = getDevStylesheetDelivery(context);
|
|
71
|
+
const state = devStylesheetState(context);
|
|
72
|
+
using compiler = createCompilerSync();
|
|
73
|
+
const bundle = compiler.prepareStylesheetBundle({
|
|
74
|
+
source: slotCSSRule,
|
|
75
|
+
from: "master-css-dev",
|
|
76
|
+
slotCSSRule,
|
|
77
|
+
managed: {
|
|
78
|
+
entry: "master-css-managed",
|
|
79
|
+
stylesheets: [{
|
|
80
|
+
id: "master-css-managed",
|
|
81
|
+
href: delivery.entryURL,
|
|
82
|
+
css: result.css
|
|
83
|
+
}, ...result.stylesheets ?? []]
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
const version = digest(JSON.stringify(bundle));
|
|
87
|
+
const urls = Object.fromEntries(bundle.graph.stylesheets.map((node) => [node.id, state.origin + state.prefix + `sheet-${digest(node.id)}-${version}.css`]));
|
|
88
|
+
const assets = compiler.renderStylesheetBundle({
|
|
89
|
+
bundle,
|
|
90
|
+
urls,
|
|
91
|
+
inlineImports: true
|
|
92
|
+
});
|
|
93
|
+
for (const asset of assets) state.stylesheets.set(new URL(asset.href).pathname, asset.css.replaceAll(state.origin, ""));
|
|
94
|
+
const root = assets.find((asset) => asset.id === bundle.graph.entry);
|
|
95
|
+
if (!root) throw new Error("Development stylesheet graph is missing its entry");
|
|
96
|
+
return root.css;
|
|
97
|
+
}
|
|
98
|
+
export { clearDevStylesheets, devStylesheetState, getDevStylesheetDelivery, publishDevGlobalStylesheet, publishDevStylesheets };
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
// src/utils/environment-closing.ts
|
|
2
|
+
const states = /* @__PURE__ */ new WeakMap();
|
|
3
|
+
/** closeBundle runs after pending hooks; cancel adapter work when close begins. */
|
|
4
|
+
function onEnvironmentClosing(environment, callback) {
|
|
5
|
+
let state = states.get(environment);
|
|
6
|
+
if (!state) {
|
|
7
|
+
const owner = environment;
|
|
8
|
+
if (typeof owner.close !== "function") return;
|
|
9
|
+
const close = owner.close;
|
|
10
|
+
state = {
|
|
11
|
+
closing: false,
|
|
12
|
+
callbacks: /* @__PURE__ */ new Set()
|
|
13
|
+
};
|
|
14
|
+
states.set(environment, state);
|
|
15
|
+
const tracked = state;
|
|
16
|
+
owner.close = function() {
|
|
17
|
+
if (!tracked.closing) {
|
|
18
|
+
tracked.closing = true;
|
|
19
|
+
for (const cancel of tracked.callbacks) cancel();
|
|
20
|
+
tracked.callbacks.clear();
|
|
21
|
+
}
|
|
22
|
+
return close.call(this);
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
if (state.closing) callback();
|
|
26
|
+
else state.callbacks.add(callback);
|
|
27
|
+
}
|
|
28
|
+
export { onEnvironmentClosing };
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { MasterCSSVitePluginContext } from "../core.js";
|
|
2
|
+
declare function getExtractedCSSResult(context: MasterCSSVitePluginContext): Promise<import("@master/css-compiler/stylesheet").MasterCSSStylesheetComposition>;
|
|
3
|
+
declare function getExtractedCSS(context: MasterCSSVitePluginContext): Promise<string>;
|
|
4
|
+
export { getExtractedCSS as default, getExtractedCSSResult };
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { withSassDiagnostics } from "./sass-diagnostics.js";
|
|
2
|
+
import { getScanner } from "./scanner-context.js";
|
|
3
|
+
import { getBuildStylesheetDelivery } from "./build-stylesheet-delivery.js";
|
|
4
|
+
import { getDevStylesheetDelivery, publishDevStylesheets } from "./dev-stylesheet-delivery.js";
|
|
5
|
+
// src/utils/extracted-css.ts
|
|
6
|
+
const revisions = /* @__PURE__ */ new WeakMap();
|
|
7
|
+
async function getExtractedCSSResult(context) {
|
|
8
|
+
const revision = (revisions.get(context) ?? 0) + 1;
|
|
9
|
+
revisions.set(context, revision);
|
|
10
|
+
const scanner = getScanner(context);
|
|
11
|
+
if (!context.stylesheets) {
|
|
12
|
+
const { createStylesheetCollection } = await import("@master/css-compiler/stylesheet");
|
|
13
|
+
context.stylesheets = createStylesheetCollection();
|
|
14
|
+
}
|
|
15
|
+
const result = await withSassDiagnostics(context, () => context.stylesheets.compose({
|
|
16
|
+
scanner,
|
|
17
|
+
baseManifest: scanner.css.manifest,
|
|
18
|
+
projectDir: context.config?.root,
|
|
19
|
+
pruneNativeCSS: context.pruneNativeCSS,
|
|
20
|
+
includeGeneratedCSS: context.includeGeneratedCSS,
|
|
21
|
+
delivery: getBuildStylesheetDelivery(context) ?? getDevStylesheetDelivery(context)
|
|
22
|
+
}));
|
|
23
|
+
if (revisions.get(context) === revision && context.scanner === scanner) {
|
|
24
|
+
const changed = JSON.stringify(context.emittedGlobals) !== JSON.stringify(result.emittedGlobals);
|
|
25
|
+
context.emittedGlobals = result.emittedGlobals;
|
|
26
|
+
if (changed) context.onEmittedGlobalsChange?.();
|
|
27
|
+
}
|
|
28
|
+
return result;
|
|
29
|
+
}
|
|
30
|
+
async function getExtractedCSS(context) {
|
|
31
|
+
const result = await getExtractedCSSResult(context);
|
|
32
|
+
return context.config?.command === "serve" ? publishDevStylesheets(context, result, getScanner(context).slotCSSRule) : result.css;
|
|
33
|
+
}
|
|
34
|
+
export { getExtractedCSS as default, getExtractedCSSResult };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { ResolvedConfig, ViteDevServer } from "vite";
|
|
2
|
+
import { MasterCSSVitePluginContext } from "../core.js";
|
|
3
|
+
type FailedDependencyRecovery = (environment: object, id: string, changed: string[], active: () => boolean) => Promise<void>;
|
|
4
|
+
/** Recheck only failed operations; successful stylesheets continue to use Vite HMR. */
|
|
5
|
+
declare function configureFailedDependencyReconciliation(context: MasterCSSVitePluginContext, server: ViteDevServer, recover: FailedDependencyRecovery): void;
|
|
6
|
+
/** Failed build transforms need a watched existing file to trigger another run. */
|
|
7
|
+
declare function configureBuildDependencyReconciliation(context: MasterCSSVitePluginContext, watch: NonNullable<ResolvedConfig['build']['watch']>): void;
|
|
8
|
+
/** A real host event already schedules compilation; avoid a duplicate fallback. */
|
|
9
|
+
declare function acknowledgeFailedDependencyChange(context: MasterCSSVitePluginContext, file: string): void;
|
|
10
|
+
/** Capture before the compiler reads a dependency, including its missing state. */
|
|
11
|
+
declare function failedDependencyVersion(context: MasterCSSVitePluginContext, file: string): string | undefined;
|
|
12
|
+
declare function trackFailedDependencyReconciliation(context: MasterCSSVitePluginContext, environment: object, key: string, id: string, versions: Map<string, string>, recover?: FailedDependencyRecovery): void;
|
|
13
|
+
declare function forgetFailedDependencyReconciliation(context: MasterCSSVitePluginContext, environment: object, key: string): void;
|
|
14
|
+
declare function clearFailedDependencyReconciliation(context: MasterCSSVitePluginContext, environment?: object): void;
|
|
15
|
+
export { FailedDependencyRecovery, acknowledgeFailedDependencyChange, clearFailedDependencyReconciliation, configureBuildDependencyReconciliation, configureFailedDependencyReconciliation, failedDependencyVersion, forgetFailedDependencyReconciliation, trackFailedDependencyReconciliation };
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import { normalizeFilePath } from "./path.js";
|
|
2
|
+
import { statSync } from "node:fs";
|
|
3
|
+
import { isAbsolute } from "node:path";
|
|
4
|
+
import { createFilter } from "vite";
|
|
5
|
+
import { stat } from "node:fs/promises";
|
|
6
|
+
// src/utils/failed-dependency-reconciliation.ts
|
|
7
|
+
const states = /* @__PURE__ */ new WeakMap();
|
|
8
|
+
function version(stats) {
|
|
9
|
+
return `${stats.dev}:${stats.ino}:${stats.size}:${stats.mtimeMs}:${stats.ctimeMs}`;
|
|
10
|
+
}
|
|
11
|
+
function missing(error) {
|
|
12
|
+
return `error:${error.code ?? "unknown"}`;
|
|
13
|
+
}
|
|
14
|
+
/** Recheck only failed operations; successful stylesheets continue to use Vite HMR. */
|
|
15
|
+
function configureFailedDependencyReconciliation(context, server, recover) {
|
|
16
|
+
clearFailedDependencyReconciliation(context);
|
|
17
|
+
const ignored = server.watcher.options.ignored;
|
|
18
|
+
const matchers = ignored === void 0 ? [] : Array.isArray(ignored) ? ignored : [ignored];
|
|
19
|
+
const filter = createFilter(void 0, matchers.filter((matcher) => typeof matcher !== "function"), { resolve: false });
|
|
20
|
+
states.set(context, {
|
|
21
|
+
pending: /* @__PURE__ */ new Map(),
|
|
22
|
+
closed: /* @__PURE__ */ new WeakSet(),
|
|
23
|
+
recover,
|
|
24
|
+
running: false,
|
|
25
|
+
accepts: (file, stats) => server.config.server.watch !== null && isAbsolute(file) && filter(file) && !matchers.some((matcher) => typeof matcher === "function" && matcher(file, stats))
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
/** Failed build transforms need a watched existing file to trigger another run. */
|
|
29
|
+
function configureBuildDependencyReconciliation(context, watch) {
|
|
30
|
+
if (states.has(context)) return;
|
|
31
|
+
const accepts = createFilter(watch.include, watch.exclude, { resolve: false });
|
|
32
|
+
states.set(context, {
|
|
33
|
+
pending: /* @__PURE__ */ new Map(),
|
|
34
|
+
closed: /* @__PURE__ */ new WeakSet(),
|
|
35
|
+
running: false,
|
|
36
|
+
recover: async () => {},
|
|
37
|
+
accepts: (file) => isAbsolute(file) && accepts(file)
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
/** A real host event already schedules compilation; avoid a duplicate fallback. */
|
|
41
|
+
function acknowledgeFailedDependencyChange(context, file) {
|
|
42
|
+
file = normalizeFilePath(file);
|
|
43
|
+
const state = states.get(context);
|
|
44
|
+
if (!state) return;
|
|
45
|
+
const value = failedDependencyVersion(context, file);
|
|
46
|
+
if (value === void 0) return;
|
|
47
|
+
for (const jobs of state.pending.values()) for (const entry of jobs.values()) if (entry.versions.has(file)) entry.versions.set(file, value);
|
|
48
|
+
}
|
|
49
|
+
/** Capture before the compiler reads a dependency, including its missing state. */
|
|
50
|
+
function failedDependencyVersion(context, file) {
|
|
51
|
+
const state = states.get(context);
|
|
52
|
+
if (!state || !isAbsolute(file)) return;
|
|
53
|
+
let stats, value;
|
|
54
|
+
try {
|
|
55
|
+
stats = statSync(file);
|
|
56
|
+
value = version(stats);
|
|
57
|
+
} catch (error) {
|
|
58
|
+
value = missing(error);
|
|
59
|
+
}
|
|
60
|
+
return state.accepts(file, stats) ? value : void 0;
|
|
61
|
+
}
|
|
62
|
+
function trackFailedDependencyReconciliation(context, environment, key, id, versions, recover) {
|
|
63
|
+
const state = states.get(context);
|
|
64
|
+
if (!state || state.closed.has(environment) || !versions.size) return;
|
|
65
|
+
let pending = state.pending.get(environment);
|
|
66
|
+
if (!pending) {
|
|
67
|
+
pending = /* @__PURE__ */ new Map();
|
|
68
|
+
state.pending.set(environment, pending);
|
|
69
|
+
}
|
|
70
|
+
pending.set(key, {
|
|
71
|
+
id,
|
|
72
|
+
versions,
|
|
73
|
+
recover
|
|
74
|
+
});
|
|
75
|
+
schedule(context, state);
|
|
76
|
+
}
|
|
77
|
+
function forgetFailedDependencyReconciliation(context, environment, key) {
|
|
78
|
+
const state = states.get(context), pending = state?.pending.get(environment);
|
|
79
|
+
pending?.delete(key);
|
|
80
|
+
if (!pending?.size) state?.pending.delete(environment);
|
|
81
|
+
if (state && !state.pending.size) {
|
|
82
|
+
clearTimeout(state.timer);
|
|
83
|
+
state.timer = void 0;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
function clearFailedDependencyReconciliation(context, environment) {
|
|
87
|
+
const state = states.get(context);
|
|
88
|
+
if (!state) return;
|
|
89
|
+
if (environment) {
|
|
90
|
+
state.closed.add(environment);
|
|
91
|
+
state.pending.delete(environment);
|
|
92
|
+
} else {
|
|
93
|
+
state.pending.clear();
|
|
94
|
+
states.delete(context);
|
|
95
|
+
}
|
|
96
|
+
if (!state.pending.size) {
|
|
97
|
+
clearTimeout(state.timer);
|
|
98
|
+
state.timer = void 0;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
function schedule(context, state) {
|
|
102
|
+
if (state.timer || state.running || !state.pending.size || states.get(context) !== state) return;
|
|
103
|
+
state.timer = setTimeout(() => {
|
|
104
|
+
state.timer = void 0;
|
|
105
|
+
reconcile(context, state);
|
|
106
|
+
}, 100);
|
|
107
|
+
state.timer.unref();
|
|
108
|
+
}
|
|
109
|
+
async function reconcile(context, state) {
|
|
110
|
+
state.running = true;
|
|
111
|
+
try {
|
|
112
|
+
const jobs = [...state.pending].flatMap(([environment, entries]) => [...entries].map(([key, entry]) => ({
|
|
113
|
+
environment,
|
|
114
|
+
key,
|
|
115
|
+
entry
|
|
116
|
+
})));
|
|
117
|
+
const files = [...new Set(jobs.flatMap(({ entry }) => [...entry.versions.keys()]))];
|
|
118
|
+
const current = new Map(await Promise.all(files.map(async (file) => {
|
|
119
|
+
let stats, value;
|
|
120
|
+
try {
|
|
121
|
+
stats = await stat(file);
|
|
122
|
+
value = version(stats);
|
|
123
|
+
} catch (error) {
|
|
124
|
+
value = missing(error);
|
|
125
|
+
}
|
|
126
|
+
return [file, state.accepts(file, stats) ? value : void 0];
|
|
127
|
+
})));
|
|
128
|
+
for (const { environment, key, entry } of jobs) {
|
|
129
|
+
const active = () => states.get(context) === state && !state.closed.has(environment);
|
|
130
|
+
if (!active() || state.pending.get(environment)?.get(key) !== entry) continue;
|
|
131
|
+
const changed = [];
|
|
132
|
+
for (const [file, before] of entry.versions) {
|
|
133
|
+
const after = current.get(file);
|
|
134
|
+
if (after === void 0) entry.versions.delete(file);
|
|
135
|
+
else if (after !== before) {
|
|
136
|
+
entry.versions.set(file, after);
|
|
137
|
+
changed.push(file);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
if (!entry.versions.size) forgetFailedDependencyReconciliation(context, environment, key);
|
|
141
|
+
if (changed.length) try {
|
|
142
|
+
await (entry.recover ?? state.recover)(environment, entry.id, changed, active);
|
|
143
|
+
} catch {}
|
|
144
|
+
}
|
|
145
|
+
} finally {
|
|
146
|
+
state.running = false;
|
|
147
|
+
schedule(context, state);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
export { acknowledgeFailedDependencyChange, clearFailedDependencyReconciliation, configureBuildDependencyReconciliation, configureFailedDependencyReconciliation, failedDependencyVersion, forgetFailedDependencyReconciliation, trackFailedDependencyReconciliation };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { ViteDevServer } from "vite";
|
|
2
|
+
import { MasterCSSVitePluginContext } from "../core.js";
|
|
3
|
+
import { FailedDependencyRecovery } from "./failed-dependency-reconciliation.js";
|
|
4
|
+
interface DependencyHost {
|
|
5
|
+
environment?: object;
|
|
6
|
+
addWatchFile?(file: string): void;
|
|
7
|
+
}
|
|
8
|
+
declare function configureStylesheetRecovery(context: MasterCSSVitePluginContext, watcher: ViteDevServer['watcher']): void;
|
|
9
|
+
/** Keep current host dependencies without retaining Vite CSS file-only graph edges. */
|
|
10
|
+
declare function withStylesheetDependencies<T>(context: MasterCSSVitePluginContext, host: DependencyHost, id: string, operation: (onDependency: (file: string) => void) => Promise<T>, scope?: string, recover?: FailedDependencyRecovery): Promise<T>;
|
|
11
|
+
declare function stylesheetDependencyOwners(context: MasterCSSVitePluginContext, environment: object, file: string): {
|
|
12
|
+
id: string;
|
|
13
|
+
failed: boolean;
|
|
14
|
+
}[];
|
|
15
|
+
declare function clearFailedStylesheets(context: MasterCSSVitePluginContext, environment?: object): void;
|
|
16
|
+
export { DependencyHost, clearFailedStylesheets, configureStylesheetRecovery, stylesheetDependencyOwners, withStylesheetDependencies };
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { normalizeFilePath } from "./path.js";
|
|
2
|
+
import { clearFailedDependencyReconciliation, failedDependencyVersion, forgetFailedDependencyReconciliation, trackFailedDependencyReconciliation } from "./failed-dependency-reconciliation.js";
|
|
3
|
+
import { trackBuildStylesheetRecovery } from "./build-watch-recovery.js";
|
|
4
|
+
import { existsSync } from "node:fs";
|
|
5
|
+
import { dirname, isAbsolute } from "node:path";
|
|
6
|
+
// src/utils/failed-stylesheet-dependencies.ts
|
|
7
|
+
const watchers = /* @__PURE__ */ new WeakMap();
|
|
8
|
+
function configureStylesheetRecovery(context, watcher) {
|
|
9
|
+
failures.delete(context);
|
|
10
|
+
watchers.set(context, watcher);
|
|
11
|
+
}
|
|
12
|
+
function watchDependency(context, file) {
|
|
13
|
+
if (!isAbsolute(file)) return;
|
|
14
|
+
let watchedPath = file;
|
|
15
|
+
while (!existsSync(watchedPath)) {
|
|
16
|
+
const parent = dirname(watchedPath);
|
|
17
|
+
if (parent === watchedPath) break;
|
|
18
|
+
watchedPath = parent;
|
|
19
|
+
}
|
|
20
|
+
watchers.get(context)?.add(watchedPath);
|
|
21
|
+
}
|
|
22
|
+
const failures = /* @__PURE__ */ new WeakMap();
|
|
23
|
+
function forEnvironment(context, environment) {
|
|
24
|
+
let environments = failures.get(context);
|
|
25
|
+
if (!environments) {
|
|
26
|
+
environments = /* @__PURE__ */ new WeakMap();
|
|
27
|
+
failures.set(context, environments);
|
|
28
|
+
}
|
|
29
|
+
let modules = environments.get(environment);
|
|
30
|
+
if (!modules) {
|
|
31
|
+
modules = /* @__PURE__ */ new Map();
|
|
32
|
+
environments.set(environment, modules);
|
|
33
|
+
}
|
|
34
|
+
return modules;
|
|
35
|
+
}
|
|
36
|
+
/** Keep current host dependencies without retaining Vite CSS file-only graph edges. */
|
|
37
|
+
async function withStylesheetDependencies(context, host, id, operation, scope = "local", recover) {
|
|
38
|
+
const key = `${scope}:${id}`;
|
|
39
|
+
const dependencies = /* @__PURE__ */ new Set();
|
|
40
|
+
const modules = host.environment && context.config?.command === "serve" ? forEnvironment(context, host.environment) : void 0;
|
|
41
|
+
const versions = /* @__PURE__ */ new Map();
|
|
42
|
+
const buildRecovery = context.config?.command === "build" && Boolean(context.config.build?.watch);
|
|
43
|
+
const environment = host.environment ?? context;
|
|
44
|
+
if (modules || buildRecovery) forgetFailedDependencyReconciliation(context, environment, key);
|
|
45
|
+
try {
|
|
46
|
+
const result = await operation((file) => {
|
|
47
|
+
if (file.includes("\0")) return;
|
|
48
|
+
file = normalizeFilePath(file);
|
|
49
|
+
if ((modules || buildRecovery) && !dependencies.has(file)) {
|
|
50
|
+
const version = failedDependencyVersion(context, file);
|
|
51
|
+
if (version !== void 0) versions.set(file, version);
|
|
52
|
+
}
|
|
53
|
+
dependencies.add(file);
|
|
54
|
+
if (modules && watchers.has(context)) watchDependency(context, file);
|
|
55
|
+
else host.addWatchFile?.(file);
|
|
56
|
+
});
|
|
57
|
+
if (modules && dependencies.size) modules.set(key, {
|
|
58
|
+
id,
|
|
59
|
+
dependencies,
|
|
60
|
+
failed: false
|
|
61
|
+
});
|
|
62
|
+
else modules?.delete(key);
|
|
63
|
+
return result;
|
|
64
|
+
} catch (error) {
|
|
65
|
+
if (modules && dependencies.size) {
|
|
66
|
+
modules.set(key, {
|
|
67
|
+
id,
|
|
68
|
+
dependencies,
|
|
69
|
+
failed: true
|
|
70
|
+
});
|
|
71
|
+
trackFailedDependencyReconciliation(context, host.environment, key, id, versions, recover);
|
|
72
|
+
for (const file of dependencies) watchDependency(context, file);
|
|
73
|
+
}
|
|
74
|
+
if (buildRecovery) trackBuildStylesheetRecovery(context, host, key, id, versions);
|
|
75
|
+
throw error;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
function stylesheetDependencyOwners(context, environment, file) {
|
|
79
|
+
file = normalizeFilePath(file);
|
|
80
|
+
const owners = /* @__PURE__ */ new Map();
|
|
81
|
+
for (const entry of failures.get(context)?.get(environment)?.values() ?? []) if (entry.dependencies.has(file)) owners.set(entry.id, {
|
|
82
|
+
id: entry.id,
|
|
83
|
+
failed: entry.failed || Boolean(owners.get(entry.id)?.failed)
|
|
84
|
+
});
|
|
85
|
+
return [...owners.values()];
|
|
86
|
+
}
|
|
87
|
+
function clearFailedStylesheets(context, environment) {
|
|
88
|
+
clearFailedDependencyReconciliation(context, environment);
|
|
89
|
+
if (environment) failures.get(context)?.delete(environment);
|
|
90
|
+
else failures.delete(context);
|
|
91
|
+
}
|
|
92
|
+
export { clearFailedStylesheets, configureStylesheetRecovery, stylesheetDependencyOwners, withStylesheetDependencies };
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
declare function escapeRegExp(source: string): string;
|
|
2
|
+
declare function toAssetHref(fileName: string, base?: string, htmlPath?: string): string;
|
|
3
|
+
declare function hasModulePreloadLink(html: string, href: string, options?: {
|
|
4
|
+
as?: string;
|
|
5
|
+
}): boolean;
|
|
6
|
+
/** A `<link rel="preload" as="fetch">` without a type, as runtime programs use. */
|
|
7
|
+
declare function hasFetchPreloadLink(html: string, href: string): boolean;
|
|
8
|
+
export { escapeRegExp, hasFetchPreloadLink, hasModulePreloadLink, toAssetHref };
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
// src/utils/html.ts
|
|
2
|
+
function splitPathSegments(path) {
|
|
3
|
+
return path.split("/").filter(Boolean);
|
|
4
|
+
}
|
|
5
|
+
function getHTMLDirectorySegments(path = "/index.html") {
|
|
6
|
+
const cleanPath = path.split(/[?#]/)[0] || "/index.html";
|
|
7
|
+
const segments = splitPathSegments(cleanPath);
|
|
8
|
+
if (!cleanPath.endsWith("/")) segments.pop();
|
|
9
|
+
return segments;
|
|
10
|
+
}
|
|
11
|
+
function toRelativeAssetHref(fileName, htmlPath) {
|
|
12
|
+
const fromSegments = getHTMLDirectorySegments(htmlPath);
|
|
13
|
+
const toSegments = splitPathSegments(fileName);
|
|
14
|
+
let common = 0;
|
|
15
|
+
while (common < fromSegments.length && common < toSegments.length && fromSegments[common] === toSegments[common]) common += 1;
|
|
16
|
+
return [...Array.from({ length: fromSegments.length - common }, () => ".."), ...toSegments.slice(common)].join("/") || ".";
|
|
17
|
+
}
|
|
18
|
+
function escapeRegExp(source) {
|
|
19
|
+
return source.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
20
|
+
}
|
|
21
|
+
function toAssetHref(fileName, base = "/", htmlPath) {
|
|
22
|
+
const normalizedFileName = fileName.replace(/^\/+/, "");
|
|
23
|
+
if (base && base !== "./") return `${base.replace(/\/?$/, "/")}${normalizedFileName}`;
|
|
24
|
+
return toRelativeAssetHref(normalizedFileName, htmlPath);
|
|
25
|
+
}
|
|
26
|
+
function hasModulePreloadLink(html, href, options) {
|
|
27
|
+
const quotedHref = escapeRegExp(href);
|
|
28
|
+
const asPattern = options?.as ? String.raw`(?=[^>]*\bas=(?:"${escapeRegExp(options.as)}"|'${escapeRegExp(options.as)}'))` : "";
|
|
29
|
+
return new RegExp(String.raw`<link\b(?=[^>]*\brel=(?:"modulepreload"|'modulepreload'))${asPattern}(?=[^>]*\bhref=(?:"${quotedHref}"|'${quotedHref}'))[^>]*>`, "i").test(html);
|
|
30
|
+
}
|
|
31
|
+
/** A `<link rel="preload" as="fetch">` without a type, as runtime programs use. */
|
|
32
|
+
function hasFetchPreloadLink(html, href) {
|
|
33
|
+
const quotedHref = escapeRegExp(href);
|
|
34
|
+
return new RegExp(String.raw`<link\b(?=[^>]*\brel=(?:"preload"|'preload'))(?=[^>]*\bas=(?:"fetch"|'fetch'))(?=[^>]*\bhref=(?:"${quotedHref}"|'${quotedHref}'))[^>]*>`, "i").test(html);
|
|
35
|
+
}
|
|
36
|
+
export { escapeRegExp, hasFetchPreloadLink, hasModulePreloadLink, toAssetHref };
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { ResolvedConfig } from "vite";
|
|
2
|
+
import { MasterCSSStylesheetCollection, MasterCSSStylesheetDeliveryOptions, MasterCSSStylesheetTransformResult } from "@master/css-compiler/stylesheet";
|
|
3
|
+
import { MasterCSSVitePluginContext } from "../core.js";
|
|
4
|
+
interface InlineStylesheet {
|
|
5
|
+
collection: MasterCSSStylesheetCollection;
|
|
6
|
+
local?: MasterCSSStylesheetTransformResult;
|
|
7
|
+
token: string;
|
|
8
|
+
reference?: string;
|
|
9
|
+
css?: string;
|
|
10
|
+
urlMarker?: string;
|
|
11
|
+
files?: Map<string, string>;
|
|
12
|
+
}
|
|
13
|
+
declare const INLINE_URL_BASE = "https://master-css-inline.invalid/";
|
|
14
|
+
declare function inlineDigest(value: string): string;
|
|
15
|
+
declare function isInlineStylesheet(id: string): boolean;
|
|
16
|
+
declare function inlineStylesheets(context: MasterCSSVitePluginContext): Map<string, InlineStylesheet>;
|
|
17
|
+
declare function disposeInlineStylesheets(context: MasterCSSVitePluginContext): void;
|
|
18
|
+
declare function inlineDelivery(context: MasterCSSVitePluginContext): MasterCSSStylesheetDeliveryOptions;
|
|
19
|
+
declare function registerInlineStylesheet(context: MasterCSSVitePluginContext, id: string, source: string, host: Pick<MasterCSSStylesheetDeliveryOptions, 'resolveImport' | 'onDependency'>): Promise<import("@master/css-compiler").MasterCSSCompileResult>;
|
|
20
|
+
declare function registerLocalInlineStylesheet(context: MasterCSSVitePluginContext, id: string, local: MasterCSSStylesheetTransformResult): void;
|
|
21
|
+
/** Return resource/import references using the compiler's source analysis. */
|
|
22
|
+
declare function inlineURLReferences(compiler: import('@master/css-compiler').MasterCSSCompiler, css: string): {
|
|
23
|
+
readonly start: number;
|
|
24
|
+
readonly end: number;
|
|
25
|
+
readonly url: string;
|
|
26
|
+
}[];
|
|
27
|
+
/** Rewrite host-issued URLs only at Rust-reported resource/import ranges. */
|
|
28
|
+
declare function rewriteInlineURLs(compiler: import('@master/css-compiler').MasterCSSCompiler, css: string, target: (url: string) => string, ownedURLs: ReadonlySet<string>): string;
|
|
29
|
+
/** Apply Vite's public output URL hook to the actual referenced file. */
|
|
30
|
+
declare function inlineBuiltURL(config: Pick<ResolvedConfig, 'base' | 'experimental'>, ssr: boolean, filename: string, hostId: string, hostType: 'js' | 'css'): {
|
|
31
|
+
url: string;
|
|
32
|
+
} | {
|
|
33
|
+
runtime: string;
|
|
34
|
+
} | {
|
|
35
|
+
relative: true;
|
|
36
|
+
};
|
|
37
|
+
export { INLINE_URL_BASE, InlineStylesheet, disposeInlineStylesheets, inlineBuiltURL, inlineDelivery, inlineDigest, inlineStylesheets, inlineURLReferences, isInlineStylesheet, registerInlineStylesheet, registerLocalInlineStylesheet, rewriteInlineURLs };
|