@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,26 @@
|
|
|
1
|
+
import { acknowledgeFailedDependencyChange, configureBuildDependencyReconciliation } from "../utils/failed-dependency-reconciliation.js";
|
|
2
|
+
import { closeBuildStylesheetRecovery, prepareBuildStylesheetRecovery } from "../utils/build-watch-recovery.js";
|
|
3
|
+
// src/plugins/build-stylesheet-recovery.ts
|
|
4
|
+
/** Recover failed watch builds without changing authored files or dependency data. */
|
|
5
|
+
function BuildStylesheetRecoveryPlugin(context) {
|
|
6
|
+
return {
|
|
7
|
+
name: "master-css:build-stylesheet-recovery",
|
|
8
|
+
apply: "build",
|
|
9
|
+
enforce: "pre",
|
|
10
|
+
configResolved(config) {
|
|
11
|
+
if (config.build?.watch) prepareBuildStylesheetRecovery(context, config.root, config.cacheDir, config.build.watch);
|
|
12
|
+
},
|
|
13
|
+
buildStart() {
|
|
14
|
+
if (!context.config?.build?.watch) return;
|
|
15
|
+
prepareBuildStylesheetRecovery(context, context.config.root, context.config.cacheDir, context.config.build.watch, this.environment ?? context);
|
|
16
|
+
configureBuildDependencyReconciliation(context, context.config.build.watch);
|
|
17
|
+
},
|
|
18
|
+
watchChange(id) {
|
|
19
|
+
acknowledgeFailedDependencyChange(context, id);
|
|
20
|
+
},
|
|
21
|
+
closeWatcher() {
|
|
22
|
+
closeBuildStylesheetRecovery(context, this.environment ?? context);
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
export { BuildStylesheetRecoveryPlugin as default };
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { Plugin } from "vite";
|
|
2
|
+
import { ResolvedMasterCSSVitePluginOptions } from "../options.js";
|
|
3
|
+
import { MasterCSSVitePluginContext } from "../core.js";
|
|
4
|
+
declare function ContextPlugin(options: ResolvedMasterCSSVitePluginOptions, context: MasterCSSVitePluginContext): Plugin;
|
|
5
|
+
export { ContextPlugin as default };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// src/plugins/context.ts
|
|
2
|
+
function ContextPlugin(options, context) {
|
|
3
|
+
return {
|
|
4
|
+
name: "master-css:context",
|
|
5
|
+
enforce: "pre",
|
|
6
|
+
configResolved(config) {
|
|
7
|
+
context.config = config;
|
|
8
|
+
if (process.env.DEBUG) console.log(`[@master/css-vite] mode: ${options.mode}`);
|
|
9
|
+
}
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
export { ContextPlugin as default };
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { normalizeFilePath } from "../utils/path.js";
|
|
2
|
+
import { releaseScannerEnvironment } from "../utils/scanner-context.js";
|
|
3
|
+
import { toAssetHref } from "../utils/html.js";
|
|
4
|
+
import { clearDevStylesheets, devStylesheetState } from "../utils/dev-stylesheet-delivery.js";
|
|
5
|
+
import { relative } from "node:path";
|
|
6
|
+
import { isFileLoadingAllowed, normalizePath } from "vite";
|
|
7
|
+
import MagicString from "magic-string";
|
|
8
|
+
// src/plugins/dev-stylesheet.ts
|
|
9
|
+
function DevStylesheetPlugin(context) {
|
|
10
|
+
return {
|
|
11
|
+
name: "master-css:dev-stylesheet",
|
|
12
|
+
apply: "serve",
|
|
13
|
+
enforce: "post",
|
|
14
|
+
configureServer(server) {
|
|
15
|
+
server.middlewares.use((request, response, next) => {
|
|
16
|
+
const state = devStylesheetState(context);
|
|
17
|
+
const url = new URL(request.url ?? "/", "http://localhost");
|
|
18
|
+
if (!url.pathname.startsWith(state.prefix)) return next();
|
|
19
|
+
const css = state.stylesheets.get(url.pathname);
|
|
20
|
+
if (css !== void 0) {
|
|
21
|
+
response.setHeader("Content-Type", "text/css");
|
|
22
|
+
response.setHeader("Cache-Control", "no-store");
|
|
23
|
+
response.end(css);
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
const resource = state.resources.get(url.pathname);
|
|
27
|
+
if (resource) {
|
|
28
|
+
const source = normalizeFilePath(resource.source);
|
|
29
|
+
if (!server.config.server.fs.allow.includes(source)) server.config.server.fs.allow.push(source);
|
|
30
|
+
if (!isFileLoadingAllowed(server.config, source)) {
|
|
31
|
+
response.statusCode = 403;
|
|
32
|
+
response.end("Development resource access denied");
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
const file = normalizePath(resource.file);
|
|
36
|
+
if (!server.config.server.fs.allow.includes(file)) server.config.server.fs.allow.push(file);
|
|
37
|
+
const path = normalizePath(relative(normalizeFilePath(server.config.root), file));
|
|
38
|
+
const encodedPath = encodeURI(path).replace(/[?#]/g, encodeURIComponent);
|
|
39
|
+
request.url = toAssetHref(encodedPath, server.config.base) + url.search;
|
|
40
|
+
next();
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
response.statusCode = 404;
|
|
44
|
+
response.end("Unknown development stylesheet asset");
|
|
45
|
+
});
|
|
46
|
+
},
|
|
47
|
+
transform(code) {
|
|
48
|
+
const { origin } = devStylesheetState(context);
|
|
49
|
+
if (!code.includes(origin)) return;
|
|
50
|
+
const output = new MagicString(code);
|
|
51
|
+
for (const match of code.matchAll(new RegExp(origin.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), "g"))) output.remove(match.index, match.index + origin.length);
|
|
52
|
+
return {
|
|
53
|
+
code: output.toString(),
|
|
54
|
+
map: output.generateMap({ hires: true })
|
|
55
|
+
};
|
|
56
|
+
},
|
|
57
|
+
closeBundle() {
|
|
58
|
+
const config = this.environment?.getTopLevelConfig() ?? context.config;
|
|
59
|
+
if (releaseScannerEnvironment(context, config, this.environment)) clearDevStylesheets(context);
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
export { DevStylesheetPlugin as default };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Environment, Plugin } from "vite";
|
|
2
|
+
import { MasterCSSEmittedGlobals } from "@master/css-schema/emitted-globals";
|
|
3
|
+
import { MasterCSSVitePluginContext } from "../core.js";
|
|
4
|
+
/**
|
|
5
|
+
* The plugin's `api`, shared by every configuration that one plugin instance
|
|
6
|
+
* resolves. Adapters whose build links one environment's stylesheets on pages
|
|
7
|
+
* that load another environment's bundle set `finalize`.
|
|
8
|
+
*/
|
|
9
|
+
interface EmittedGlobalsPluginAPI {
|
|
10
|
+
/** Receives each build environment's emitted globals as its output renders and returns the ones that output carries. */
|
|
11
|
+
finalize?: (environment: Environment, emittedGlobals: Required<MasterCSSEmittedGlobals>) => MasterCSSEmittedGlobals;
|
|
12
|
+
}
|
|
13
|
+
declare function EmittedGlobalsVirtualModulePlugin(context: MasterCSSVitePluginContext, api?: EmittedGlobalsPluginAPI): Plugin;
|
|
14
|
+
export { EmittedGlobalsPluginAPI, EmittedGlobalsVirtualModulePlugin as default };
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import { normalizeEmittedGlobals, toEmittedGlobalsModule } from "../internal/src/emitted-globals-module.js";
|
|
2
|
+
import { RESOLVED_VIRTUAL_EMITTED_GLOBALS_ID, VIRTUAL_EMITTED_GLOBALS_ID } from "../common.js";
|
|
3
|
+
import { getExtractedCSSResult } from "../utils/extracted-css.js";
|
|
4
|
+
import { registerStylesheetSource } from "../utils/register-style-source.js";
|
|
5
|
+
import { refreshGeneratedModule } from "../utils/dev-module-refresh.js";
|
|
6
|
+
import { createCoalescedTask } from "../utils/coalesced-task.js";
|
|
7
|
+
import { discoverManifestEntries } from "@master/css-compiler/project";
|
|
8
|
+
import { readFile } from "node:fs/promises";
|
|
9
|
+
import MagicString from "magic-string";
|
|
10
|
+
// src/plugins/emitted-globals-virtual-module.ts
|
|
11
|
+
function toServerDevEmittedGlobalsModule(emittedGlobals) {
|
|
12
|
+
return [
|
|
13
|
+
"const emittedGlobals = import.meta.hot?.data.emittedGlobals ?? {};",
|
|
14
|
+
"for (const key of Object.keys(emittedGlobals)) delete emittedGlobals[key];",
|
|
15
|
+
`Object.assign(emittedGlobals, ${JSON.stringify(normalizeEmittedGlobals(emittedGlobals))});`,
|
|
16
|
+
"if (import.meta.hot) {",
|
|
17
|
+
" import.meta.hot.data.emittedGlobals = emittedGlobals;",
|
|
18
|
+
" import.meta.hot.accept();",
|
|
19
|
+
"}",
|
|
20
|
+
"export default emittedGlobals;"
|
|
21
|
+
].join("\n");
|
|
22
|
+
}
|
|
23
|
+
function EmittedGlobalsVirtualModulePlugin(context, api = {}) {
|
|
24
|
+
const placeholder = "__MASTER_CSS_FINAL_EMITTED_GLOBALS__";
|
|
25
|
+
let finalGlobals;
|
|
26
|
+
let dev;
|
|
27
|
+
const signature = (value) => JSON.stringify(normalizeEmittedGlobals(value), (_key, item) => {
|
|
28
|
+
if (!item || typeof item !== "object" || Array.isArray(item)) return item;
|
|
29
|
+
return Object.fromEntries(Object.entries(item).sort(([a], [b]) => a.localeCompare(b)));
|
|
30
|
+
});
|
|
31
|
+
return {
|
|
32
|
+
name: "master-css:virtual-module:emitted-globals",
|
|
33
|
+
enforce: "pre",
|
|
34
|
+
api,
|
|
35
|
+
configureServer(server) {
|
|
36
|
+
if (dev) for (const environment of dev.lifetimes.keys()) dev.closeEnvironment(environment);
|
|
37
|
+
const config = server.config;
|
|
38
|
+
let closed = false;
|
|
39
|
+
const served = /* @__PURE__ */ new Map();
|
|
40
|
+
const loading = /* @__PURE__ */ new Set();
|
|
41
|
+
const lifetimes = /* @__PURE__ */ new Map();
|
|
42
|
+
const closedEnvironments = /* @__PURE__ */ new WeakSet();
|
|
43
|
+
const active = () => !closed && dev === state && server.config === config;
|
|
44
|
+
const onError = (error) => {
|
|
45
|
+
if (active()) server.config.logger.error(String(error));
|
|
46
|
+
};
|
|
47
|
+
const publish = createCoalescedTask(async () => {
|
|
48
|
+
if (!active() || !context.emittedGlobals) return;
|
|
49
|
+
const next = signature(context.emittedGlobals);
|
|
50
|
+
const previous = /* @__PURE__ */ new Map();
|
|
51
|
+
try {
|
|
52
|
+
await refreshGeneratedModule(server, RESOLVED_VIRTUAL_EMITTED_GLOBALS_ID, (environment) => {
|
|
53
|
+
if (loading.has(environment) || !served.has(environment) || served.get(environment) === next) return false;
|
|
54
|
+
previous.set(environment, served.get(environment));
|
|
55
|
+
served.set(environment, next);
|
|
56
|
+
return true;
|
|
57
|
+
});
|
|
58
|
+
} catch (error) {
|
|
59
|
+
for (const [environment, signature] of previous) if (served.get(environment) === next) served.set(environment, signature);
|
|
60
|
+
throw error;
|
|
61
|
+
}
|
|
62
|
+
}, onError);
|
|
63
|
+
const state = dev = {
|
|
64
|
+
active,
|
|
65
|
+
served,
|
|
66
|
+
loading,
|
|
67
|
+
lifetimes,
|
|
68
|
+
closedEnvironments,
|
|
69
|
+
publish,
|
|
70
|
+
closeEnvironment(environment) {
|
|
71
|
+
served.delete(environment);
|
|
72
|
+
loading.delete(environment);
|
|
73
|
+
closedEnvironments.add(environment);
|
|
74
|
+
lifetimes.get(environment)?.close();
|
|
75
|
+
lifetimes.delete(environment);
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
context.onEmittedGlobalsChange = () => {
|
|
79
|
+
publish();
|
|
80
|
+
};
|
|
81
|
+
context.refreshEmittedGlobals = createCoalescedTask(async () => {
|
|
82
|
+
if (!active() || !served.size) return;
|
|
83
|
+
await Promise.all(Object.values(server.environments).filter((environment) => served.has(environment)).map((environment) => Promise.race([environment.waitForRequestsIdle(), lifetimes.get(environment).promise])));
|
|
84
|
+
if (!active() || !served.size) return;
|
|
85
|
+
await getExtractedCSSResult(context);
|
|
86
|
+
await publish();
|
|
87
|
+
}, onError);
|
|
88
|
+
server.httpServer?.once("close", () => {
|
|
89
|
+
closed = true;
|
|
90
|
+
for (const environment of lifetimes.keys()) state.closeEnvironment(environment);
|
|
91
|
+
});
|
|
92
|
+
},
|
|
93
|
+
async resolveId(id) {
|
|
94
|
+
if (id === VIRTUAL_EMITTED_GLOBALS_ID) return RESOLVED_VIRTUAL_EMITTED_GLOBALS_ID;
|
|
95
|
+
},
|
|
96
|
+
async load(id) {
|
|
97
|
+
if (id !== RESOLVED_VIRTUAL_EMITTED_GLOBALS_ID) return;
|
|
98
|
+
if (context.config?.command === "build") return `export default JSON.parse(${JSON.stringify(placeholder)});`;
|
|
99
|
+
const environment = this.environment;
|
|
100
|
+
const state = context.config?.command === "serve" && dev?.active() && !dev.closedEnvironments.has(environment) ? dev : void 0;
|
|
101
|
+
let lifetime;
|
|
102
|
+
if (state) {
|
|
103
|
+
lifetime = state.lifetimes.get(environment);
|
|
104
|
+
if (!lifetime) {
|
|
105
|
+
let close;
|
|
106
|
+
lifetime = {
|
|
107
|
+
promise: new Promise((resolve) => {
|
|
108
|
+
close = resolve;
|
|
109
|
+
}),
|
|
110
|
+
close
|
|
111
|
+
};
|
|
112
|
+
state.lifetimes.set(environment, lifetime);
|
|
113
|
+
}
|
|
114
|
+
state.loading.add(environment);
|
|
115
|
+
}
|
|
116
|
+
try {
|
|
117
|
+
if (state) {
|
|
118
|
+
state.initialStylesheets ??= (async () => {
|
|
119
|
+
const entries = await discoverManifestEntries({ root: context.config?.root });
|
|
120
|
+
for (const entry of entries) {
|
|
121
|
+
if (context.stylesheets?.snapshot().sourceIds.includes(entry)) continue;
|
|
122
|
+
await registerStylesheetSource(context, entry, await readFile(entry, "utf8"));
|
|
123
|
+
}
|
|
124
|
+
})().catch((error) => {
|
|
125
|
+
state.initialStylesheets = void 0;
|
|
126
|
+
throw error;
|
|
127
|
+
});
|
|
128
|
+
await state.initialStylesheets;
|
|
129
|
+
}
|
|
130
|
+
const result = await getExtractedCSSResult(context);
|
|
131
|
+
const globals = context.emittedGlobals ?? result.emittedGlobals;
|
|
132
|
+
if (state?.active() && state.lifetimes.get(environment) === lifetime) state.served.set(environment, signature(globals));
|
|
133
|
+
if (state && environment.config.consumer === "server") return toServerDevEmittedGlobalsModule(globals);
|
|
134
|
+
return toEmittedGlobalsModule(globals);
|
|
135
|
+
} finally {
|
|
136
|
+
if (state && state.lifetimes.get(environment) === lifetime) {
|
|
137
|
+
state.loading.delete(environment);
|
|
138
|
+
state.publish();
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
},
|
|
142
|
+
closeBundle() {
|
|
143
|
+
dev?.closeEnvironment(this.environment);
|
|
144
|
+
},
|
|
145
|
+
shouldTransformCachedModule({ id }) {
|
|
146
|
+
return id === RESOLVED_VIRTUAL_EMITTED_GLOBALS_ID;
|
|
147
|
+
},
|
|
148
|
+
renderStart: {
|
|
149
|
+
order: "post",
|
|
150
|
+
async handler() {
|
|
151
|
+
if (context.config?.command !== "build") return;
|
|
152
|
+
const { emittedGlobals } = await getExtractedCSSResult(context);
|
|
153
|
+
finalGlobals = JSON.stringify(api.finalize ? normalizeEmittedGlobals(api.finalize(this.environment, emittedGlobals)) : emittedGlobals);
|
|
154
|
+
}
|
|
155
|
+
},
|
|
156
|
+
renderChunk(code) {
|
|
157
|
+
if (finalGlobals === void 0 || !code.includes(placeholder)) return;
|
|
158
|
+
const output = new MagicString(code);
|
|
159
|
+
for (const match of code.matchAll(new RegExp(`(["'])${placeholder}\\1`, "g"))) output.overwrite(match.index, match.index + match[0].length, JSON.stringify(finalGlobals));
|
|
160
|
+
return {
|
|
161
|
+
code: output.toString(),
|
|
162
|
+
map: output.generateMap({ hires: true })
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
export { EmittedGlobalsVirtualModulePlugin as default };
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { Plugin } from "vite";
|
|
2
|
+
import { ResolvedMasterCSSVitePluginOptions } from "../options.js";
|
|
3
|
+
declare function InjectRuntimePlugin(_options: ResolvedMasterCSSVitePluginOptions): Plugin;
|
|
4
|
+
declare function InjectRuntimeServePlugin(_options: ResolvedMasterCSSVitePluginOptions): Plugin;
|
|
5
|
+
export { InjectRuntimeServePlugin, InjectRuntimePlugin as default };
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { DEV_RUNTIME_ENTRY_ID, RUNTIME_ENTRY_ID } from "../common.js";
|
|
2
|
+
import { toAssetHref } from "../utils/html.js";
|
|
3
|
+
// src/plugins/inject-runtime.ts
|
|
4
|
+
function InjectRuntimePlugin(_options) {
|
|
5
|
+
return {
|
|
6
|
+
name: "master-css:inject-runtime",
|
|
7
|
+
enforce: "pre",
|
|
8
|
+
apply: "build",
|
|
9
|
+
transformIndexHtml: {
|
|
10
|
+
order: "pre",
|
|
11
|
+
handler(html) {
|
|
12
|
+
if (html.includes(RUNTIME_ENTRY_ID) || html.includes(DEV_RUNTIME_ENTRY_ID)) return;
|
|
13
|
+
return {
|
|
14
|
+
html,
|
|
15
|
+
tags: [{
|
|
16
|
+
tag: "script",
|
|
17
|
+
attrs: {
|
|
18
|
+
type: "module",
|
|
19
|
+
src: RUNTIME_ENTRY_ID
|
|
20
|
+
},
|
|
21
|
+
injectTo: "body"
|
|
22
|
+
}]
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
function InjectRuntimeServePlugin(_options) {
|
|
29
|
+
return {
|
|
30
|
+
name: "master-css:inject-runtime:serve",
|
|
31
|
+
apply: "serve",
|
|
32
|
+
transformIndexHtml: {
|
|
33
|
+
order: "post",
|
|
34
|
+
handler(html, htmlContext) {
|
|
35
|
+
if (html.includes(RUNTIME_ENTRY_ID) || html.includes(DEV_RUNTIME_ENTRY_ID)) return;
|
|
36
|
+
return {
|
|
37
|
+
html,
|
|
38
|
+
tags: [{
|
|
39
|
+
tag: "script",
|
|
40
|
+
attrs: {
|
|
41
|
+
type: "module",
|
|
42
|
+
src: toAssetHref(DEV_RUNTIME_ENTRY_ID, htmlContext.server?.config?.base, htmlContext.path)
|
|
43
|
+
},
|
|
44
|
+
injectTo: "body"
|
|
45
|
+
}]
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
export { InjectRuntimeServePlugin, InjectRuntimePlugin as default };
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { Plugin } from "vite";
|
|
2
|
+
import { MasterCSSVitePluginContext } from "../core.js";
|
|
3
|
+
/** Export managed CSS as a string without registering an automatic stylesheet. */
|
|
4
|
+
declare function InlineStylesheetPlugin(context: MasterCSSVitePluginContext): Plugin;
|
|
5
|
+
export { InlineStylesheetPlugin as default };
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
import { withSassDiagnostics } from "../utils/sass-diagnostics.js";
|
|
2
|
+
import { getScanner } from "../utils/scanner-context.js";
|
|
3
|
+
import { INLINE_URL_BASE, disposeInlineStylesheets, inlineBuiltURL, inlineDelivery, inlineDigest, inlineStylesheets, inlineURLReferences, isInlineStylesheet, rewriteInlineURLs } from "../utils/inline-stylesheet.js";
|
|
4
|
+
import { readFileSync } from "node:fs";
|
|
5
|
+
import { posix } from "node:path";
|
|
6
|
+
import { createCompilerSync } from "@master/css-compiler/node";
|
|
7
|
+
import MagicString from "magic-string";
|
|
8
|
+
// src/plugins/inline-stylesheet.ts
|
|
9
|
+
const configuredBaseKey = Symbol("master-css:configured-inline-divider");
|
|
10
|
+
/** Export managed CSS as a string without registering an automatic stylesheet. */
|
|
11
|
+
function InlineStylesheetPlugin(context) {
|
|
12
|
+
const pending = /* @__PURE__ */ new Map();
|
|
13
|
+
const used = /* @__PURE__ */ new Set();
|
|
14
|
+
return {
|
|
15
|
+
name: "master-css:inline-stylesheet",
|
|
16
|
+
enforce: "post",
|
|
17
|
+
apply: "build",
|
|
18
|
+
config: {
|
|
19
|
+
order: "post",
|
|
20
|
+
handler(config) {
|
|
21
|
+
Reflect.set(config, configuredBaseKey, config.base);
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
shouldTransformCachedModule({ id }) {
|
|
25
|
+
if (isInlineStylesheet(id) && /\.(?:css|scss|sass)(?:[?#].*)?$/i.test(id)) return true;
|
|
26
|
+
},
|
|
27
|
+
transform(_code, id) {
|
|
28
|
+
const entry = inlineStylesheets(context).get(id);
|
|
29
|
+
if (!entry) return;
|
|
30
|
+
entry.reference = this.emitFile({
|
|
31
|
+
type: "asset",
|
|
32
|
+
name: "master-css-inline-divider.css",
|
|
33
|
+
source: "/* Master CSS inline asset base. */"
|
|
34
|
+
});
|
|
35
|
+
if (this.environment.config.consumer === "server") return {
|
|
36
|
+
code: `export default ${JSON.stringify(entry.token)}`,
|
|
37
|
+
map: null
|
|
38
|
+
};
|
|
39
|
+
return {
|
|
40
|
+
code: `export default ${JSON.stringify(entry.token)}.replaceAll(${JSON.stringify(entry.token + "_URL")}, new URL('.', import.meta.ROLLUP_FILE_URL_${entry.reference}).href)`,
|
|
41
|
+
map: null
|
|
42
|
+
};
|
|
43
|
+
},
|
|
44
|
+
resolveFileUrl({ referenceId, relativePath, format }) {
|
|
45
|
+
if (![...inlineStylesheets(context).values()].some((entry) => entry.reference === referenceId)) return;
|
|
46
|
+
if (format === "iife" || format === "umd") return `new URL(${JSON.stringify(relativePath)}, (typeof document === "undefined" ? (typeof location === "undefined" ? require("node:url").pathToFileURL(__filename).href : location.href) : document.currentScript?.src || document.baseURI)).href`;
|
|
47
|
+
if (format === "cjs") return `new URL(${JSON.stringify(relativePath)}, require("node:url").pathToFileURL(__filename).href).href`;
|
|
48
|
+
},
|
|
49
|
+
async renderStart() {
|
|
50
|
+
pending.clear();
|
|
51
|
+
used.clear();
|
|
52
|
+
const scanner = getScanner(context);
|
|
53
|
+
using compiler = createCompilerSync();
|
|
54
|
+
for (const entry of inlineStylesheets(context).values()) {
|
|
55
|
+
if (!entry.reference) continue;
|
|
56
|
+
const result = entry.local ? {
|
|
57
|
+
...entry.local,
|
|
58
|
+
css: entry.local.code
|
|
59
|
+
} : await withSassDiagnostics(context, () => entry.collection.compose({
|
|
60
|
+
scanner,
|
|
61
|
+
baseManifest: scanner.css.manifest,
|
|
62
|
+
projectDir: context.config?.root,
|
|
63
|
+
pruneNativeCSS: context.pruneNativeCSS,
|
|
64
|
+
includeGeneratedCSS: context.includeGeneratedCSS,
|
|
65
|
+
delivery: inlineDelivery(context)
|
|
66
|
+
}));
|
|
67
|
+
const managed = {
|
|
68
|
+
entry: "inline-managed",
|
|
69
|
+
stylesheets: [{
|
|
70
|
+
id: "inline-managed",
|
|
71
|
+
href: INLINE_URL_BASE + "entry.css",
|
|
72
|
+
css: result.css
|
|
73
|
+
}, ...result.stylesheets ?? []]
|
|
74
|
+
};
|
|
75
|
+
const bundle = compiler.prepareStylesheetBundle({
|
|
76
|
+
source: scanner.slotCSSRule,
|
|
77
|
+
from: entry.token,
|
|
78
|
+
slotCSSRule: scanner.slotCSSRule,
|
|
79
|
+
managed
|
|
80
|
+
});
|
|
81
|
+
const hash = inlineDigest(JSON.stringify(bundle));
|
|
82
|
+
const urls = Object.fromEntries(bundle.graph.stylesheets.map((node, i) => [node.id, `${INLINE_URL_BASE}master-css-inline-${hash}-${i}.css`]));
|
|
83
|
+
const assets = compiler.renderStylesheetBundle({
|
|
84
|
+
bundle,
|
|
85
|
+
urls,
|
|
86
|
+
inlineImports: true
|
|
87
|
+
});
|
|
88
|
+
const ownedURLs = /* @__PURE__ */ new Set([...Object.values(urls), ...(result.resources ?? []).map((resource) => resource.href)]);
|
|
89
|
+
const css = assets.find((asset) => asset.id === bundle.graph.entry).css;
|
|
90
|
+
const byURL = new Map(assets.map((asset) => [asset.href, asset]));
|
|
91
|
+
const reachable = /* @__PURE__ */ new Set();
|
|
92
|
+
const queue = [css];
|
|
93
|
+
for (const source of queue) for (const reference of inlineURLReferences(compiler, source)) {
|
|
94
|
+
const url = reference.url.split(/[?#]/)[0];
|
|
95
|
+
if (!ownedURLs.has(url) || reachable.has(url)) continue;
|
|
96
|
+
reachable.add(url);
|
|
97
|
+
const asset = byURL.get(url);
|
|
98
|
+
if (asset) queue.push(asset.css);
|
|
99
|
+
}
|
|
100
|
+
entry.urlMarker = entry.token + "_BASE";
|
|
101
|
+
while (css.includes(entry.urlMarker)) entry.urlMarker += "_";
|
|
102
|
+
const directory = posix.dirname(this.getFileName(entry.reference));
|
|
103
|
+
entry.css = css;
|
|
104
|
+
const files = new Map([...ownedURLs].map((url) => [url, posix.join(directory, url.slice(INLINE_URL_BASE.length))]));
|
|
105
|
+
entry.files = files;
|
|
106
|
+
const publication = [];
|
|
107
|
+
const linked = assets.filter((asset) => asset.id !== bundle.graph.entry && reachable.has(asset.href));
|
|
108
|
+
const renderLinked = () => linked.map((asset) => {
|
|
109
|
+
const fileName = files.get(asset.href);
|
|
110
|
+
return {
|
|
111
|
+
fileName,
|
|
112
|
+
source: rewriteInlineURLs(compiler, asset.css, (url) => {
|
|
113
|
+
const bare = url.split(/[?#]/)[0], file = entry.files.get(bare), suffix = url.slice(bare.length), target = file + suffix;
|
|
114
|
+
const configuredBase = Reflect.get(this.environment.getTopLevelConfig(), configuredBaseKey);
|
|
115
|
+
const config = configuredBase === "./" || configuredBase === "" ? {
|
|
116
|
+
base: configuredBase,
|
|
117
|
+
experimental: this.environment.config.experimental
|
|
118
|
+
} : this.environment.config;
|
|
119
|
+
const result = inlineBuiltURL(config, this.environment.config.consumer === "server", target, fileName, "css");
|
|
120
|
+
return "url" in result ? result.url : posix.relative(directory, file) + suffix;
|
|
121
|
+
}, ownedURLs)
|
|
122
|
+
};
|
|
123
|
+
});
|
|
124
|
+
if (linked.length) {
|
|
125
|
+
const urlHash = inlineDigest(JSON.stringify(renderLinked()));
|
|
126
|
+
for (const asset of linked) {
|
|
127
|
+
const fileName = files.get(asset.href);
|
|
128
|
+
files.set(asset.href, fileName.slice(0, -4) + `-${urlHash}.css`);
|
|
129
|
+
}
|
|
130
|
+
publication.push(...renderLinked());
|
|
131
|
+
}
|
|
132
|
+
for (const resource of result.resources ?? []) if (reachable.has(resource.href)) publication.push({
|
|
133
|
+
fileName: posix.join(directory, resource.href.slice(INLINE_URL_BASE.length)),
|
|
134
|
+
source: readFileSync(resource.file)
|
|
135
|
+
});
|
|
136
|
+
pending.set(entry.token, publication);
|
|
137
|
+
}
|
|
138
|
+
},
|
|
139
|
+
renderChunk(code, chunk) {
|
|
140
|
+
const output = new MagicString(code);
|
|
141
|
+
using compiler = createCompilerSync();
|
|
142
|
+
for (const entry of inlineStylesheets(context).values()) {
|
|
143
|
+
if (entry.css === void 0 || !entry.files) continue;
|
|
144
|
+
const pattern = new RegExp(`(["'])${entry.token}\\1`, "g");
|
|
145
|
+
const matches = [...code.matchAll(pattern)];
|
|
146
|
+
if (!matches.length) continue;
|
|
147
|
+
const runtime = [];
|
|
148
|
+
const css = rewriteInlineURLs(compiler, entry.css, (url) => {
|
|
149
|
+
const bare = url.split(/[?#]/)[0], file = entry.files.get(bare), suffix = url.slice(bare.length), target = file + suffix;
|
|
150
|
+
const result = inlineBuiltURL(this.environment.config, this.environment.config.consumer === "server", target, chunk.fileName, "js");
|
|
151
|
+
if ("url" in result) return result.url;
|
|
152
|
+
if ("runtime" in result) {
|
|
153
|
+
const marker = `${entry.urlMarker}_RUNTIME_${runtime.length}__`;
|
|
154
|
+
runtime.push({
|
|
155
|
+
marker,
|
|
156
|
+
expression: result.runtime
|
|
157
|
+
});
|
|
158
|
+
return marker;
|
|
159
|
+
}
|
|
160
|
+
return entry.urlMarker + posix.relative(posix.dirname(this.getFileName(entry.reference)), file) + suffix;
|
|
161
|
+
}, new Set(entry.files.keys()));
|
|
162
|
+
let expression = JSON.stringify(css);
|
|
163
|
+
for (const item of runtime) expression += `.replaceAll(${JSON.stringify(item.marker)}, encodeURI(String(${item.expression})).replaceAll("%25", "%"))`;
|
|
164
|
+
for (const match of matches) {
|
|
165
|
+
used.add(entry.token);
|
|
166
|
+
output.overwrite(match.index, match.index + match[0].length, expression);
|
|
167
|
+
}
|
|
168
|
+
const urlPattern = new RegExp(`(["'])${entry.token}_URL\\1`, "g");
|
|
169
|
+
for (const match of code.matchAll(urlPattern)) output.overwrite(match.index, match.index + match[0].length, JSON.stringify(entry.urlMarker));
|
|
170
|
+
}
|
|
171
|
+
if (!output.hasChanged()) return;
|
|
172
|
+
return {
|
|
173
|
+
code: output.toString(),
|
|
174
|
+
map: output.generateMap({ hires: true })
|
|
175
|
+
};
|
|
176
|
+
},
|
|
177
|
+
generateBundle(_options, bundle) {
|
|
178
|
+
if (!this.environment.config.build.emitAssets) return;
|
|
179
|
+
const entries = [...inlineStylesheets(context).values()];
|
|
180
|
+
const anchors = new Set(entries.filter((entry) => used.has(entry.token) && entry.reference).map((entry) => this.getFileName(entry.reference)));
|
|
181
|
+
for (const entry of entries) if (used.has(entry.token)) for (const asset of pending.get(entry.token) ?? []) this.emitFile({
|
|
182
|
+
type: "asset",
|
|
183
|
+
...asset
|
|
184
|
+
});
|
|
185
|
+
else if (entry.reference) {
|
|
186
|
+
const fileName = this.getFileName(entry.reference);
|
|
187
|
+
if (!anchors.has(fileName)) delete bundle[fileName];
|
|
188
|
+
}
|
|
189
|
+
},
|
|
190
|
+
closeBundle() {
|
|
191
|
+
pending.clear();
|
|
192
|
+
used.clear();
|
|
193
|
+
disposeInlineStylesheets(context);
|
|
194
|
+
}
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
export { InlineStylesheetPlugin as default };
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { Plugin } from "vite";
|
|
2
|
+
import { ResolvedMasterCSSVitePluginOptions } from "../options.js";
|
|
3
|
+
import { MasterCSSVitePluginContext } from "../core.js";
|
|
4
|
+
declare function LocalStylesPlugin(options: ResolvedMasterCSSVitePluginOptions, context: MasterCSSVitePluginContext): Plugin;
|
|
5
|
+
export { LocalStylesPlugin as default };
|