@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.
Files changed (121) hide show
  1. package/README.md +348 -0
  2. package/dist/common.d.ts +14 -0
  3. package/dist/common.js +26 -0
  4. package/dist/core.d.ts +23 -0
  5. package/dist/core.js +165 -0
  6. package/dist/index.d.ts +3 -0
  7. package/dist/index.js +1 -0
  8. package/dist/internal/src/emitted-globals-module.js +12 -0
  9. package/dist/internal/src/manifest-facade.js +68 -0
  10. package/dist/internal/src/manifest-loader.js +33 -0
  11. package/dist/internal/src/manifest-module.js +58 -0
  12. package/dist/internal/src/manifest-virtual-module.js +123 -0
  13. package/dist/internal/src/node.js +22 -0
  14. package/dist/internal/src/program-module.js +50 -0
  15. package/dist/internal/src/project.js +10 -0
  16. package/dist/internal/src/runtime-bootstrap.js +80 -0
  17. package/dist/internal/src/style-module.js +3 -0
  18. package/dist/modes/pre-render.d.ts +5 -0
  19. package/dist/modes/pre-render.js +6 -0
  20. package/dist/modes/progressive.d.ts +5 -0
  21. package/dist/modes/progressive.js +12 -0
  22. package/dist/modes/runtime.d.ts +5 -0
  23. package/dist/modes/runtime.js +17 -0
  24. package/dist/modes/static.d.ts +5 -0
  25. package/dist/modes/static.js +5 -0
  26. package/dist/options.d.ts +20 -0
  27. package/dist/options.js +23 -0
  28. package/dist/plugins/avoid-fouc.d.ts +5 -0
  29. package/dist/plugins/avoid-fouc.js +48 -0
  30. package/dist/plugins/build-stylesheet-recovery.d.ts +5 -0
  31. package/dist/plugins/build-stylesheet-recovery.js +26 -0
  32. package/dist/plugins/context.d.ts +5 -0
  33. package/dist/plugins/context.js +12 -0
  34. package/dist/plugins/dev-stylesheet.d.ts +4 -0
  35. package/dist/plugins/dev-stylesheet.js +63 -0
  36. package/dist/plugins/emitted-globals-virtual-module.d.ts +14 -0
  37. package/dist/plugins/emitted-globals-virtual-module.js +167 -0
  38. package/dist/plugins/inject-runtime.d.ts +5 -0
  39. package/dist/plugins/inject-runtime.js +51 -0
  40. package/dist/plugins/inline-stylesheet.d.ts +5 -0
  41. package/dist/plugins/inline-stylesheet.js +197 -0
  42. package/dist/plugins/local-styles.d.ts +5 -0
  43. package/dist/plugins/local-styles.js +214 -0
  44. package/dist/plugins/manifest-loader.d.ts +4 -0
  45. package/dist/plugins/manifest-loader.js +102 -0
  46. package/dist/plugins/manifest-virtual-module.d.ts +4 -0
  47. package/dist/plugins/manifest-virtual-module.js +70 -0
  48. package/dist/plugins/pre-render.d.ts +5 -0
  49. package/dist/plugins/pre-render.js +224 -0
  50. package/dist/plugins/program-preload.d.ts +5 -0
  51. package/dist/plugins/program-preload.js +37 -0
  52. package/dist/plugins/runtime-bootstrap.d.ts +3 -0
  53. package/dist/plugins/runtime-bootstrap.js +14 -0
  54. package/dist/plugins/runtime-preload.d.ts +4 -0
  55. package/dist/plugins/runtime-preload.js +38 -0
  56. package/dist/plugins/sass-source.d.ts +5 -0
  57. package/dist/plugins/sass-source.js +176 -0
  58. package/dist/plugins/scanner.d.ts +5 -0
  59. package/dist/plugins/scanner.js +24 -0
  60. package/dist/plugins/style-entry-build.d.ts +5 -0
  61. package/dist/plugins/style-entry-build.js +121 -0
  62. package/dist/plugins/style-entry-hmr.d.ts +6 -0
  63. package/dist/plugins/style-entry-hmr.js +78 -0
  64. package/dist/plugins/style-entry.d.ts +5 -0
  65. package/dist/plugins/style-entry.js +89 -0
  66. package/dist/plugins/stylesheet-recovery.d.ts +5 -0
  67. package/dist/plugins/stylesheet-recovery.js +70 -0
  68. package/dist/plugins/usage-graph.d.ts +5 -0
  69. package/dist/plugins/usage-graph.js +48 -0
  70. package/dist/preset/src/default-manifest.js +15913 -0
  71. package/dist/utils/build-import-resolver.d.ts +29 -0
  72. package/dist/utils/build-import-resolver.js +101 -0
  73. package/dist/utils/build-sass-source.d.ts +38 -0
  74. package/dist/utils/build-sass-source.js +225 -0
  75. package/dist/utils/build-stylesheet-delivery.d.ts +12 -0
  76. package/dist/utils/build-stylesheet-delivery.js +130 -0
  77. package/dist/utils/build-watch-recovery.d.ts +10 -0
  78. package/dist/utils/build-watch-recovery.js +119 -0
  79. package/dist/utils/coalesced-task.d.ts +3 -0
  80. package/dist/utils/coalesced-task.js +25 -0
  81. package/dist/utils/dev-module-refresh.d.ts +9 -0
  82. package/dist/utils/dev-module-refresh.js +17 -0
  83. package/dist/utils/dev-stylesheet-delivery.d.ts +21 -0
  84. package/dist/utils/dev-stylesheet-delivery.js +98 -0
  85. package/dist/utils/environment-closing.d.ts +3 -0
  86. package/dist/utils/environment-closing.js +28 -0
  87. package/dist/utils/extracted-css.d.ts +4 -0
  88. package/dist/utils/extracted-css.js +34 -0
  89. package/dist/utils/failed-dependency-reconciliation.d.ts +15 -0
  90. package/dist/utils/failed-dependency-reconciliation.js +150 -0
  91. package/dist/utils/failed-stylesheet-dependencies.d.ts +16 -0
  92. package/dist/utils/failed-stylesheet-dependencies.js +92 -0
  93. package/dist/utils/html.d.ts +8 -0
  94. package/dist/utils/html.js +36 -0
  95. package/dist/utils/inline-stylesheet.d.ts +37 -0
  96. package/dist/utils/inline-stylesheet.js +129 -0
  97. package/dist/utils/local-stylesheet.d.ts +10 -0
  98. package/dist/utils/local-stylesheet.js +25 -0
  99. package/dist/utils/manifest-recovery.d.ts +11 -0
  100. package/dist/utils/manifest-recovery.js +77 -0
  101. package/dist/utils/module-sources.d.ts +26 -0
  102. package/dist/utils/module-sources.js +131 -0
  103. package/dist/utils/path.d.ts +5 -0
  104. package/dist/utils/path.js +27 -0
  105. package/dist/utils/recovery-error.d.ts +3 -0
  106. package/dist/utils/recovery-error.js +17 -0
  107. package/dist/utils/register-style-source.d.ts +4 -0
  108. package/dist/utils/register-style-source.js +23 -0
  109. package/dist/utils/sass-diagnostics.d.ts +4 -0
  110. package/dist/utils/sass-diagnostics.js +109 -0
  111. package/dist/utils/sass-proxy-access.d.ts +4 -0
  112. package/dist/utils/sass-proxy-access.js +28 -0
  113. package/dist/utils/sass-source-markers.d.ts +8 -0
  114. package/dist/utils/sass-source-markers.js +50 -0
  115. package/dist/utils/scanner-context.d.ts +12 -0
  116. package/dist/utils/scanner-context.js +100 -0
  117. package/dist/utils/scoped-plugins.d.ts +4 -0
  118. package/dist/utils/scoped-plugins.js +81 -0
  119. package/dist/utils/write-file.d.ts +3 -0
  120. package/dist/utils/write-file.js +9 -0
  121. package/package.json +62 -0
