vite-plugin-taro 0.5.13 → 0.5.16
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/dist/node/plugins/client/client-taro.d.ts +1 -1
- package/dist/node/plugins/client/client-taro.js +2 -1
- package/dist/node/plugins/h5/create-stencil-client-adapter.d.ts +1 -1
- package/dist/node/plugins/h5/create-stencil-client-adapter.js +2 -1
- package/dist/node/plugins/h5/resolver/module-resolver.js +2 -1
- package/dist/node/plugins/wx/dev/create-hmr-results-stream.d.ts +23 -0
- package/dist/node/plugins/wx/dev/create-hmr-results-stream.js +57 -0
- package/dist/node/plugins/wx/dev/create-style-capture.d.ts +54 -0
- package/dist/node/plugins/wx/dev/create-style-capture.js +173 -0
- package/dist/node/plugins/wx/dev/dev-host.d.ts +1 -1
- package/dist/node/plugins/wx/dev/dev-host.js +161 -93
- package/dist/node/plugins/wx/dev/hmr-files.d.ts +1 -0
- package/dist/node/plugins/wx/dev/hmr-files.js +1 -0
- package/dist/node/plugins/wx/dev/host-actions.d.ts +16 -0
- package/dist/node/plugins/wx/dev/host-actions.js +58 -0
- package/dist/node/plugins/wx/dev/patch-publisher.d.ts +2 -2
- package/dist/node/plugins/wx/dev/patch-publisher.js +17 -1
- package/dist/node/plugins/wx/dev/plugins.d.ts +4 -0
- package/dist/node/plugins/wx/dev/plugins.js +24 -8
- package/dist/node/plugins/wx/dev/react-refresh.js +6 -2
- package/dist/node/plugins/wx/dev/runtime-reports.d.ts +27 -0
- package/dist/node/plugins/wx/dev/runtime-reports.js +45 -0
- package/dist/node/plugins/wx/dev/wx-dev-options.d.ts +7 -3
- package/dist/node/plugins/wx/dev/wx-dev-options.js +46 -28
- package/dist/node/plugins/wx/module.d.ts +1 -1
- package/dist/node/plugins/wx/module.js +2 -1
- package/dist/node/plugins/wx/native/compile-native-component-interface.js +2 -1
- package/dist/node/plugins/wx/native/create-native-component-output.js +2 -0
- package/dist/node/plugins/wx/native/native-component-assets.d.ts +1 -1
- package/dist/node/plugins/wx/native/native-component-assets.js +3 -3
- package/dist/node/plugins/wx/native/native-component-interface.js +2 -1
- package/dist/node/plugins/wx/resolve/resolver.js +3 -2
- package/dist/node/plugins/wx/styles/plugins.js +20 -1
- package/dist/node/utils/modules.d.ts +1 -1
- package/dist/node/utils/modules.js +4 -3
- package/dist/node/utils/packages.js +2 -2
- package/package.json +4 -3
- package/src/node/plugins/client/client-taro.ts +2 -2
- package/src/node/plugins/h5/create-stencil-client-adapter.ts +2 -2
- package/src/node/plugins/h5/resolver/module-resolver.ts +2 -1
- package/src/node/plugins/wx/dev/create-hmr-results-stream.ts +71 -0
- package/src/node/plugins/wx/dev/create-style-capture.ts +248 -0
- package/src/node/plugins/wx/dev/dev-host.ts +188 -124
- package/src/node/plugins/wx/dev/hmr-files.ts +1 -0
- package/src/node/plugins/wx/dev/host-actions.ts +88 -0
- package/src/node/plugins/wx/dev/patch-publisher.ts +19 -2
- package/src/node/plugins/wx/dev/plugins.ts +25 -8
- package/src/node/plugins/wx/dev/react-refresh.ts +6 -2
- package/src/node/plugins/wx/dev/runtime-reports.ts +70 -0
- package/src/node/plugins/wx/dev/wx-dev-options.ts +50 -36
- package/src/node/plugins/wx/module.ts +2 -4
- package/src/node/plugins/wx/native/compile-native-component-interface.ts +2 -1
- package/src/node/plugins/wx/native/create-native-component-output.ts +2 -0
- package/src/node/plugins/wx/native/native-component-assets.ts +3 -4
- package/src/node/plugins/wx/native/native-component-interface.ts +2 -1
- package/src/node/plugins/wx/resolve/resolver.ts +3 -2
- package/src/node/plugins/wx/styles/plugins.ts +21 -1
- package/src/node/utils/modules.ts +4 -3
- package/src/node/utils/packages.ts +2 -2
- package/dist/node/plugins/wx/dev/create-wx-dev-mode.d.ts +0 -6
- package/dist/node/plugins/wx/dev/create-wx-dev-mode.js +0 -9
- package/dist/node/plugins/wx/dev/styles/create-style-capture-plugin.d.ts +0 -12
- package/dist/node/plugins/wx/dev/styles/create-style-capture-plugin.js +0 -21
- package/dist/node/plugins/wx/dev/styles/publish-style-hmr.d.ts +0 -27
- package/dist/node/plugins/wx/dev/styles/publish-style-hmr.js +0 -48
- package/dist/node/utils/serialized-task-queue.d.ts +0 -13
- package/dist/node/utils/serialized-task-queue.js +0 -25
- package/src/node/plugins/wx/dev/create-wx-dev-mode.ts +0 -14
- package/src/node/plugins/wx/dev/styles/create-style-capture-plugin.ts +0 -34
- package/src/node/plugins/wx/dev/styles/publish-style-hmr.ts +0 -71
- package/src/node/utils/serialized-task-queue.ts +0 -32
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { normalizePath } from 'vite';
|
|
1
2
|
import { normalizeModuleId } from '../../utils/modules.js';
|
|
2
3
|
import { resolvePackageFile } from '../../utils/packages.js';
|
|
3
4
|
import { clientTaroNativeId } from './constant.js';
|
|
@@ -17,7 +18,7 @@ import { injectTaroFrameworkApis } from './inject-taro-framework-apis.js';
|
|
|
17
18
|
/** Public facade used by transformed application API imports. */
|
|
18
19
|
export const clientTaroApiId = 'virtual:taro/api';
|
|
19
20
|
const clientTaroApiPath = resolvePackageFile('dist/runtime/client/taro/api.js');
|
|
20
|
-
const normalizedClientTaroApiPath =
|
|
21
|
+
const normalizedClientTaroApiPath = normalizePath(clientTaroApiPath);
|
|
21
22
|
const clientTaroComponentId = 'virtual:taro/components';
|
|
22
23
|
const clientTaroModules = new Map([
|
|
23
24
|
[clientTaroApiId, clientTaroApiPath],
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
+
import { normalizePath } from 'vite';
|
|
1
2
|
import { normalizeModuleId } from '../../utils/modules.js';
|
|
2
3
|
import { transformWithOxcWalker } from '../../utils/oxc-transform.js';
|
|
3
4
|
import { packageRequire } from '../../utils/packages.js';
|
|
4
5
|
const stencilClientPath = packageRequire.resolve('@stencil/core/internal/client', {
|
|
5
6
|
paths: [packageRequire.resolve('@tarojs/components/package.json')]
|
|
6
7
|
});
|
|
7
|
-
const normalizedStencilClientPath =
|
|
8
|
+
const normalizedStencilClientPath = normalizePath(stencilClientPath);
|
|
8
9
|
/**
|
|
9
10
|
* Creates the compiler-owned adaptation of Stencil's client style insertion.
|
|
10
11
|
*
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { normalizePath } from 'vite';
|
|
1
2
|
import { normalizeModuleId, resolveAppComponentPath } from '../../../utils/modules.js';
|
|
2
3
|
import { appComponentId } from '../../client/constant.js';
|
|
3
4
|
import { h5AppPath } from '../constant.js';
|
|
@@ -11,7 +12,7 @@ export function createModuleResolver(options) {
|
|
|
11
12
|
}
|
|
12
13
|
},
|
|
13
14
|
transform({ code, id, projectRoot, sourcemap = true }) {
|
|
14
|
-
if (normalizeModuleId(id) ===
|
|
15
|
+
if (normalizeModuleId(id) === normalizePath(h5AppPath)) {
|
|
15
16
|
return transformH5App({ code, id, options, projectRoot, sourcemap });
|
|
16
17
|
}
|
|
17
18
|
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { DevOptions } from 'rolldown/experimental';
|
|
2
|
+
import { type SchedulerLike, Subject } from 'rxjs';
|
|
3
|
+
type HmrUpdatesResult = Parameters<NonNullable<DevOptions['onHmrUpdates']>>[0];
|
|
4
|
+
type HmrUpdates = Exclude<HmrUpdatesResult, Error>;
|
|
5
|
+
/**
|
|
6
|
+
* Adapts Rolldown's non-awaited HMR callback into lossless quiet-window publications.
|
|
7
|
+
*
|
|
8
|
+
* Debouncing the result stream itself would retain only the final callback and lose incremental patch factories that later
|
|
9
|
+
* patches provably do not reproduce. Instead, the debounced view is only a closing notifier for `buffer`: every callback is
|
|
10
|
+
* retained in arrival order, and one configured quiet period emits the complete window to the host's existing serialized
|
|
11
|
+
* writer. This first stream migration deliberately does not own physical state; `publish` and `reportError` remain synchronous
|
|
12
|
+
* admission callbacks so the dev host can enqueue both through its single writer.
|
|
13
|
+
*
|
|
14
|
+
* DevEngine failures are values, not Observable errors. They represent transient editor generations and carry no executable
|
|
15
|
+
* patch, so the stream reports the final error but otherwise removes them. Successful callbacks on either side remain ordered
|
|
16
|
+
* and lossless; Rolldown generated each against its unpublished client frontier, and the host delivers every retained payload.
|
|
17
|
+
* Completing the returned Subject flushes its current buffer synchronously, allowing host shutdown to await the resulting
|
|
18
|
+
* serialized task rather than silently dropping an admitted patch.
|
|
19
|
+
*
|
|
20
|
+
* Complexity is O(updates + changed files) per emitted window, with one retained reference per callback until the quiet edge.
|
|
21
|
+
*/
|
|
22
|
+
export declare function createHmrResultsStream(settleMilliseconds: number, scheduler: SchedulerLike, publish: (result: HmrUpdates) => void, reportError: (error: Error) => void): Subject<HmrUpdatesResult>;
|
|
23
|
+
export {};
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { buffer, debounceTime, filter, Subject } from 'rxjs';
|
|
2
|
+
/**
|
|
3
|
+
* Adapts Rolldown's non-awaited HMR callback into lossless quiet-window publications.
|
|
4
|
+
*
|
|
5
|
+
* Debouncing the result stream itself would retain only the final callback and lose incremental patch factories that later
|
|
6
|
+
* patches provably do not reproduce. Instead, the debounced view is only a closing notifier for `buffer`: every callback is
|
|
7
|
+
* retained in arrival order, and one configured quiet period emits the complete window to the host's existing serialized
|
|
8
|
+
* writer. This first stream migration deliberately does not own physical state; `publish` and `reportError` remain synchronous
|
|
9
|
+
* admission callbacks so the dev host can enqueue both through its single writer.
|
|
10
|
+
*
|
|
11
|
+
* DevEngine failures are values, not Observable errors. They represent transient editor generations and carry no executable
|
|
12
|
+
* patch, so the stream reports the final error but otherwise removes them. Successful callbacks on either side remain ordered
|
|
13
|
+
* and lossless; Rolldown generated each against its unpublished client frontier, and the host delivers every retained payload.
|
|
14
|
+
* Completing the returned Subject flushes its current buffer synchronously, allowing host shutdown to await the resulting
|
|
15
|
+
* serialized task rather than silently dropping an admitted patch.
|
|
16
|
+
*
|
|
17
|
+
* Complexity is O(updates + changed files) per emitted window, with one retained reference per callback until the quiet edge.
|
|
18
|
+
*/
|
|
19
|
+
export function createHmrResultsStream(settleMilliseconds, scheduler, publish, reportError) {
|
|
20
|
+
/*
|
|
21
|
+
* This hot Subject is the sole mutable boundary between Rolldown's non-awaited callback and RxJS. Each next preserves one
|
|
22
|
+
* compiler generation by reference and in arrival order. buffer owns the temporary lossless window; debounceTime observes the
|
|
23
|
+
* same Subject only to decide when that window closes. Replacing this with a debounced scalar would discard patch factories,
|
|
24
|
+
* while letting callback Promises mutate host state directly would overlap publications. Completion flushes the final window
|
|
25
|
+
* before shutdown, after which the Subject is never reused.
|
|
26
|
+
*/
|
|
27
|
+
const results = new Subject();
|
|
28
|
+
results
|
|
29
|
+
.pipe(buffer(results.pipe(debounceTime(settleMilliseconds, scheduler))), filter((window) => window.length > 0))
|
|
30
|
+
.subscribe((window) => {
|
|
31
|
+
/*
|
|
32
|
+
* An Error is one source generation that produced no executable delta; it does not invalidate successful Rolldown
|
|
33
|
+
* callbacks already admitted on either side of it. Dropping the whole quiet window would therefore discard real
|
|
34
|
+
* patch factories, while starting a complete build would compile the same known-invalid editor contents. Keep the
|
|
35
|
+
* old runtime running, report only the latest diagnostic from a repeated parser burst, and continue below with the
|
|
36
|
+
* successful callback values exactly as if the temporary invalid save had never produced an HMR payload.
|
|
37
|
+
*/
|
|
38
|
+
const lastFailure = window.findLast((result) => result instanceof Error);
|
|
39
|
+
if (lastFailure) {
|
|
40
|
+
reportError(lastFailure);
|
|
41
|
+
}
|
|
42
|
+
const successfulWindow = window.filter((result) => !(result instanceof Error));
|
|
43
|
+
if (successfulWindow.length > 0) {
|
|
44
|
+
/*
|
|
45
|
+
* flatMap preserves callback arrival order and each callback's internal Rolldown order. Updates must not be
|
|
46
|
+
* deduplicated: later undelivered patches are deltas and do not reproduce factories from earlier sequences.
|
|
47
|
+
* changedFiles is opaque DevEngine metadata and has no identity semantics in the host, so preserving its raw
|
|
48
|
+
* concatenation is both cheaper and more faithful than maintaining a second Set-based interpretation here.
|
|
49
|
+
*/
|
|
50
|
+
publish({
|
|
51
|
+
updates: successfulWindow.flatMap((result) => result.updates),
|
|
52
|
+
changedFiles: successfulWindow.flatMap((result) => result.changedFiles)
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
return results;
|
|
57
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import type { GetModuleInfo, Plugin } from 'rolldown';
|
|
2
|
+
/** Final CSS extracted from Vite's transformed style module, before the shared WX compatibility pass. */
|
|
3
|
+
type ProcessedStyle = Readonly<{
|
|
4
|
+
css: string;
|
|
5
|
+
/** Marks roots whose generated utilities must be refreshed when JavaScript changes Tailwind candidates. */
|
|
6
|
+
isTailwindRoot: boolean;
|
|
7
|
+
}>;
|
|
8
|
+
/** Minimal structural view of DevEngine output; style reconciliation does not own chunks or other asset metadata. */
|
|
9
|
+
type CompleteOutputFile = Readonly<{
|
|
10
|
+
type: 'asset';
|
|
11
|
+
fileName: string;
|
|
12
|
+
source: string | Uint8Array;
|
|
13
|
+
}> | Readonly<{
|
|
14
|
+
type: 'chunk';
|
|
15
|
+
fileName: string;
|
|
16
|
+
}>;
|
|
17
|
+
export type StyleCaptureAction = Readonly<{
|
|
18
|
+
kind: 'capture-graph';
|
|
19
|
+
getModuleInfo: GetModuleInfo;
|
|
20
|
+
}> | Readonly<{
|
|
21
|
+
kind: 'capture-style';
|
|
22
|
+
id: string;
|
|
23
|
+
style: ProcessedStyle;
|
|
24
|
+
}>;
|
|
25
|
+
/**
|
|
26
|
+
* Captures final Vite CSS and composes the graph projection with its durable WXSS publisher.
|
|
27
|
+
*
|
|
28
|
+
* Rolldown remains authoritative for topology. Plugin hooks emit typed actions so the host serializes capture mutations with
|
|
29
|
+
* output and HMR publication; the projection and publisher below each own only one mutable concern.
|
|
30
|
+
*
|
|
31
|
+
* Complete-build path:
|
|
32
|
+
* final transform captures → DevEngine output write → graph reconciliation → App build rotation
|
|
33
|
+
*
|
|
34
|
+
* Incremental path:
|
|
35
|
+
* final transform captures → optional Tailwind root refresh → graph rendering → WXSS write → JavaScript patch publication
|
|
36
|
+
*
|
|
37
|
+
* Both paths render the same ordered App/Page graph projection. This prevents complete builds and HMR from implementing two
|
|
38
|
+
* subtly different CSS ownership policies, while keeping physical byte equality and atomic writes out of graph state.
|
|
39
|
+
*/
|
|
40
|
+
export declare function createStyleCapture({ applicationEntryIds, outDir, emit, transformTailwindRoot }: {
|
|
41
|
+
applicationEntryIds: readonly string[];
|
|
42
|
+
outDir: string;
|
|
43
|
+
emit: (action: StyleCaptureAction) => void;
|
|
44
|
+
transformTailwindRoot: (rootId: string, requestId: string) => Promise<Readonly<{
|
|
45
|
+
code: string;
|
|
46
|
+
}> | null>;
|
|
47
|
+
}): Readonly<{
|
|
48
|
+
captureGraph: (reader: GetModuleInfo) => void;
|
|
49
|
+
captureStyle: (id: string, style: ProcessedStyle) => void;
|
|
50
|
+
plugin: Plugin;
|
|
51
|
+
publishChanged: (changedIds: readonly string[]) => Promise<void>;
|
|
52
|
+
reconcileComplete: (output: readonly CompleteOutputFile[]) => Promise<void>;
|
|
53
|
+
}>;
|
|
54
|
+
export {};
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import { isCSSRequest } from 'vite';
|
|
2
|
+
import { normalizeModuleId } from '../../../utils/modules.js';
|
|
3
|
+
import { transformWxStyle } from '../styles/transform-wx-style.js';
|
|
4
|
+
import { composeGraphStyleCss, createGraphStylePlan, createTailwindSidecarId, extractViteCss, isGlobalStyleRequest } from '../styles/utils.js';
|
|
5
|
+
import { globalWxssFileName, writeHmrFile } from './hmr-files.js';
|
|
6
|
+
/**
|
|
7
|
+
* Captures final Vite CSS and composes the graph projection with its durable WXSS publisher.
|
|
8
|
+
*
|
|
9
|
+
* Rolldown remains authoritative for topology. Plugin hooks emit typed actions so the host serializes capture mutations with
|
|
10
|
+
* output and HMR publication; the projection and publisher below each own only one mutable concern.
|
|
11
|
+
*
|
|
12
|
+
* Complete-build path:
|
|
13
|
+
* final transform captures → DevEngine output write → graph reconciliation → App build rotation
|
|
14
|
+
*
|
|
15
|
+
* Incremental path:
|
|
16
|
+
* final transform captures → optional Tailwind root refresh → graph rendering → WXSS write → JavaScript patch publication
|
|
17
|
+
*
|
|
18
|
+
* Both paths render the same ordered App/Page graph projection. This prevents complete builds and HMR from implementing two
|
|
19
|
+
* subtly different CSS ownership policies, while keeping physical byte equality and atomic writes out of graph state.
|
|
20
|
+
*/
|
|
21
|
+
export function createStyleCapture({ applicationEntryIds, outDir, emit, transformTailwindRoot }) {
|
|
22
|
+
const projection = createStyleProjection({
|
|
23
|
+
applicationEntryIds: applicationEntryIds,
|
|
24
|
+
transformTailwindRoot: transformTailwindRoot
|
|
25
|
+
});
|
|
26
|
+
const publication = createStylePublication(outDir);
|
|
27
|
+
const plugin = {
|
|
28
|
+
name: 'vpt:wx-dev-style-capture',
|
|
29
|
+
buildStart() {
|
|
30
|
+
// Capture a live reader rather than a graph snapshot. Rolldown updates the capability as imports change, and a later
|
|
31
|
+
// complete generation replaces it through the host action queue before that generation can publish output.
|
|
32
|
+
emit({ kind: 'capture-graph', getModuleInfo: (moduleId) => this.getModuleInfo(moduleId) });
|
|
33
|
+
},
|
|
34
|
+
transform(code, id) {
|
|
35
|
+
if (!isGlobalStyleRequest(id)) {
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
// This host plugin runs after Vite's CSS transform, so `code` is the JavaScript wrapper containing final PostCSS and
|
|
39
|
+
// CSS-Module output. Capturing source CSS instead would lose generated class names and framework transformations.
|
|
40
|
+
const css = extractViteCss(code, id);
|
|
41
|
+
emit({
|
|
42
|
+
kind: 'capture-style',
|
|
43
|
+
id: normalizeModuleId(id),
|
|
44
|
+
style: {
|
|
45
|
+
css: css,
|
|
46
|
+
isTailwindRoot: css.includes('weapp-tailwindcss vite-generated-css:')
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
return {
|
|
52
|
+
captureGraph: projection.captureGraph,
|
|
53
|
+
captureStyle: projection.captureStyle,
|
|
54
|
+
plugin: plugin,
|
|
55
|
+
async publishChanged(changedIds) {
|
|
56
|
+
// A CSS edit already carries updated processed bytes. Any non-CSS edit can alter both imports and Tailwind class
|
|
57
|
+
// candidates, so it requires a fresh graph plan and Tailwind-root generation even when no .css ID changed directly.
|
|
58
|
+
const styleChanged = changedIds.some(isGlobalStyleRequest);
|
|
59
|
+
const candidatesChanged = changedIds.some((id) => !isCSSRequest(id));
|
|
60
|
+
if (!styleChanged && !candidatesChanged) {
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
await publication.publish(await projection.render(candidatesChanged));
|
|
64
|
+
},
|
|
65
|
+
async reconcileComplete(output) {
|
|
66
|
+
// Bundled development can omit CSS Modules from the compiler asset even with cssCodeSplit disabled. Observe the
|
|
67
|
+
// physical output first, then reconcile the same graph projection used by incremental HMR before App rotation.
|
|
68
|
+
publication.observeOutput(output);
|
|
69
|
+
await publication.publish(await projection.render(false));
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Owns the live graph capability and final transformed bytes for every observed style module.
|
|
75
|
+
*
|
|
76
|
+
* Rendering is O(V + E + C): graph planning visits each reachable module and edge once, then composition and WX conversion
|
|
77
|
+
* process C CSS bytes once. The only persistent memory is one processed byte string per style identity observed by the server.
|
|
78
|
+
*/
|
|
79
|
+
function createStyleProjection({ applicationEntryIds, transformTailwindRoot }) {
|
|
80
|
+
/*
|
|
81
|
+
* This mutable capability is rebound by buildStart for each complete generation. Rolldown keeps the function live across
|
|
82
|
+
* incremental graph edits, so rendering uses authoritative topology without maintaining a shadow graph.
|
|
83
|
+
*/
|
|
84
|
+
let getModuleInfo;
|
|
85
|
+
/*
|
|
86
|
+
* This mutable projection stores final CSS bytes that Rolldown does not retain. Successful transforms replace one entry;
|
|
87
|
+
* unreachable entries can remain because every render filters them through the current graph plan. Its size is bounded by
|
|
88
|
+
* style module identities observed during this server lifecycle.
|
|
89
|
+
*/
|
|
90
|
+
const processedStyles = new Map();
|
|
91
|
+
return {
|
|
92
|
+
captureGraph(reader) {
|
|
93
|
+
getModuleInfo = reader;
|
|
94
|
+
},
|
|
95
|
+
captureStyle(id, style) {
|
|
96
|
+
processedStyles.set(id, style);
|
|
97
|
+
},
|
|
98
|
+
async render(refreshTailwind) {
|
|
99
|
+
if (!getModuleInfo) {
|
|
100
|
+
throw new Error('WX style graph is unavailable before publication');
|
|
101
|
+
}
|
|
102
|
+
// App first and configured Pages afterward define one deterministic global cascade. The plan also removes stale map
|
|
103
|
+
// entries implicitly: styles no longer reachable from these roots never enter composition.
|
|
104
|
+
const styleIds = createGraphStylePlan(applicationEntryIds, getModuleInfo, (styleId) => processedStyles.has(styleId));
|
|
105
|
+
if (refreshTailwind) {
|
|
106
|
+
await refreshTailwindStyles(styleIds, processedStyles, transformTailwindRoot);
|
|
107
|
+
}
|
|
108
|
+
// Compose browser-facing transformed CSS first, then run one whole-file WX pass. Transforming modules independently
|
|
109
|
+
// would change cross-module cascade behavior and duplicate compatibility work.
|
|
110
|
+
const css = composeGraphStyleCss(styleIds, (styleId) => requireProcessedStyle(processedStyles, styleId).css);
|
|
111
|
+
return (await transformWxStyle(css)).css;
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Owns the physical WXSS frontier independently from graph capture and rendering.
|
|
117
|
+
*
|
|
118
|
+
* DevEngine writes complete output itself; incremental HMR does not. Observing complete output before publishing the projection
|
|
119
|
+
* gives both writers one byte frontier, so equality avoids redundant filesystem notifications without pretending the host owns
|
|
120
|
+
* the compiler's write transaction.
|
|
121
|
+
*/
|
|
122
|
+
function createStylePublication(outDir) {
|
|
123
|
+
/*
|
|
124
|
+
* This mutable value mirrors bytes durable on disk. Complete output adopts the compiler's external write before graph
|
|
125
|
+
* reconciliation; host publication advances it only after an atomic write succeeds or byte equality proves none is needed.
|
|
126
|
+
*/
|
|
127
|
+
let publishedWxss;
|
|
128
|
+
return {
|
|
129
|
+
observeOutput(output) {
|
|
130
|
+
// Missing WXSS means DevEngine intentionally reused the existing physical asset. Do not reset the frontier: doing so
|
|
131
|
+
// would force an identical rewrite and a spurious DevTools style event on every omitted complete generation.
|
|
132
|
+
const style = output.find((file) => file.type === 'asset' && file.fileName === globalWxssFileName);
|
|
133
|
+
if (style) {
|
|
134
|
+
publishedWxss = typeof style.source === 'string' ? style.source : new TextDecoder().decode(style.source);
|
|
135
|
+
}
|
|
136
|
+
},
|
|
137
|
+
async publish(wxss) {
|
|
138
|
+
if (wxss !== publishedWxss) {
|
|
139
|
+
// writeHmrFile uses atomic replacement; advance the frontier only after durability so a failed write leaves the
|
|
140
|
+
// last known physical generation available for the next reconciliation attempt.
|
|
141
|
+
await writeHmrFile(outDir, globalWxssFileName, wxss);
|
|
142
|
+
}
|
|
143
|
+
publishedWxss = wxss;
|
|
144
|
+
}
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Regenerates all reachable Tailwind roots and commits the cache only when every transform succeeds.
|
|
149
|
+
*
|
|
150
|
+
* Roots run concurrently because they are independent derivations of the same candidate generation. Results remain local until
|
|
151
|
+
* Promise.all fulfills; one failed root therefore preserves every prior root together instead of publishing a mixed generation.
|
|
152
|
+
*/
|
|
153
|
+
async function refreshTailwindStyles(styleIds, processedStyles, transformRoot) {
|
|
154
|
+
const roots = styleIds.filter((styleId) => requireProcessedStyle(processedStyles, styleId).isTailwindRoot);
|
|
155
|
+
const refreshedStyles = await Promise.all(roots.map(async (rootId) => {
|
|
156
|
+
const requestId = createTailwindSidecarId(rootId);
|
|
157
|
+
const result = await transformRoot(rootId, requestId);
|
|
158
|
+
if (!result) {
|
|
159
|
+
throw new Error(`Tailwind sidecar transform produced no result: ${requestId}`);
|
|
160
|
+
}
|
|
161
|
+
return [rootId, { css: extractViteCss(result.code, requestId), isTailwindRoot: true }];
|
|
162
|
+
}));
|
|
163
|
+
refreshedStyles.forEach(([rootId, style]) => {
|
|
164
|
+
processedStyles.set(rootId, style);
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
function requireProcessedStyle(processedStyles, styleId) {
|
|
168
|
+
const style = processedStyles.get(styleId);
|
|
169
|
+
if (!style) {
|
|
170
|
+
throw new Error(`WX style plan references uncaptured CSS: ${styleId}`);
|
|
171
|
+
}
|
|
172
|
+
return style;
|
|
173
|
+
}
|