vite-plugin-taro 0.5.12 → 0.5.13
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/h5/plugins.js +22 -1
- package/dist/node/plugins/tailwind/tailwind-css.d.ts +1 -0
- package/dist/node/plugins/tailwind/tailwind-css.js +3 -0
- package/dist/node/plugins/wx/dev/dev-host.d.ts +6 -2
- package/dist/node/plugins/wx/dev/dev-host.js +70 -5
- package/dist/node/plugins/wx/dev/hmr-files.d.ts +9 -0
- package/dist/node/plugins/wx/dev/hmr-files.js +11 -0
- package/dist/node/plugins/wx/dev/plugins.d.ts +21 -2
- package/dist/node/plugins/wx/dev/plugins.js +38 -2
- package/dist/node/plugins/wx/dev/styles/create-style-capture-plugin.d.ts +12 -0
- package/dist/node/plugins/wx/dev/styles/create-style-capture-plugin.js +21 -0
- package/dist/node/plugins/wx/dev/styles/publish-style-hmr.d.ts +27 -0
- package/dist/node/plugins/wx/dev/styles/publish-style-hmr.js +48 -0
- package/dist/node/plugins/wx/dev/wx-dev-options.d.ts +3 -2
- package/dist/node/plugins/wx/dev/wx-dev-options.js +7 -2
- package/dist/node/plugins/wx/output/files.d.ts +1 -1
- package/dist/node/plugins/wx/output/files.js +6 -1
- package/dist/node/plugins/wx/plugins.js +13 -6
- package/dist/node/plugins/wx/resolve/resolver.d.ts +2 -1
- package/dist/node/plugins/wx/resolve/resolver.js +31 -17
- package/dist/node/plugins/wx/styles/plugins.d.ts +3 -0
- package/dist/node/plugins/wx/styles/plugins.js +92 -0
- package/dist/node/plugins/wx/styles/transform-wx-style.d.ts +8 -0
- package/dist/node/plugins/wx/styles/transform-wx-style.js +9 -0
- package/dist/node/plugins/wx/styles/utils.d.ts +39 -0
- package/dist/node/plugins/wx/styles/utils.js +95 -0
- package/dist/node/utils/vite.d.ts +17 -0
- package/dist/node/utils/vite.js +43 -0
- package/dist/node/vite-plugin.js +0 -2
- package/package.json +3 -3
- package/src/node/plugins/h5/plugins.ts +22 -1
- package/src/node/plugins/tailwind/tailwind-css.ts +4 -0
- package/src/node/plugins/wx/dev/dev-host.ts +87 -5
- package/src/node/plugins/wx/dev/hmr-files.ts +12 -0
- package/src/node/plugins/wx/dev/plugins.ts +44 -4
- package/src/node/plugins/wx/dev/styles/create-style-capture-plugin.ts +34 -0
- package/src/node/plugins/wx/dev/styles/publish-style-hmr.ts +71 -0
- package/src/node/plugins/wx/dev/wx-dev-options.ts +9 -2
- package/src/node/plugins/wx/output/files.ts +6 -1
- package/src/node/plugins/wx/plugins.ts +16 -6
- package/src/node/plugins/wx/resolve/resolver.ts +33 -17
- package/src/node/plugins/wx/styles/plugins.ts +105 -0
- package/src/node/plugins/wx/styles/transform-wx-style.ts +11 -0
- package/src/node/plugins/wx/styles/utils.ts +119 -0
- package/src/node/utils/vite.ts +67 -0
- package/src/node/vite-plugin.ts +0 -2
- package/dist/node/plugins/css/plugins.d.ts +0 -4
- package/dist/node/plugins/css/plugins.js +0 -119
- package/src/node/plugins/css/plugins.ts +0 -135
|
@@ -1,14 +1,35 @@
|
|
|
1
1
|
import babel, { defineRolldownBabelPreset } from '@rolldown/plugin-babel';
|
|
2
|
+
import { WeappTailwindcss } from 'weapp-tailwindcss/vite';
|
|
2
3
|
import { esTarget } from '../../utils/constant.js';
|
|
3
4
|
import { toViteFileImportPath } from '../../utils/modules.js';
|
|
4
5
|
import { packageRequire } from '../../utils/packages.js';
|
|
5
6
|
import { clientTaroApiId } from '../client/client-taro.js';
|
|
7
|
+
import { tailwindcssBasedir } from '../tailwind/tailwind-css.js';
|
|
6
8
|
import { h5AppPath } from './constant.js';
|
|
7
9
|
import { createStencilClientAdapter } from './create-stencil-client-adapter.js';
|
|
8
10
|
import { createModuleResolver } from './resolver/module-resolver.js';
|
|
9
11
|
/** Creates the plugins that own the H5 target. */
|
|
10
12
|
export function createH5TargetPlugins(options) {
|
|
11
|
-
return [
|
|
13
|
+
return [
|
|
14
|
+
WeappTailwindcss({
|
|
15
|
+
appType: 'weapp-vite',
|
|
16
|
+
rewriteCssImports: false,
|
|
17
|
+
platform: 'web',
|
|
18
|
+
tailwindcssBasedir,
|
|
19
|
+
generator: {
|
|
20
|
+
target: 'web'
|
|
21
|
+
},
|
|
22
|
+
cssOptions: {
|
|
23
|
+
cssCalc: false,
|
|
24
|
+
autoprefixer: true,
|
|
25
|
+
rem2rpx: true,
|
|
26
|
+
px2rpx: true
|
|
27
|
+
},
|
|
28
|
+
logLevel: 'warn'
|
|
29
|
+
}),
|
|
30
|
+
...createH5SupportPlugins(),
|
|
31
|
+
createH5TargetPlugin(options)
|
|
32
|
+
];
|
|
12
33
|
}
|
|
13
34
|
/** Configures H5 resolution and supplies the specialized physical application entry. */
|
|
14
35
|
function createH5TargetPlugin(options) {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const tailwindcssBasedir: string;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type ViteDevServer } from 'vite';
|
|
2
2
|
import type { VitePluginTaroOptions } from '../../../../options.ts';
|
|
3
3
|
export type WxDevHost = Readonly<{
|
|
4
4
|
close: () => Promise<void>;
|
|
@@ -8,8 +8,12 @@ export type WxDevHost = Readonly<{
|
|
|
8
8
|
* with dev(...)) and the patch publisher, and replaces Vite's bundledDev.listen so the
|
|
9
9
|
* engine writes directly to the Mini Program output directory instead of serving browser
|
|
10
10
|
* HMR over HTTP.
|
|
11
|
+
*
|
|
12
|
+
* `applicationEntryIds` is the resolver's immutable cascade policy, not a second graph: it selects the App capsule followed
|
|
13
|
+
* by configured Page capsules from Rolldown's larger entry set. Rolldown remains the authority for every live import edge.
|
|
11
14
|
*/
|
|
12
|
-
export declare function createWxDevHost({ server, options }: {
|
|
15
|
+
export declare function createWxDevHost({ server, options, applicationEntryIds }: {
|
|
13
16
|
server: ViteDevServer;
|
|
14
17
|
options: VitePluginTaroOptions;
|
|
18
|
+
applicationEntryIds: readonly string[];
|
|
15
19
|
}): Promise<WxDevHost>;
|
|
@@ -1,25 +1,49 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
1
2
|
import path from 'node:path';
|
|
2
3
|
import colors from 'picocolors';
|
|
3
4
|
import { dev } from 'rolldown/experimental';
|
|
5
|
+
import { isCSSRequest } from 'vite';
|
|
4
6
|
import { SerializedTaskQueue } from '../../../utils/serialized-task-queue.js';
|
|
5
|
-
import {
|
|
7
|
+
import { createGraphStylePlan, isGlobalStyleRequest } from '../styles/utils.js';
|
|
8
|
+
import { developmentAppWxssFileName, hmrControlPath, hmrInfoFileName, hmrPatchesFileName, renderDevelopmentAppWxss, renderHmrInfo, renderInitialHmrPatches, writeHmrFile } from './hmr-files.js';
|
|
6
9
|
import { PatchPublisher } from './patch-publisher.js';
|
|
10
|
+
import { createStyleCapturePlugin } from './styles/create-style-capture-plugin.js';
|
|
11
|
+
import { globalWxssFileName, publishStyleHmr, refreshTailwindStyles } from './styles/publish-style-hmr.js';
|
|
7
12
|
import { installWxDevOptions, requireSingleOutput } from './wx-dev-options.js';
|
|
8
13
|
/**
|
|
9
14
|
* Creates the wx dev host: the adapter that owns the physical Rolldown DevEngine (created
|
|
10
15
|
* with dev(...)) and the patch publisher, and replaces Vite's bundledDev.listen so the
|
|
11
16
|
* engine writes directly to the Mini Program output directory instead of serving browser
|
|
12
17
|
* HMR over HTTP.
|
|
18
|
+
*
|
|
19
|
+
* `applicationEntryIds` is the resolver's immutable cascade policy, not a second graph: it selects the App capsule followed
|
|
20
|
+
* by configured Page capsules from Rolldown's larger entry set. Rolldown remains the authority for every live import edge.
|
|
13
21
|
*/
|
|
14
|
-
export async function createWxDevHost({ server, options }) {
|
|
22
|
+
export async function createWxDevHost({ server, options, applicationEntryIds }) {
|
|
15
23
|
const bundledDev = getBundledDev(server);
|
|
24
|
+
// This is the host's mutable style projection: CSS absent from Rolldown, the live graph capability rebound by each
|
|
25
|
+
// complete build, and the last durable WXSS bytes used only to suppress identical filesystem publications. Style capture
|
|
26
|
+
// remains O(1); derived order and reachability stay local to each HMR transaction.
|
|
27
|
+
const styleState = {
|
|
28
|
+
getModuleInfo: undefined,
|
|
29
|
+
processedStyles: new Map(),
|
|
30
|
+
publishedWxss: undefined
|
|
31
|
+
};
|
|
32
|
+
const styleCapturePlugin = createStyleCapturePlugin({
|
|
33
|
+
captureGraph(reader) {
|
|
34
|
+
styleState.getModuleInfo = reader;
|
|
35
|
+
},
|
|
36
|
+
captureStyle(id, style) {
|
|
37
|
+
styleState.processedStyles.set(id, style);
|
|
38
|
+
}
|
|
39
|
+
});
|
|
16
40
|
// Rolldown invokes output callbacks without awaiting their promises. This queue is the single owner of mutable HMR host
|
|
17
41
|
// state and physical metadata writes, preventing a later patch or build identity from being overwritten by older work.
|
|
18
42
|
const hostTasks = new SerializedTaskQueue((operation, error) => logWxError(server.config.logger, operation, error));
|
|
19
43
|
const publisher = new PatchPublisher((content) => writeHmrFile(server.config.build.outDir, hmrPatchesFileName, content));
|
|
20
44
|
// DevEngine does not reject run() after an initial plugin failure. The options layer owns a first-build buildEnd barrier
|
|
21
45
|
// and exposes only its result; later build errors continue independently through onOutput and onHmrUpdates.
|
|
22
|
-
const initialBuild = installWxDevOptions({ bundledDev, server, options });
|
|
46
|
+
const initialBuild = installWxDevOptions({ bundledDev, server, options, hostPlugins: [styleCapturePlugin] });
|
|
23
47
|
const engine = await createEngine();
|
|
24
48
|
// The wx dev host owns the only DevEngine. Vite's default listen() would create a second
|
|
25
49
|
// skip-write engine that renders into memory for browser HMR; instead the physical
|
|
@@ -134,12 +158,42 @@ export async function createWxDevHost({ server, options }) {
|
|
|
134
158
|
if (batch.length === 0) {
|
|
135
159
|
return;
|
|
136
160
|
}
|
|
161
|
+
// `onHmrUpdates` is the transaction boundary after every affected transform has updated graph and candidate state.
|
|
162
|
+
// Every non-CSS edit may alter imports or Tailwind classes; rendering broadly and comparing finalized bytes avoids
|
|
163
|
+
// source scanning while preventing unrelated JavaScript edits from notifying DevTools through an identical rename.
|
|
164
|
+
await publishChangedStyles(batch);
|
|
165
|
+
// Publish global.wxss before the matching JavaScript patch so DevTools observes a coherent HMR transaction.
|
|
137
166
|
// The physical file must exist before Rolldown advances: once committed, later patches may be generated relative to
|
|
138
167
|
// this batch even if DevTools has not observed its file event yet. PatchPublisher keeps the unapplied range cumulative,
|
|
139
168
|
// so any later file generation still carries every factory needed to bridge the runtime's older application frontier.
|
|
140
169
|
await publisher.produce(batch);
|
|
141
170
|
await commitPublishedBatch(batch);
|
|
142
171
|
}
|
|
172
|
+
/** Publishes the style projection for one completed patch transaction when its source or topology may have changed. */
|
|
173
|
+
async function publishChangedStyles(batch) {
|
|
174
|
+
const changedIds = batch.flatMap((patch) => patch.changedIds);
|
|
175
|
+
const styleChanged = changedIds.some(isGlobalStyleRequest);
|
|
176
|
+
const candidatesChanged = changedIds.some((id) => !isCSSRequest(id));
|
|
177
|
+
if (!styleChanged && !candidatesChanged) {
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
// buildStart installs this reader before Rolldown can produce either a complete output or an incremental batch.
|
|
181
|
+
const getModuleInfo = styleState.getModuleInfo;
|
|
182
|
+
if (!getModuleInfo) {
|
|
183
|
+
throw new Error('WX style graph is unavailable before HMR publication');
|
|
184
|
+
}
|
|
185
|
+
// Traverse topology exactly once; root refresh and final rendering consume this immutable transaction plan.
|
|
186
|
+
const styleIds = createGraphStylePlan(applicationEntryIds, getModuleInfo, (styleId) => styleState.processedStyles.has(styleId));
|
|
187
|
+
if (candidatesChanged) {
|
|
188
|
+
await refreshTailwindStyles(styleIds, styleState.processedStyles, async (rootId, requestId) => server.environments.client.pluginContainer.transform(await readFile(rootId, 'utf8'), requestId));
|
|
189
|
+
}
|
|
190
|
+
styleState.publishedWxss = await publishStyleHmr({
|
|
191
|
+
styleIds: styleIds,
|
|
192
|
+
outDir: server.config.build.outDir,
|
|
193
|
+
processedStyles: styleState.processedStyles,
|
|
194
|
+
publishedWxss: styleState.publishedWxss
|
|
195
|
+
});
|
|
196
|
+
}
|
|
143
197
|
/**
|
|
144
198
|
* Advances Rolldown's published frontier in the same sequence order materialized in the cumulative physical file.
|
|
145
199
|
*
|
|
@@ -161,7 +215,12 @@ export async function createWxDevHost({ server, options }) {
|
|
|
161
215
|
logWxError(server.config.logger, 'wx dev build failed', result);
|
|
162
216
|
return;
|
|
163
217
|
}
|
|
164
|
-
hostTasks.enqueue('wx dev build finalization failed',
|
|
218
|
+
hostTasks.enqueue('wx dev build finalization failed', finalizeDevOutput);
|
|
219
|
+
}
|
|
220
|
+
/** Rebinds the byte frontier after a complete build replaces the physical stylesheet outside HMR publication. */
|
|
221
|
+
async function finalizeDevOutput() {
|
|
222
|
+
styleState.publishedWxss = await readFile(path.join(server.config.build.outDir, globalWxssFileName), 'utf8');
|
|
223
|
+
await rotateBuildSession();
|
|
165
224
|
}
|
|
166
225
|
}
|
|
167
226
|
/** The bound HTTP port, or undefined before Vite's server is listening. */
|
|
@@ -176,7 +235,7 @@ function boundPort(server) {
|
|
|
176
235
|
}
|
|
177
236
|
return address.port;
|
|
178
237
|
}
|
|
179
|
-
/** Resets physical patches
|
|
238
|
+
/** Resets physical patches and then exposes one coherent build identity to a freshly compiled App heap. */
|
|
180
239
|
async function publishBuildMetadata(server, buildId, port) {
|
|
181
240
|
const info = {
|
|
182
241
|
buildId,
|
|
@@ -184,6 +243,12 @@ async function publishBuildMetadata(server, buildId, port) {
|
|
|
184
243
|
};
|
|
185
244
|
await writeHmrFile(server.config.build.outDir, hmrPatchesFileName, renderInitialHmrPatches());
|
|
186
245
|
await writeHmrFile(server.config.build.outDir, hmrInfoFileName, renderHmrInfo(info));
|
|
246
|
+
// `removeDevelopmentAppWxss` kept the previous physical wrapper in place while the complete output was written. Replace
|
|
247
|
+
// it only now, after the empty patch frontier and matching identity are durable. DevTools treats `app.wxss` as an App root,
|
|
248
|
+
// so this write intentionally causes the one full refresh allowed at a complete-build boundary; the refreshed App reads
|
|
249
|
+
// the new info above. Incremental updates must never write this file because an App refresh could destroy the heap while
|
|
250
|
+
// its JavaScript patch is being acknowledged. They publish only the imported `assets/global.wxss` stylesheet instead.
|
|
251
|
+
await writeHmrFile(server.config.build.outDir, developmentAppWxssFileName, renderDevelopmentAppWxss(buildId));
|
|
187
252
|
}
|
|
188
253
|
/** Replaces browser server URLs with the physical project directory consumed by WeChat DevTools. */
|
|
189
254
|
function installDevToolsPrinter(server) {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { BindingClientHmrUpdate } from 'rolldown/experimental';
|
|
2
|
+
export declare const developmentAppWxssFileName = "app.wxss";
|
|
2
3
|
export declare const hmrInfoFileName = "hmr/info.js";
|
|
3
4
|
export declare const hmrPatchesFileName = "hmr/patches.js";
|
|
4
5
|
/** Report endpoint path served by the wx dev control edge. */
|
|
@@ -16,6 +17,14 @@ export type PatchUpdate = Extract<BindingClientHmrUpdate['update'], {
|
|
|
16
17
|
export declare function renderHmrInfo(info: HmrInfo): string;
|
|
17
18
|
/** Provides a valid dependency before the host has a patch range to publish. */
|
|
18
19
|
export declare function renderInitialHmrPatches(): string;
|
|
20
|
+
/**
|
|
21
|
+
* Renders the native App style entry for one complete development build.
|
|
22
|
+
*
|
|
23
|
+
* Imported global CSS can change while the entry remains byte-identical. DevTools may then reuse an older persistent compile
|
|
24
|
+
* cache after it restarts. Tying this inert comment to the build identity invalidates that cache once per complete build,
|
|
25
|
+
* while incremental style updates continue changing only the imported file and therefore preserve the App heap.
|
|
26
|
+
*/
|
|
27
|
+
export declare function renderDevelopmentAppWxss(buildId: string): string;
|
|
19
28
|
/**
|
|
20
29
|
* Renders the cumulative patch suffix as inert CommonJS data.
|
|
21
30
|
*
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { randomUUID } from 'node:crypto';
|
|
2
2
|
import fs from 'node:fs/promises';
|
|
3
3
|
import path from 'node:path';
|
|
4
|
+
export const developmentAppWxssFileName = 'app.wxss';
|
|
4
5
|
export const hmrInfoFileName = 'hmr/info.js';
|
|
5
6
|
export const hmrPatchesFileName = 'hmr/patches.js';
|
|
6
7
|
/** Report endpoint path served by the wx dev control edge. */
|
|
@@ -13,6 +14,16 @@ export function renderHmrInfo(info) {
|
|
|
13
14
|
export function renderInitialHmrPatches() {
|
|
14
15
|
return 'module.exports = undefined;\n';
|
|
15
16
|
}
|
|
17
|
+
/**
|
|
18
|
+
* Renders the native App style entry for one complete development build.
|
|
19
|
+
*
|
|
20
|
+
* Imported global CSS can change while the entry remains byte-identical. DevTools may then reuse an older persistent compile
|
|
21
|
+
* cache after it restarts. Tying this inert comment to the build identity invalidates that cache once per complete build,
|
|
22
|
+
* while incremental style updates continue changing only the imported file and therefore preserve the App heap.
|
|
23
|
+
*/
|
|
24
|
+
export function renderDevelopmentAppWxss(buildId) {
|
|
25
|
+
return `@import "./assets/global.wxss";\n/* vpt-build:${buildId} */\n`;
|
|
26
|
+
}
|
|
16
27
|
/**
|
|
17
28
|
* Renders the cumulative patch suffix as inert CommonJS data.
|
|
18
29
|
*
|
|
@@ -1,10 +1,29 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type PluginOption } from 'vite';
|
|
2
2
|
import type { VitePluginTaroOptions } from '../../../../options.ts';
|
|
3
3
|
/**
|
|
4
4
|
* Adds the serve-only bundled-development plugin set for the wx target: the dev adapter,
|
|
5
5
|
* Page HMR activation, and React Refresh adaptation transforms.
|
|
6
|
+
*
|
|
7
|
+
* The ordered application entries cross this configuration boundary unchanged so the host can compose global CSS without
|
|
8
|
+
* reconstructing the resolver's App/Page ownership policy from unrelated Rolldown shell and transport entries.
|
|
6
9
|
*/
|
|
7
|
-
export declare function createWxDevelopmentPlugin(options: VitePluginTaroOptions): PluginOption[];
|
|
10
|
+
export declare function createWxDevelopmentPlugin(options: VitePluginTaroOptions, applicationEntryIds: readonly string[]): PluginOption[];
|
|
11
|
+
/**
|
|
12
|
+
* Transfers development ownership of `app.wxss` from complete output to the dev host.
|
|
13
|
+
*
|
|
14
|
+
* The ordinary WX output hook emits the static production wrapper during every complete build. In development, the existing
|
|
15
|
+
* physical wrapper instead contains the previous build ID. If the static asset remained in this bundle, the DevEngine would:
|
|
16
|
+
*
|
|
17
|
+
* 1. replace the versioned wrapper with static production bytes while JavaScript and HMR metadata are still being finalized;
|
|
18
|
+
* 2. let DevTools observe that root-style change and reload the App against the previous build identity;
|
|
19
|
+
* 3. let the host replace the wrapper again with the new build ID, causing a second App reload.
|
|
20
|
+
*
|
|
21
|
+
* Deleting only the in-memory bundle entry avoids both premature writes. Development sets `emptyOutDir: false`, so the prior
|
|
22
|
+
* physical `app.wxss` remains available while the complete output is written. The host replaces it exactly once after
|
|
23
|
+
* `hmr/patches.js` and `hmr/info.js` are durable. Incremental HMR never enters this complete-output hook and continues changing
|
|
24
|
+
* only `assets/global.wxss`, which preserves the App heap. The serve-only plugin leaves production output unchanged.
|
|
25
|
+
*/
|
|
26
|
+
export declare function removeDevelopmentAppWxss(bundle: Record<string, unknown>): void;
|
|
8
27
|
/** Ensures the Refresh hook exists before React's renderer evaluates and injects itself. */
|
|
9
28
|
export declare function injectReactRefreshBootstrap(code: string): {
|
|
10
29
|
code: string;
|
|
@@ -4,13 +4,18 @@ import { memoize } from '../../../utils/memoize.js';
|
|
|
4
4
|
import { normalizeModuleId } from '../../../utils/modules.js';
|
|
5
5
|
import { appCapsulePath, pageCapsulePath, rolldownRuntimeId, taroRuntimePath } from '../module.js';
|
|
6
6
|
import { createWxDevHost } from './dev-host.js';
|
|
7
|
+
import { developmentAppWxssFileName } from './hmr-files.js';
|
|
7
8
|
import { createWxReactRefreshTransforms } from './react-refresh.js';
|
|
8
9
|
const taroRuntimeId = '@tarojs/runtime';
|
|
9
10
|
/**
|
|
10
11
|
* Adds the serve-only bundled-development plugin set for the wx target: the dev adapter,
|
|
11
12
|
* Page HMR activation, and React Refresh adaptation transforms.
|
|
13
|
+
*
|
|
14
|
+
* The ordered application entries cross this configuration boundary unchanged so the host can compose global CSS without
|
|
15
|
+
* reconstructing the resolver's App/Page ownership policy from unrelated Rolldown shell and transport entries.
|
|
12
16
|
*/
|
|
13
|
-
export function createWxDevelopmentPlugin(options) {
|
|
17
|
+
export function createWxDevelopmentPlugin(options, applicationEntryIds) {
|
|
18
|
+
// This mutable handle transfers ownership from configureServer to closeBundle; at most one host exists per plugin instance.
|
|
14
19
|
let host = null;
|
|
15
20
|
// Portable hook filters stay broad; these exact identities exclude similarly named user modules.
|
|
16
21
|
const normalizedAppCapsulePath = normalizeModuleId(appCapsulePath);
|
|
@@ -47,7 +52,20 @@ export function createWxDevelopmentPlugin(options) {
|
|
|
47
52
|
// asks bundledDev to create its hard-coded skip-write DevEngine.
|
|
48
53
|
order: 'post',
|
|
49
54
|
async handler(server) {
|
|
50
|
-
host = await createWxDevHost({
|
|
55
|
+
host = await createWxDevHost({
|
|
56
|
+
server: server,
|
|
57
|
+
options: options,
|
|
58
|
+
applicationEntryIds: applicationEntryIds
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
generateBundle: {
|
|
63
|
+
order: 'post',
|
|
64
|
+
handler(_, bundle) {
|
|
65
|
+
// `vpt:wx` emits the production App wrapper during every complete build: initial startup and each
|
|
66
|
+
// recovery build, not just once when this plugin instance is created. Development transfers that file
|
|
67
|
+
// to the host so its only physical write happens after the matching build identity is durable.
|
|
68
|
+
removeDevelopmentAppWxss(bundle);
|
|
51
69
|
}
|
|
52
70
|
},
|
|
53
71
|
closeBundle() {
|
|
@@ -117,6 +135,24 @@ export function createWxDevelopmentPlugin(options) {
|
|
|
117
135
|
...createWxReactRefreshTransforms()
|
|
118
136
|
];
|
|
119
137
|
}
|
|
138
|
+
/**
|
|
139
|
+
* Transfers development ownership of `app.wxss` from complete output to the dev host.
|
|
140
|
+
*
|
|
141
|
+
* The ordinary WX output hook emits the static production wrapper during every complete build. In development, the existing
|
|
142
|
+
* physical wrapper instead contains the previous build ID. If the static asset remained in this bundle, the DevEngine would:
|
|
143
|
+
*
|
|
144
|
+
* 1. replace the versioned wrapper with static production bytes while JavaScript and HMR metadata are still being finalized;
|
|
145
|
+
* 2. let DevTools observe that root-style change and reload the App against the previous build identity;
|
|
146
|
+
* 3. let the host replace the wrapper again with the new build ID, causing a second App reload.
|
|
147
|
+
*
|
|
148
|
+
* Deleting only the in-memory bundle entry avoids both premature writes. Development sets `emptyOutDir: false`, so the prior
|
|
149
|
+
* physical `app.wxss` remains available while the complete output is written. The host replaces it exactly once after
|
|
150
|
+
* `hmr/patches.js` and `hmr/info.js` are durable. Incremental HMR never enters this complete-output hook and continues changing
|
|
151
|
+
* only `assets/global.wxss`, which preserves the App heap. The serve-only plugin leaves production output unchanged.
|
|
152
|
+
*/
|
|
153
|
+
export function removeDevelopmentAppWxss(bundle) {
|
|
154
|
+
delete bundle[developmentAppWxssFileName];
|
|
155
|
+
}
|
|
120
156
|
/** Ensures the Refresh hook exists before React's renderer evaluates and injects itself. */
|
|
121
157
|
export function injectReactRefreshBootstrap(code) {
|
|
122
158
|
return {
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { GetModuleInfo, Plugin } from 'rolldown';
|
|
2
|
+
export type ProcessedStyle = Readonly<{
|
|
3
|
+
css: string;
|
|
4
|
+
isTailwindRoot: boolean;
|
|
5
|
+
}>;
|
|
6
|
+
type StyleCaptureOptions = Readonly<{
|
|
7
|
+
captureGraph: (getModuleInfo: GetModuleInfo) => void;
|
|
8
|
+
captureStyle: (id: string, style: ProcessedStyle) => void;
|
|
9
|
+
}>;
|
|
10
|
+
/** Captures Vite's final development CSS and Rolldown's live graph without running the style pipeline twice. */
|
|
11
|
+
export declare function createStyleCapturePlugin({ captureGraph, captureStyle }: StyleCaptureOptions): Plugin;
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { normalizeModuleId } from '../../../../utils/modules.js';
|
|
2
|
+
import { extractViteCss, isGlobalStyleRequest } from '../../styles/utils.js';
|
|
3
|
+
/** Captures Vite's final development CSS and Rolldown's live graph without running the style pipeline twice. */
|
|
4
|
+
export function createStyleCapturePlugin({ captureGraph, captureStyle }) {
|
|
5
|
+
return {
|
|
6
|
+
name: 'vpt:wx-dev-style-capture',
|
|
7
|
+
buildStart() {
|
|
8
|
+
captureGraph((moduleId) => this.getModuleInfo(moduleId));
|
|
9
|
+
},
|
|
10
|
+
transform(code, id) {
|
|
11
|
+
if (!isGlobalStyleRequest(id)) {
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
const css = extractViteCss(code, id);
|
|
15
|
+
captureStyle(normalizeModuleId(id), {
|
|
16
|
+
css: css,
|
|
17
|
+
isTailwindRoot: css.includes('weapp-tailwindcss vite-generated-css:')
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { ProcessedStyle } from './create-style-capture-plugin.ts';
|
|
2
|
+
export declare const globalWxssFileName = "assets/global.wxss";
|
|
3
|
+
type StyleHmrOptions = Readonly<{
|
|
4
|
+
styleIds: readonly string[];
|
|
5
|
+
outDir: string;
|
|
6
|
+
processedStyles: ReadonlyMap<string, ProcessedStyle>;
|
|
7
|
+
publishedWxss: string | undefined;
|
|
8
|
+
}>;
|
|
9
|
+
/** Regenerates reachable Tailwind roots concurrently from upstream's current candidate state. */
|
|
10
|
+
export declare function refreshTailwindStyles(styleIds: readonly string[], processedStyles: Map<string, ProcessedStyle>, transformRoot: (rootId: string, requestId: string) => Promise<Readonly<{
|
|
11
|
+
code: string;
|
|
12
|
+
}> | null>): Promise<void>;
|
|
13
|
+
/**
|
|
14
|
+
* Materializes one host-owned style snapshot for a completed HMR transaction.
|
|
15
|
+
*
|
|
16
|
+
* Rolldown owns topology but does not retain Vite's final CSS module payload, while `processedStyles` owns those payloads but
|
|
17
|
+
* deliberately retains no topology. The caller supplies the transaction's one ordered graph plan; both Tailwind refresh and
|
|
18
|
+
* this renderer consume that same snapshot, so sidecar generation cannot cause a second topology traversal.
|
|
19
|
+
*
|
|
20
|
+
* Ordinary CSS is never transformed again here: capture already observed it after Vite/PostCSS. The composed stylesheet alone
|
|
21
|
+
* receives the same final WX conversion as complete builds. Byte equality with the host's physical publication frontier skips
|
|
22
|
+
* an atomic rename that would otherwise notify DevTools despite no style change. The returned bytes advance that frontier only
|
|
23
|
+
* after any required write succeeds. The caller awaits this before exposing the corresponding JavaScript patch.
|
|
24
|
+
* Complexity is O(styles + CSS bytes), after the caller's O(V + E) plan traversal.
|
|
25
|
+
*/
|
|
26
|
+
export declare function publishStyleHmr({ styleIds, outDir, processedStyles, publishedWxss }: StyleHmrOptions): Promise<string>;
|
|
27
|
+
export {};
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { transformWxStyle } from '../../styles/transform-wx-style.js';
|
|
2
|
+
import { composeGraphStyleCss, createTailwindSidecarId, extractViteCss } from '../../styles/utils.js';
|
|
3
|
+
import { writeHmrFile } from '../hmr-files.js';
|
|
4
|
+
export const globalWxssFileName = 'assets/global.wxss';
|
|
5
|
+
/** Regenerates reachable Tailwind roots concurrently from upstream's current candidate state. */
|
|
6
|
+
export async function refreshTailwindStyles(styleIds, processedStyles, transformRoot) {
|
|
7
|
+
const roots = styleIds.filter((styleId) => requireProcessedStyle(processedStyles, styleId).isTailwindRoot);
|
|
8
|
+
const refreshedStyles = await Promise.all(roots.map(async (rootId) => {
|
|
9
|
+
const requestId = createTailwindSidecarId(rootId);
|
|
10
|
+
const result = await transformRoot(rootId, requestId);
|
|
11
|
+
if (!result) {
|
|
12
|
+
throw new Error(`Tailwind sidecar transform produced no result: ${requestId}`);
|
|
13
|
+
}
|
|
14
|
+
return [rootId, { css: extractViteCss(result.code, requestId), isTailwindRoot: true }];
|
|
15
|
+
}));
|
|
16
|
+
// Commit the cache generation only after every independent root succeeds; a failed sibling cannot leave a mixed snapshot.
|
|
17
|
+
refreshedStyles.forEach(([rootId, style]) => {
|
|
18
|
+
processedStyles.set(rootId, style);
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Materializes one host-owned style snapshot for a completed HMR transaction.
|
|
23
|
+
*
|
|
24
|
+
* Rolldown owns topology but does not retain Vite's final CSS module payload, while `processedStyles` owns those payloads but
|
|
25
|
+
* deliberately retains no topology. The caller supplies the transaction's one ordered graph plan; both Tailwind refresh and
|
|
26
|
+
* this renderer consume that same snapshot, so sidecar generation cannot cause a second topology traversal.
|
|
27
|
+
*
|
|
28
|
+
* Ordinary CSS is never transformed again here: capture already observed it after Vite/PostCSS. The composed stylesheet alone
|
|
29
|
+
* receives the same final WX conversion as complete builds. Byte equality with the host's physical publication frontier skips
|
|
30
|
+
* an atomic rename that would otherwise notify DevTools despite no style change. The returned bytes advance that frontier only
|
|
31
|
+
* after any required write succeeds. The caller awaits this before exposing the corresponding JavaScript patch.
|
|
32
|
+
* Complexity is O(styles + CSS bytes), after the caller's O(V + E) plan traversal.
|
|
33
|
+
*/
|
|
34
|
+
export async function publishStyleHmr({ styleIds, outDir, processedStyles, publishedWxss }) {
|
|
35
|
+
const css = composeGraphStyleCss(styleIds, (styleId) => requireProcessedStyle(processedStyles, styleId).css);
|
|
36
|
+
const wxss = (await transformWxStyle(css)).css;
|
|
37
|
+
if (wxss !== publishedWxss) {
|
|
38
|
+
await writeHmrFile(outDir, globalWxssFileName, wxss);
|
|
39
|
+
}
|
|
40
|
+
return wxss;
|
|
41
|
+
}
|
|
42
|
+
function requireProcessedStyle(processedStyles, styleId) {
|
|
43
|
+
const style = processedStyles.get(styleId);
|
|
44
|
+
if (!style) {
|
|
45
|
+
throw new Error(`WX style plan references uncaptured CSS: ${styleId}`);
|
|
46
|
+
}
|
|
47
|
+
return style;
|
|
48
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { InputOptions, OutputOptions } from 'rolldown';
|
|
1
|
+
import type { InputOptions, OutputOptions, Plugin } from 'rolldown';
|
|
2
2
|
import { type DevEngine } from 'rolldown/experimental';
|
|
3
3
|
import type { ViteDevServer } from 'vite';
|
|
4
4
|
import type { VitePluginTaroOptions } from '../../../../options.ts';
|
|
@@ -16,10 +16,11 @@ export type BundledDev = {
|
|
|
16
16
|
triggerBundleRegenerationIfStale(): Promise<boolean>;
|
|
17
17
|
};
|
|
18
18
|
/** Installs the physical WX output and runtime conventions over Vite's browser-oriented bundled-development options. */
|
|
19
|
-
export declare function installWxDevOptions({ bundledDev, server, options }: {
|
|
19
|
+
export declare function installWxDevOptions({ bundledDev, server, options, hostPlugins }: {
|
|
20
20
|
bundledDev: BundledDev;
|
|
21
21
|
server: ViteDevServer;
|
|
22
22
|
options: VitePluginTaroOptions;
|
|
23
|
+
hostPlugins: Plugin[];
|
|
23
24
|
}): Promise<void>;
|
|
24
25
|
/** Returns the configured output after rejecting states unsupported by the physical WX engine. */
|
|
25
26
|
export declare function requireSingleOutput(rolldownOptions: BundledDevRolldownOptions): OutputOptions;
|
|
@@ -6,7 +6,7 @@ import { resolvePackageFile } from '../../../utils/packages.js';
|
|
|
6
6
|
import { appShellFileName } from '../module.js';
|
|
7
7
|
import { createWxDevMode } from './create-wx-dev-mode.js';
|
|
8
8
|
/** Installs the physical WX output and runtime conventions over Vite's browser-oriented bundled-development options. */
|
|
9
|
-
export function installWxDevOptions({ bundledDev, server, options }) {
|
|
9
|
+
export function installWxDevOptions({ bundledDev, server, options, hostPlugins }) {
|
|
10
10
|
// The buildEnd hook and its one-shot result belong to the same abstraction. Consumers can await startup without receiving
|
|
11
11
|
// a resolver capable of settling it externally.
|
|
12
12
|
const initialBuild = Promise.withResolvers();
|
|
@@ -47,7 +47,12 @@ export function installWxDevOptions({ bundledDev, server, options }) {
|
|
|
47
47
|
};
|
|
48
48
|
// Preserve the physical paths watched by WeChat DevTools across host restarts; the complete build overwrites every
|
|
49
49
|
// active output without disrupting the hot-reload watcher.
|
|
50
|
-
rolldownOptions.plugins = [
|
|
50
|
+
rolldownOptions.plugins = [
|
|
51
|
+
rolldownOptions.plugins,
|
|
52
|
+
hostPlugins,
|
|
53
|
+
reportInitialBuildPlugin,
|
|
54
|
+
createViteReporter(server)
|
|
55
|
+
];
|
|
51
56
|
disableViteOxcSourcemap(rolldownOptions.plugins);
|
|
52
57
|
return rolldownOptions;
|
|
53
58
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { Rolldown } from 'vite';
|
|
2
2
|
import type { VitePluginTaroOptions } from '../../../../options.ts';
|
|
3
3
|
import type { GeneratedSubpackage } from '../placement/placer.ts';
|
|
4
|
-
/** Creates every
|
|
4
|
+
/** Creates every compiler-owned WX file derived from the final Rolldown bundle. */
|
|
5
5
|
export declare function createOutputFiles({ bundle, options, subpackages, getModuleInfo }: {
|
|
6
6
|
bundle: Rolldown.OutputBundle;
|
|
7
7
|
options: VitePluginTaroOptions;
|
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
import { createNativeComponentOutput } from '../native/create-native-component-output.js';
|
|
2
2
|
import { createJsonAssets } from './json.js';
|
|
3
3
|
import { createTemplateAssets } from './templates.js';
|
|
4
|
-
/** Creates every
|
|
4
|
+
/** Creates every compiler-owned WX file derived from the final Rolldown bundle. */
|
|
5
5
|
export async function createOutputFiles({ bundle, options, subpackages, getModuleInfo }) {
|
|
6
6
|
const nativeOutput = await createNativeComponentOutput({ bundle, getModuleInfo });
|
|
7
7
|
return [
|
|
8
|
+
{
|
|
9
|
+
type: 'asset',
|
|
10
|
+
fileName: 'app.wxss',
|
|
11
|
+
source: '@import "./assets/global.wxss";\n'
|
|
12
|
+
},
|
|
8
13
|
...createJsonAssets({ options, subpackages, nativeComponents: nativeOutput.registrations }),
|
|
9
14
|
...createTemplateAssets(bundle, options, nativeOutput.registrations),
|
|
10
15
|
...nativeOutput.files
|
|
@@ -11,13 +11,20 @@ import { renderCapsule } from './render/capsule.js';
|
|
|
11
11
|
import { renderNative } from './render/native.js';
|
|
12
12
|
import { materializeTransport } from './render/transport.js';
|
|
13
13
|
import { createResolver } from './resolve/resolver.js';
|
|
14
|
+
import { createWxStylePlugins } from './styles/plugins.js';
|
|
14
15
|
/** Creates the complete plugin set for the wx target. */
|
|
15
16
|
export function createWxTargetPlugins(options) {
|
|
16
|
-
|
|
17
|
+
const resolver = createResolver(options);
|
|
18
|
+
// Reuse the resolver instance's ordered application subset. Rolldown's complete input also contains bootstrap, transport,
|
|
19
|
+
// shell, and component entries; entry membership alone cannot recover which roots define the App/Page CSS cascade.
|
|
20
|
+
return [
|
|
21
|
+
createWxStylePlugins(),
|
|
22
|
+
createWxPlugin(options, resolver),
|
|
23
|
+
createWxDevelopmentPlugin(options, resolver.applicationEntryIds)
|
|
24
|
+
];
|
|
17
25
|
}
|
|
18
26
|
/** Configures the complete wx target build pipeline. */
|
|
19
|
-
function createWxPlugin(options) {
|
|
20
|
-
const resolver = createResolver(options);
|
|
27
|
+
function createWxPlugin(options, resolver) {
|
|
21
28
|
const placer = createPlacer();
|
|
22
29
|
return {
|
|
23
30
|
name: 'vpt:wx',
|
|
@@ -103,10 +110,10 @@ function createWxPlugin(options) {
|
|
|
103
110
|
},
|
|
104
111
|
generateBundle: {
|
|
105
112
|
/*
|
|
106
|
-
* This hook is registered after
|
|
113
|
+
* This hook is registered after createWxStylePlugins() and shares hook-level `order: 'post'` with the adapted
|
|
107
114
|
* upstream hooks and VPT style finalizer. Registration order therefore guarantees that the imported global
|
|
108
|
-
* stylesheet is complete before native Page/component companions are emitted. Without this order, the finalizer
|
|
109
|
-
* incomplete Tailwind output or mistake native WXSS companions for additional compiler styles.
|
|
115
|
+
* stylesheet is complete before native Page/component companions are emitted. Without this order, the finalizer
|
|
116
|
+
* could consume incomplete Tailwind output or mistake native WXSS companions for additional compiler styles.
|
|
110
117
|
*/
|
|
111
118
|
order: 'post',
|
|
112
119
|
async handler(_, bundle) {
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import type { VitePluginTaroOptions } from '../../../../options.ts';
|
|
2
2
|
/** Creates the resolver and source specializer for the wx module graph. */
|
|
3
3
|
export declare function createResolver(options: VitePluginTaroOptions): {
|
|
4
|
-
input: Record<string, string>;
|
|
5
4
|
resolveId(id: string, importer: string | undefined, projectRoot: string): string | undefined;
|
|
6
5
|
specialize(code: string, id: string, sourcemap?: boolean): Promise<import("../../../utils/transform.ts").AstTransformResult> | undefined;
|
|
6
|
+
applicationEntryIds: string[];
|
|
7
|
+
input: any;
|
|
7
8
|
};
|