@@ -0,0 +1,29 @@
1
+ import { MasterCSSStylesheetImportResolver } from "@master/css-compiler/stylesheet";
2
+ import { MasterCSSVitePluginContext } from "../core.js";
3
+ interface ImportResolverContext {
4
+ resolve?: (id: string, importer: string, options: {
5
+ skipSelf: true;
6
+ }) => Promise<{
7
+ id: string;
8
+ external?: boolean | string;
9
+ } | null>;
10
+ addWatchFile?: (id: string) => void;
11
+ load?: (options: {
12
+ id: string;
13
+ }) => Promise<{
14
+ meta: Record<string, unknown>;
15
+ }>;
16
+ }
17
+ declare function clearBuildStylesheetSources(context: MasterCSSVitePluginContext): void;
18
+ /** Capture loader CSS before Master or Vite transforms replace it. */
19
+ declare function captureBuildStylesheetSource(context: MasterCSSVitePluginContext, id: string, source: string): {
20
+ "master-css:stylesheet-source": string;
21
+ } | undefined;
22
+ /** Graph-only loads must not create another unconditional stylesheet entry. */
23
+ declare function removeGraphOnlyStylesheetEntries(context: MasterCSSVitePluginContext, getModuleInfo: (id: string) => {
24
+ importers: readonly string[];
25
+ dynamicImporters: readonly string[];
26
+ } | null): void;
27
+ /** Reuse Vite/plugin resolution, including aliases and browser import conditions. */
28
+ declare function getBuildImportResolver(context: MasterCSSVitePluginContext, plugin: ImportResolverContext): MasterCSSStylesheetImportResolver | undefined;
29
+ export { captureBuildStylesheetSource, clearBuildStylesheetSources, getBuildImportResolver, removeGraphOnlyStylesheetEntries };
@@ -0,0 +1,101 @@
1
+ import { normalizeFilePath } from "./path.js";
2
+ import { moduleSourceID, moduleSourceOwner } from "./module-sources.js";
3
+ import { getPreparedSassSource, getPreparedSassSourceMap, getSassSourceFile, prepareBuildSassSource, sassSourceID } from "./build-sass-source.js";
4
+ import { isAbsolute } from "node:path";
5
+ // src/utils/build-import-resolver.ts
6
+ const SOURCE_META = "master-css:stylesheet-source";
7
+ const states = /* @__PURE__ */ new WeakMap();
8
+ function state(context) {
9
+ let result = states.get(context);
10
+ if (!result) {
11
+ result = {
12
+ sources: /* @__PURE__ */ new Map(),
13
+ importedModules: /* @__PURE__ */ new Set()
14
+ };
15
+ states.set(context, result);
16
+ }
17
+ return result;
18
+ }
19
+ function clearBuildStylesheetSources(context) {
20
+ states.delete(context);
21
+ }
22
+ /** Capture loader CSS before Master or Vite transforms replace it. */
23
+ function captureBuildStylesheetSource(context, id, source) {
24
+ if (context.config?.command !== "build" || !/\.css(?:[?#].*)?$/i.test(id)) return;
25
+ state(context).sources.set(id, source);
26
+ return { [SOURCE_META]: source };
27
+ }
28
+ /** Graph-only loads must not create another unconditional stylesheet entry. */
29
+ function removeGraphOnlyStylesheetEntries(context, getModuleInfo) {
30
+ for (const id of state(context).importedModules) {
31
+ const info = getModuleInfo(id);
32
+ if (info && !info.importers.length && !info.dynamicImporters.length) context.stylesheets?.delete(id);
33
+ }
34
+ }
35
+ /** Reuse Vite/plugin resolution, including aliases and browser import conditions. */
36
+ function getBuildImportResolver(context, plugin) {
37
+ if (!plugin.resolve) return;
38
+ return async (specifier, importer) => {
39
+ if (/^(?:https?:|data:|\/\/|#)/i.test(specifier)) return null;
40
+ const scoped = moduleSourceOwner(importer);
41
+ const owner = scoped?.owner ?? getSassSourceFile(importer);
42
+ const result = await plugin.resolve(specifier, scoped?.file ?? owner ?? importer, { skipSelf: true });
43
+ if (!result) return;
44
+ if (result.external) return specifier === "@master/css" || specifier === "@master/css-preset" ? void 0 : null;
45
+ const sassFile = getSassSourceFile(result.id);
46
+ const original = sassFile ?? result.id.replace(/[?#].*$/, "");
47
+ const originalFile = isAbsolute(original) ? normalizeFilePath(original) : original;
48
+ const preparedOwner = owner && getPreparedSassSource(context, owner);
49
+ const scopedSource = preparedOwner && (await preparedOwner.prepared).moduleSources?.get(originalFile);
50
+ if (typeof scopedSource === "string") {
51
+ plugin.addWatchFile?.(originalFile);
52
+ const id = moduleSourceID(owner, originalFile);
53
+ return {
54
+ id,
55
+ source: scopedSource,
56
+ baseFile: originalFile,
57
+ sourceMap: await getPreparedSassSourceMap(context, id)
58
+ };
59
+ }
60
+ if (sassFile) {
61
+ plugin.addWatchFile?.(sassFile);
62
+ const prepared = await prepareBuildSassSource(context, sassFile, (file) => plugin.addWatchFile?.(file));
63
+ for (const dependency of prepared.deps ?? []) plugin.addWatchFile?.(dependency);
64
+ return {
65
+ id: sassSourceID(sassFile),
66
+ source: prepared.code,
67
+ baseFile: sassFile,
68
+ sourceMap: await getPreparedSassSourceMap(context, sassFile)
69
+ };
70
+ }
71
+ const file = result.id.replace(/(\.(?:css|scss|sass))(?:[?#].*)$/i, "$1");
72
+ if (isAbsolute(file) && /\.(?:scss|sass)$/i.test(file)) {
73
+ plugin.addWatchFile?.(file);
74
+ const prepared = await prepareBuildSassSource(context, file, (file) => plugin.addWatchFile?.(file));
75
+ for (const dependency of prepared.deps ?? []) plugin.addWatchFile?.(dependency);
76
+ return {
77
+ id: file,
78
+ source: prepared.code,
79
+ baseFile: file,
80
+ sourceMap: await getPreparedSassSourceMap(context, file)
81
+ };
82
+ }
83
+ if (isAbsolute(file) && /\.css$/i.test(file)) return file;
84
+ if (result.id.startsWith("\0") && /\.css(?:[?#].*)?$/i.test(result.id) && plugin.load) {
85
+ const loaded = state(context);
86
+ loaded.importedModules.add(result.id);
87
+ if (!loaded.sources.has(result.id)) {
88
+ const cachedSource = (await plugin.load({ id: result.id })).meta[SOURCE_META];
89
+ if (!loaded.sources.has(result.id) && typeof cachedSource === "string") loaded.sources.set(result.id, cachedSource);
90
+ }
91
+ const source = loaded.sources.get(result.id);
92
+ if (source === void 0) throw new Error(`CSS loader did not provide source: ${result.id}`);
93
+ return {
94
+ id: result.id,
95
+ source,
96
+ baseFile: getSassSourceFile(result.id)
97
+ };
98
+ }
99
+ };
100
+ }
101
+ export { captureBuildStylesheetSource, clearBuildStylesheetSources, getBuildImportResolver, removeGraphOnlyStylesheetEntries };
@@ -0,0 +1,38 @@
1
+ import { preprocessCSS } from "vite";
2
+ import { MasterCSSVitePluginContext } from "../core.js";
3
+ import { ModuleSourceDiagnostic } from "./module-sources.js";
4
+ type PreparedSource = Awaited<ReturnType<typeof preprocessCSS>> & {
5
+ moduleSources?: Map<string, string>;
6
+ moduleDiagnostics?: Map<string, ModuleSourceDiagnostic>;
7
+ };
8
+ declare function getSassSourceFile(id: string): string | undefined;
9
+ declare function sassSourceID(file: string): string;
10
+ declare function sassModuleID(file: string): string;
11
+ declare function isSassModuleID(id: string): boolean;
12
+ declare function isRawStyleRequest(id: string): boolean;
13
+ declare function clearBuildSassSources(context: MasterCSSVitePluginContext): void;
14
+ /** Invalidate every prepared owner of an edited source or composed dependency. */
15
+ declare function invalidatePreparedSassSources(context: MasterCSSVitePluginContext, file: string): string[];
16
+ declare function getPreparedSassSource(context: MasterCSSVitePluginContext, id: string): {
17
+ source: string;
18
+ dependencies: Set<string>;
19
+ file: string;
20
+ prepared: Promise<PreparedSource>;
21
+ } | undefined;
22
+ /** Diagnostics for a projected child use its own source and generated map. */
23
+ declare function getPreparedSassDiagnosticSource(context: MasterCSSVitePluginContext, id: string): Promise<{
24
+ file: string;
25
+ source: string;
26
+ generatedID: string;
27
+ prepared: PreparedSource;
28
+ } | {
29
+ file: string;
30
+ source: string;
31
+ generatedID: string;
32
+ prepared: ModuleSourceDiagnostic;
33
+ } | undefined>;
34
+ /** Carry the host's map alongside CSS so reference lookup can retain partial origins. */
35
+ declare function getPreparedSassSourceMap(context: MasterCSSVitePluginContext, id: string): Promise<string | undefined>;
36
+ /** Use Vite's preprocessors/Modules and URL rebasing, leaving imports for Rust. */
37
+ declare function prepareBuildSassSource(context: MasterCSSVitePluginContext, file: string, onDependency?: (file: string) => void): Promise<PreparedSource>;
38
+ export { clearBuildSassSources, getPreparedSassDiagnosticSource, getPreparedSassSource, getPreparedSassSourceMap, getSassSourceFile, invalidatePreparedSassSources, isRawStyleRequest, isSassModuleID, prepareBuildSassSource, sassModuleID, sassSourceID };
@@ -0,0 +1,225 @@
1
+ import { normalizeFilePath } from "./path.js";
2
+ import { createSassSourceMarkers } from "./sass-source-markers.js";
3
+ import { createModuleSourceProjection, moduleSourceOwner } from "./module-sources.js";
4
+ import { createHash } from "node:crypto";
5
+ import { readFileSync } from "node:fs";
6
+ import { isAbsolute, join } from "node:path";
7
+ import { preprocessCSS } from "vite";
8
+ import { mkdir, mkdtemp, realpath, rm, writeFile } from "node:fs/promises";
9
+ import { pathToFileURL } from "node:url";
10
+ // src/utils/build-sass-source.ts
11
+ const CSS_SUFFIX = ".master-css-sass.css";
12
+ const MODULE_PREFIX = "\0master-css:sass-module:";
13
+ const caches = /* @__PURE__ */ new WeakMap();
14
+ function getSassSourceFile(id) {
15
+ id = id.replace(/[?#].*$/, "");
16
+ if (id.startsWith(MODULE_PREFIX)) return decodeURIComponent(id.slice(24, -3));
17
+ if (id.endsWith(CSS_SUFFIX)) return id.slice(0, -20);
18
+ }
19
+ function sassSourceID(file) {
20
+ return `${file}${CSS_SUFFIX}`;
21
+ }
22
+ function sassModuleID(file) {
23
+ return MODULE_PREFIX + encodeURIComponent(file) + ".js";
24
+ }
25
+ function isSassModuleID(id) {
26
+ return id.startsWith(MODULE_PREFIX);
27
+ }
28
+ function isRawStyleRequest(id) {
29
+ return /[?&](?:raw|url)(?:[=&]|$)/.test(id);
30
+ }
31
+ function clearBuildSassSources(context) {
32
+ caches.delete(context);
33
+ }
34
+ /** Invalidate every prepared owner of an edited source or composed dependency. */
35
+ function invalidatePreparedSassSources(context, file) {
36
+ file = normalizeFilePath(file);
37
+ const cache = caches.get(context);
38
+ const affected = [];
39
+ for (const [owner, entry] of cache ?? []) {
40
+ if (owner !== file && !entry.dependencies.has(file)) continue;
41
+ entry.prepared = void 0;
42
+ affected.push(owner);
43
+ }
44
+ return affected;
45
+ }
46
+ function getPreparedSassSource(context, id) {
47
+ const file = normalizeFilePath(getSassSourceFile(id) ?? id.replace(/[?#].*$/, ""));
48
+ const cached = caches.get(context)?.get(file);
49
+ return cached?.prepared ? {
50
+ file,
51
+ ...cached,
52
+ prepared: cached.prepared
53
+ } : void 0;
54
+ }
55
+ /** Diagnostics for a projected child use its own source and generated map. */
56
+ async function getPreparedSassDiagnosticSource(context, id) {
57
+ const scoped = moduleSourceOwner(id);
58
+ const cached = getPreparedSassSource(context, scoped?.owner ?? id);
59
+ if (!cached) return;
60
+ const prepared = await cached.prepared;
61
+ if (!scoped) return {
62
+ file: cached.file,
63
+ source: cached.source,
64
+ generatedID: id,
65
+ prepared
66
+ };
67
+ const child = prepared.moduleDiagnostics?.get(scoped.file);
68
+ if (child) return {
69
+ file: scoped.file,
70
+ source: child.source,
71
+ generatedID: sassSourceID(scoped.file),
72
+ prepared: child
73
+ };
74
+ }
75
+ /** Carry the host's map alongside CSS so reference lookup can retain partial origins. */
76
+ async function getPreparedSassSourceMap(context, id) {
77
+ const map = (await getPreparedSassDiagnosticSource(context, id))?.prepared.map;
78
+ return map ? typeof map === "string" ? map : JSON.stringify(map) : void 0;
79
+ }
80
+ /** Use Vite's preprocessors/Modules and URL rebasing, leaving imports for Rust. */
81
+ function prepareBuildSassSource(context, file, onDependency) {
82
+ if (!context.config) throw new Error("Sass preparation requires resolved Vite configuration.");
83
+ file = normalizeFilePath(file);
84
+ let cache = caches.get(context);
85
+ if (!cache) {
86
+ cache = /* @__PURE__ */ new Map();
87
+ caches.set(context, cache);
88
+ }
89
+ let cached = cache.get(file);
90
+ if (!cached?.prepared) {
91
+ const sourceMarkers = createSassSourceMarkers();
92
+ const preserveImports = {
93
+ postcssPlugin: "master-css:preserve-preprocessor-imports",
94
+ prepare({ root }) {
95
+ const imports = [];
96
+ root.walkAtRules((rule) => {
97
+ if (rule.name.toLowerCase() !== "import") return;
98
+ imports.push({
99
+ rule,
100
+ name: rule.name
101
+ });
102
+ rule.name = "--master-css-preserved-import";
103
+ });
104
+ return { OnceExit() {
105
+ for (const { rule, name } of imports) rule.name = name;
106
+ if (!projection) root.walkComments((comment) => {
107
+ if (sourceMarkers.markers.has(comment.text.trim())) comment.remove();
108
+ });
109
+ } };
110
+ }
111
+ };
112
+ const config = context.config;
113
+ const source = readFileSync(file, "utf8");
114
+ const projection = /\.module\.(?:css|scss|sass)$/.test(file) && config.css.modules !== false ? createModuleSourceProjection(file) : void 0;
115
+ const dependencies = new Set(cached?.dependencies);
116
+ const discovered = /* @__PURE__ */ new Set();
117
+ let importDirectory;
118
+ const importedSources = /* @__PURE__ */ new Map();
119
+ const originalFile = (id) => projection?.sourceFiles.get(normalizeFilePath(id)) ?? normalizeFilePath(id);
120
+ const preprocessorConfig = {
121
+ ...config,
122
+ createResolver(options) {
123
+ const resolve = config.createResolver(options);
124
+ const cssImport = options?.extensions?.length === 1 && options.extensions[0] === ".css";
125
+ return async (...args) => {
126
+ if (args[1]) args[1] = originalFile(args[1]);
127
+ const resolved = await resolve(...args);
128
+ if (resolved && isAbsolute(resolved)) {
129
+ dependencies.add(originalFile(resolved));
130
+ discovered.add(originalFile(resolved));
131
+ }
132
+ if (resolved && projection && cssImport && /\.(?:scss|sass)$/.test(resolved)) {
133
+ let prepared = importedSources.get(resolved);
134
+ if (!prepared) {
135
+ prepared = prepareImportedSource(resolved);
136
+ importedSources.set(resolved, prepared);
137
+ }
138
+ return prepared;
139
+ }
140
+ return resolved;
141
+ };
142
+ },
143
+ css: {
144
+ ...config.css,
145
+ devSourcemap: true,
146
+ preprocessorOptions: {
147
+ ...config.css.preprocessorOptions,
148
+ scss: {
149
+ ...config.css.preprocessorOptions?.scss,
150
+ sourceMapIncludeSources: true,
151
+ additionalData: (projection ?? sourceMarkers).additionalData(config.css.preprocessorOptions?.scss?.additionalData)
152
+ },
153
+ sass: {
154
+ ...config.css.preprocessorOptions?.sass,
155
+ sourceMapIncludeSources: true,
156
+ additionalData: (projection ?? sourceMarkers).additionalData(config.css.preprocessorOptions?.sass?.additionalData)
157
+ }
158
+ },
159
+ transformer: "postcss",
160
+ postcss: { plugins: [projection?.plugin ?? preserveImports] }
161
+ }
162
+ };
163
+ async function prepareImportedSource(id) {
164
+ const result = await preprocessCSS(readFileSync(id, "utf8"), id, {
165
+ ...preprocessorConfig,
166
+ css: {
167
+ ...preprocessorConfig.css,
168
+ modules: false,
169
+ postcss: { plugins: [preserveImports] }
170
+ }
171
+ });
172
+ for (const dependency of result.deps ?? []) {
173
+ discovered.add(originalFile(dependency));
174
+ dependencies.add(originalFile(dependency));
175
+ }
176
+ importDirectory ??= mkdir(config.cacheDir, { recursive: true }).then(() => mkdtemp(join(config.cacheDir, "master-css-sass-import-"))).then((directory) => realpath(directory));
177
+ const path = normalizeFilePath(join(await importDirectory, `${createHash("sha256").update(id).digest("hex")}.css`));
178
+ projection.sourceFiles.set(path, id);
179
+ const raw = typeof result.map === "string" ? JSON.parse(result.map) : result.map;
180
+ const root = raw && "sourceRoot" in raw && raw.sourceRoot ? raw.sourceRoot.replace(/\/?$/, "/") : "./";
181
+ const base = isAbsolute(root) ? pathToFileURL(root) : new URL(root, pathToFileURL(id));
182
+ const map = raw && "sources" in raw && raw.sources ? JSON.stringify({
183
+ ...raw,
184
+ sourceRoot: "",
185
+ sources: raw.sources.map((source) => source ? (isAbsolute(source) ? pathToFileURL(source) : new URL(source, base)).href : source)
186
+ }) : void 0;
187
+ const annotation = map ? `\n/*# sourceMappingURL=data:application/json;base64,${Buffer.from(map).toString("base64")} */` : "";
188
+ await writeFile(path, result.code + annotation);
189
+ return path;
190
+ }
191
+ cached = {
192
+ source,
193
+ prepared: preprocessCSS(source, file, preprocessorConfig).then((result) => {
194
+ for (const dependency of result.deps ?? []) discovered.add(originalFile(dependency));
195
+ if (projection) for (const dependency of result.deps ?? []) {
196
+ const file = originalFile(dependency);
197
+ if (/\.css$/i.test(file) && !projection.sources.has(file)) projection.copyDuplicate(file, readFileSync(file, "utf8"));
198
+ }
199
+ dependencies.clear();
200
+ for (const dependency of discovered) dependencies.add(dependency);
201
+ return {
202
+ ...result,
203
+ deps: dependencies,
204
+ ...projection ? {
205
+ moduleSources: projection.sources,
206
+ moduleDiagnostics: projection.diagnostics
207
+ } : {}
208
+ };
209
+ }).finally(async () => {
210
+ await Promise.allSettled(importedSources.values());
211
+ if (importDirectory) await rm(await importDirectory, {
212
+ recursive: true,
213
+ force: true
214
+ });
215
+ }),
216
+ dependencies
217
+ };
218
+ cache.set(file, cached);
219
+ }
220
+ const entry = cached, prepared = entry.prepared;
221
+ return onDependency ? prepared.finally(() => {
222
+ for (const dependency of entry.dependencies) onDependency(dependency);
223
+ }) : prepared;
224
+ }
225
+ export { clearBuildSassSources, getPreparedSassDiagnosticSource, getPreparedSassSource, getPreparedSassSourceMap, getSassSourceFile, invalidatePreparedSassSources, isRawStyleRequest, isSassModuleID, prepareBuildSassSource, sassModuleID, sassSourceID };
@@ -0,0 +1,12 @@
1
+ import { MasterCSSStylesheetComposition, MasterCSSStylesheetDeliveryOptions } from "@master/css-compiler/stylesheet";
2
+ import { MasterCSSVitePluginContext } from "../core.js";
3
+ import { MasterCSSCompiler } from "@master/css-compiler";
4
+ import { LocalStylesheet } from "./local-stylesheet.js";
5
+ /** These temporary graph URLs are replaced after the full CSS content is known. */
6
+ declare function getBuildStylesheetDelivery(context: MasterCSSVitePluginContext): MasterCSSStylesheetDeliveryOptions | undefined;
7
+ declare function prepareBuildStylesheet(compiler: MasterCSSCompiler, source: string, slotCSSRule: string, extracted: MasterCSSStylesheetComposition, locals?: readonly LocalStylesheet[]): {
8
+ resources: readonly import("@master/css-compiler/stylesheet").MasterCSSStylesheetResourceAsset[] | undefined;
9
+ source: string;
10
+ assets: readonly import("@master/css-binding/protocol").MasterCSSStylesheetAsset[];
11
+ } | undefined;
12
+ export { getBuildStylesheetDelivery, prepareBuildStylesheet };
@@ -0,0 +1,130 @@
1
+ import { createHash } from "node:crypto";
2
+ import { readFileSync } from "node:fs";
3
+ import { extname } from "node:path";
4
+ // src/utils/build-stylesheet-delivery.ts
5
+ function digest(source) {
6
+ return createHash("sha256").update(source).digest("hex").slice(0, 20);
7
+ }
8
+ /** These temporary graph URLs are replaced after the full CSS content is known. */
9
+ function getBuildStylesheetDelivery(context) {
10
+ if (context.config?.command !== "build") return;
11
+ return {
12
+ entryURL: "./master-css-entry.css",
13
+ stylesheetURL: (file, variant) => `./master-css-source-${digest(variant ?? file)}.css`,
14
+ resourceURL: (file) => `./master-css-resource-${digest(readFileSync(file))}${extname(file)}`,
15
+ relativeResourceURLs: true,
16
+ resolveNodePackageImports: true
17
+ };
18
+ }
19
+ function prepareBuildStylesheet(compiler, source, slotCSSRule, extracted, locals = []) {
20
+ if (locals.length) return prepareLocalBuildStylesheets(compiler, source, slotCSSRule, extracted, locals);
21
+ const managed = {
22
+ entry: "master-css-managed",
23
+ stylesheets: [{
24
+ id: "master-css-managed",
25
+ href: "./master-css-entry.css",
26
+ css: extracted.css
27
+ }, ...extracted.stylesheets ?? []]
28
+ };
29
+ const bundle = compiler.prepareStylesheetBundle({
30
+ source,
31
+ from: "master-css-bundle",
32
+ slotCSSRule,
33
+ managed
34
+ });
35
+ if (!bundle.slots) return;
36
+ return {
37
+ ...renderBuildStylesheetBundle(compiler, bundle),
38
+ resources: extracted.resources
39
+ };
40
+ }
41
+ /**
42
+ * Name fragments after their rendered bytes. Graph node IDs and temporary
43
+ * delivery URLs derive from host file paths, so hashing the prepared bundle
44
+ * would vary with the checkout location.
45
+ */
46
+ function renderBuildStylesheetBundle(compiler, bundle) {
47
+ const render = (url) => {
48
+ const urls = Object.fromEntries(bundle.graph.stylesheets.map((node, index) => [node.id, url(index)]));
49
+ return {
50
+ urls,
51
+ assets: compiler.renderStylesheetBundle({
52
+ bundle,
53
+ urls,
54
+ preserveResourceBase: true
55
+ })
56
+ };
57
+ };
58
+ const hash = digest(JSON.stringify(render((index) => `./master-css-${index}.css`).assets.map((asset) => asset.css)));
59
+ const { urls, assets } = render((index) => `./master-css-${hash}-${index}.css`);
60
+ return {
61
+ source: `@import "${urls[bundle.graph.entry]}";`,
62
+ assets
63
+ };
64
+ }
65
+ /** Compose each local entry at its own position before final content-based naming. */
66
+ function prepareLocalBuildStylesheets(compiler, source, slotCSSRule, extracted, locals) {
67
+ const entry = "./master-css-host.css";
68
+ const graph = /* @__PURE__ */ new Map([[entry, {
69
+ id: entry,
70
+ href: entry,
71
+ css: source
72
+ }]]);
73
+ const resources = /* @__PURE__ */ new Map();
74
+ const replacements = [{
75
+ slot: slotCSSRule,
76
+ css: extracted.css,
77
+ stylesheets: extracted.stylesheets,
78
+ resources: extracted.resources
79
+ }, ...[...locals].sort((a, b) => a.slot < b.slot ? -1 : a.slot > b.slot ? 1 : 0).map(({ slot, result }) => ({
80
+ slot,
81
+ css: result.code,
82
+ stylesheets: result.stylesheets,
83
+ resources: result.resources
84
+ }))];
85
+ let replaced = false;
86
+ for (const [replacementIndex, replacement] of replacements.entries()) for (const [assetIndex, asset] of [...graph.values()].entries()) {
87
+ const bundle = compiler.prepareStylesheetBundle({
88
+ source: asset.css,
89
+ from: asset.id,
90
+ slotCSSRule: replacement.slot,
91
+ managed: {
92
+ entry: "managed",
93
+ stylesheets: [{
94
+ id: "managed",
95
+ href: "./master-css-entry.css",
96
+ css: replacement.css
97
+ }, ...replacement.stylesheets ?? []]
98
+ }
99
+ });
100
+ if (!bundle.slots) continue;
101
+ replaced = true;
102
+ const urls = Object.fromEntries(bundle.graph.stylesheets.map((node, index) => [node.id, node.id === bundle.graph.entry ? asset.href : `./master-css-intermediate-${replacementIndex}-${assetIndex}-${index}.css`]));
103
+ const assets = compiler.renderStylesheetBundle({
104
+ bundle,
105
+ urls,
106
+ preserveResourceBase: true
107
+ });
108
+ for (const next of assets) graph.set(next.href, {
109
+ id: next.href,
110
+ href: next.href,
111
+ css: next.css
112
+ });
113
+ for (const resource of replacement.resources ?? []) resources.set(resource.href, resource);
114
+ }
115
+ if (!replaced) return;
116
+ const slot = "#master-css-complete-local-graph{--slot:0}";
117
+ return {
118
+ ...renderBuildStylesheetBundle(compiler, compiler.prepareStylesheetBundle({
119
+ source: slot,
120
+ from: "master-css-output",
121
+ slotCSSRule: slot,
122
+ managed: {
123
+ entry,
124
+ stylesheets: [...graph.values()]
125
+ }
126
+ })),
127
+ resources: [...resources.values()]
128
+ };
129
+ }
130
+ export { getBuildStylesheetDelivery, prepareBuildStylesheet };
@@ -0,0 +1,10 @@
1
+ import { ResolvedConfig } from "vite";
2
+ import { MasterCSSVitePluginContext } from "../core.js";
3
+ import { DependencyHost } from "./failed-stylesheet-dependencies.js";
4
+ type BuildWatch = ResolvedConfig['build']['watch'];
5
+ /** Allocate during config resolution; retain every started owner. */
6
+ declare function prepareBuildStylesheetRecovery(context: MasterCSSVitePluginContext, root: string, cacheDir: string, watch: BuildWatch, environment?: object): void;
7
+ /** An existing owned cache file lets the build host invalidate failed modules. */
8
+ declare function trackBuildStylesheetRecovery(context: MasterCSSVitePluginContext, host: DependencyHost, key: string, id: string, versions: Map<string, string>): void;
9
+ declare function closeBuildStylesheetRecovery(context: MasterCSSVitePluginContext, environment: object): void;
10
+ export { closeBuildStylesheetRecovery, prepareBuildStylesheetRecovery, trackBuildStylesheetRecovery };
@@ -0,0 +1,119 @@
1
+ import { clearFailedDependencyReconciliation, trackFailedDependencyReconciliation } from "./failed-dependency-reconciliation.js";
2
+ import { mkdirSync, mkdtempSync, readdirSync, rmSync, writeFileSync } from "node:fs";
3
+ import { join } from "node:path";
4
+ import { createFilter } from "vite";
5
+ // src/utils/build-watch-recovery.ts
6
+ const recoveries = /* @__PURE__ */ new WeakMap();
7
+ const held = /* @__PURE__ */ new Set();
8
+ function retain(state, environment) {
9
+ state.owners.add(environment);
10
+ held.add(state.directory);
11
+ }
12
+ function running(pid) {
13
+ try {
14
+ process.kill(pid, 0);
15
+ return true;
16
+ } catch (error) {
17
+ return error.code === "EPERM";
18
+ }
19
+ }
20
+ /**
21
+ * Configuration has to allocate before the host can say whether the build will
22
+ * start, and the host runs no hook after a failure during configuration or
23
+ * environment creation, so material from such a run outlives it. Reclaim it
24
+ * here instead: the owning process id is in the directory name, so a directory
25
+ * is stale when no owner in this process holds it and the process that
26
+ * allocated it is gone or is this one.
27
+ */
28
+ function sweepStaleRecoveries(base, prefix) {
29
+ let entries;
30
+ try {
31
+ entries = readdirSync(base);
32
+ } catch {
33
+ return;
34
+ }
35
+ for (const entry of entries) {
36
+ if (!entry.startsWith(prefix)) continue;
37
+ const directory = join(base, entry);
38
+ if (held.has(directory)) continue;
39
+ const pid = Number.parseInt(entry.slice(prefix.length), 10);
40
+ if (pid !== process.pid && Number.isInteger(pid) && running(pid)) continue;
41
+ rmSync(directory, {
42
+ recursive: true,
43
+ force: true
44
+ });
45
+ }
46
+ }
47
+ /**
48
+ * The build host applies `build.watch` include and exclude to every watched
49
+ * file, plugin-added ones included, so a project filter can silently drop the
50
+ * file recovery depends on. Take the first location the project's own filter
51
+ * accepts rather than overriding what it asked for.
52
+ */
53
+ function resolveRecoveryLocation(root, cacheDir, watch) {
54
+ const accepts = createFilter(watch?.include, watch?.exclude, { resolve: false });
55
+ return [
56
+ {
57
+ base: cacheDir,
58
+ prefix: "master-css-watch-",
59
+ name: "invalidate"
60
+ },
61
+ {
62
+ base: cacheDir,
63
+ prefix: "master-css-watch-",
64
+ name: "invalidate.css"
65
+ },
66
+ {
67
+ base: root,
68
+ prefix: ".master-css-watch-",
69
+ name: "invalidate.css"
70
+ }
71
+ ].find(({ base, prefix, name }) => accepts(join(base, `${prefix}probe`, name)));
72
+ }
73
+ /** Allocate during config resolution; retain every started owner. */
74
+ function prepareBuildStylesheetRecovery(context, root, cacheDir, watch, environment) {
75
+ const existing = recoveries.get(context);
76
+ if (existing) {
77
+ if (environment) retain(existing, environment);
78
+ return;
79
+ }
80
+ const location = resolveRecoveryLocation(root, cacheDir, watch);
81
+ if (!location) return;
82
+ mkdirSync(location.base, { recursive: true });
83
+ sweepStaleRecoveries(location.base, location.prefix);
84
+ const directory = mkdtempSync(join(location.base, `${location.prefix}${process.pid}-`)), file = join(directory, location.name);
85
+ writeFileSync(file, "pending");
86
+ const state = {
87
+ directory,
88
+ file,
89
+ owners: /* @__PURE__ */ new Set()
90
+ };
91
+ recoveries.set(context, state);
92
+ if (environment) retain(state, environment);
93
+ }
94
+ /** An existing owned cache file lets the build host invalidate failed modules. */
95
+ function trackBuildStylesheetRecovery(context, host, key, id, versions) {
96
+ const state = recoveries.get(context);
97
+ if (!versions.size || !host.addWatchFile || !state) return;
98
+ const environment = host.environment ?? context;
99
+ retain(state, environment);
100
+ host.addWatchFile(state.file);
101
+ trackFailedDependencyReconciliation(context, environment, key, id, versions, async (_environment, _id, _changed, active) => {
102
+ if (active()) writeFileSync(state.file, String(process.hrtime.bigint()));
103
+ });
104
+ }
105
+ function closeBuildStylesheetRecovery(context, environment) {
106
+ clearFailedDependencyReconciliation(context, environment);
107
+ const state = recoveries.get(context);
108
+ if (!state) return;
109
+ state.owners.delete(environment);
110
+ if (!state.owners.size) {
111
+ rmSync(state.directory, {
112
+ recursive: true,
113
+ force: true
114
+ });
115
+ held.delete(state.directory);
116
+ recoveries.delete(context);
117
+ }
118
+ }
119
+ export { closeBuildStylesheetRecovery, prepareBuildStylesheetRecovery, trackBuildStylesheetRecovery };
@@ -0,0 +1,3 @@
1
+ /** Keep one active operation and collapse pending events into its latest follow-up. */
2
+ declare function createCoalescedTask(work: () => Promise<void>, onError: (error: unknown) => void): () => Promise<void>;
3
+ export { createCoalescedTask };