vite-plugin-taro 0.5.14 → 0.6.0
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 +2 -2
- package/dist/node/plugins/conditional/conditional-directives.d.ts +2 -2
- package/dist/node/plugins/h5/plugins.d.ts +2 -2
- package/dist/node/plugins/h5/resolver/module-resolver.d.ts +2 -2
- package/dist/node/plugins/h5/transform-app.d.ts +2 -2
- package/dist/node/plugins/h5/transform-app.js +2 -2
- package/dist/node/plugins/wx/dev/create-style-capture.d.ts +16 -4
- package/dist/node/plugins/wx/dev/create-style-capture.js +101 -53
- package/dist/node/plugins/wx/dev/dev-host.d.ts +2 -2
- package/dist/node/plugins/wx/dev/dev-host.js +13 -3
- package/dist/node/plugins/wx/dev/plugins.d.ts +2 -2
- package/dist/node/plugins/wx/dev/wx-dev-options.d.ts +2 -2
- package/dist/node/plugins/wx/output/files.d.ts +2 -2
- package/dist/node/plugins/wx/output/json.d.ts +3 -3
- package/dist/node/plugins/wx/output/json.js +1 -1
- package/dist/node/plugins/wx/output/templates.d.ts +2 -2
- package/dist/node/plugins/wx/plugins.d.ts +2 -2
- package/dist/node/plugins/wx/render/transport.js +1 -1
- package/dist/node/plugins/wx/resolve/resolver.d.ts +2 -2
- package/dist/node/plugins/wx/resolve/specialize-bootstrap.d.ts +2 -2
- package/dist/node/plugins/wx/resolve/specialize-bootstrap.js +1 -1
- package/dist/node/plugins/wx/resolve/specialize-page-capsule.d.ts +2 -2
- package/dist/node/plugins/wx/resolve/specialize-page-capsule.js +2 -2
- package/dist/node/utils/project-config.d.ts +2 -2
- package/dist/node/vpt.d.ts +4 -0
- package/dist/node/{vite-plugin.js → vpt.js} +1 -1
- package/dist/options.d.ts +65 -13
- package/dist/runtime/h5/app.js +2 -2
- package/dist/runtime/wx/amphibious/bootstrap.js +1 -1
- package/dist/runtime/wx/amphibious/transport.js +1 -1
- package/dist/runtime/wx/capsule/page.js +1 -1
- package/dist/vite.d.ts +2 -2
- package/dist/vite.js +1 -1
- package/package.json +3 -3
- package/src/node/plugins/client/client-taro.ts +3 -3
- package/src/node/plugins/conditional/conditional-directives.ts +3 -3
- package/src/node/plugins/h5/plugins.ts +3 -3
- package/src/node/plugins/h5/resolver/module-resolver.ts +2 -2
- package/src/node/plugins/h5/transform-app.ts +5 -5
- package/src/node/plugins/wx/dev/create-style-capture.ts +126 -57
- package/src/node/plugins/wx/dev/dev-host.ts +16 -5
- package/src/node/plugins/wx/dev/plugins.ts +2 -5
- package/src/node/plugins/wx/dev/wx-dev-options.ts +2 -2
- package/src/node/plugins/wx/output/files.ts +2 -2
- package/src/node/plugins/wx/output/json.ts +8 -8
- package/src/node/plugins/wx/output/templates.ts +3 -3
- package/src/node/plugins/wx/plugins.ts +3 -3
- package/src/node/plugins/wx/render/transport.ts +1 -1
- package/src/node/plugins/wx/resolve/resolver.ts +5 -5
- package/src/node/plugins/wx/resolve/specialize-bootstrap.ts +3 -3
- package/src/node/plugins/wx/resolve/specialize-page-capsule.ts +4 -4
- package/src/node/utils/project-config.ts +2 -2
- package/src/node/{vite-plugin.ts → vpt.ts} +2 -2
- package/src/options.ts +71 -13
- package/src/runtime/h5/app.ts +4 -4
- package/src/runtime/wx/amphibious/bootstrap.ts +2 -2
- package/src/runtime/wx/amphibious/transport.ts +2 -4
- package/src/runtime/wx/capsule/page.ts +3 -8
- package/src/vite.ts +2 -2
- package/dist/node/vite-plugin.d.ts +0 -4
package/dist/options.d.ts
CHANGED
|
@@ -1,20 +1,72 @@
|
|
|
1
1
|
/** A JSON object used by generated target configs. */
|
|
2
|
-
export type
|
|
2
|
+
export type VptJsonObject = Record<string, unknown>;
|
|
3
3
|
/** Build target handled by this plugin. */
|
|
4
|
-
export type
|
|
4
|
+
export type VptTarget = 'wx' | 'h5';
|
|
5
5
|
/** Configures one Taro page. */
|
|
6
|
-
export type
|
|
7
|
-
/**
|
|
6
|
+
export type VptPageOption = {
|
|
7
|
+
/**
|
|
8
|
+
* Taro route and output path without a file extension.
|
|
9
|
+
*
|
|
10
|
+
* The plugin resolves the page component from `src/${path}.tsx`, relative to the Vite project root. For example,
|
|
11
|
+
* `pages/home/index` resolves to `src/pages/home/index.tsx` and is emitted under `pages/home/index` for `wx`.
|
|
12
|
+
*/
|
|
8
13
|
path: string;
|
|
9
|
-
|
|
14
|
+
/**
|
|
15
|
+
* Target-independent Taro page configuration.
|
|
16
|
+
*
|
|
17
|
+
* For `wx`, these values form the generated `<path>.json`; the plugin augments `usingComponents` with its generated
|
|
18
|
+
* component registrations. For `h5`, the values are added to the corresponding Taro router entry.
|
|
19
|
+
*/
|
|
20
|
+
config: VptJsonObject;
|
|
10
21
|
};
|
|
11
|
-
/** Configures
|
|
12
|
-
export interface
|
|
13
|
-
|
|
22
|
+
/** Configures vpt for one build target. */
|
|
23
|
+
export interface VptOptions {
|
|
24
|
+
/**
|
|
25
|
+
* Platform produced by the current Vite invocation.
|
|
26
|
+
*
|
|
27
|
+
* Use `wx` to emit a WeChat Mini Program or `h5` to emit a browser application. The selected target controls Taro
|
|
28
|
+
* module resolution, conditional compilation, runtime bootstrapping, style processing, and output generation.
|
|
29
|
+
*/
|
|
30
|
+
target: VptTarget;
|
|
31
|
+
/**
|
|
32
|
+
* Source module that default-exports the root React application component.
|
|
33
|
+
*
|
|
34
|
+
* Relative paths are resolved from Vite's project root, for example `src/app.tsx`. The component wraps the active
|
|
35
|
+
* page through its `children` prop and is the appropriate place to import application-wide styles.
|
|
36
|
+
*/
|
|
14
37
|
app: string;
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
38
|
+
/**
|
|
39
|
+
* Complete ordered list of application pages.
|
|
40
|
+
*
|
|
41
|
+
* The declared order becomes the `pages` order in the generated `app.json`, the H5 route order, and the Page order
|
|
42
|
+
* in the application style cascade. Each Page source is resolved according to its `path`.
|
|
43
|
+
*/
|
|
44
|
+
pages: VptPageOption[];
|
|
45
|
+
/**
|
|
46
|
+
* Target-independent Taro application configuration.
|
|
47
|
+
*
|
|
48
|
+
* For `wx`, these values form the generated `app.json`. For `h5`, they configure the Taro application and router.
|
|
49
|
+
* The plugin always derives `pages` from {@link pages}; caller-provided `pages`, `subPackages`, and `subpackages`
|
|
50
|
+
* values are discarded because the build pipeline owns page order and generated package placement.
|
|
51
|
+
*/
|
|
52
|
+
appJson: VptJsonObject;
|
|
53
|
+
/**
|
|
54
|
+
* WeChat DevTools project configuration written to `project.config.json` without merging.
|
|
55
|
+
*
|
|
56
|
+
* This option is required so one configuration shape can be shared between targets, but it is only emitted for a
|
|
57
|
+
* `wx` build and is ignored for `h5`.
|
|
58
|
+
*/
|
|
59
|
+
projectConfigJson: VptJsonObject;
|
|
60
|
+
/**
|
|
61
|
+
* Local WeChat DevTools overrides written to `project.private.config.json` without merging.
|
|
62
|
+
*
|
|
63
|
+
* The file is emitted only when this value is provided for a `wx` build. It is ignored for `h5`.
|
|
64
|
+
*/
|
|
65
|
+
projectPrivateConfigJson?: VptJsonObject;
|
|
66
|
+
/**
|
|
67
|
+
* WeChat Mini Program indexing rules written to `sitemap.json` without merging.
|
|
68
|
+
*
|
|
69
|
+
* The file is emitted only when this value is provided for a `wx` build. It is ignored for `h5`.
|
|
70
|
+
*/
|
|
71
|
+
sitemapJson?: VptJsonObject;
|
|
20
72
|
}
|
package/dist/runtime/h5/app.js
CHANGED
|
@@ -5,9 +5,9 @@ import ReactDOM from 'react-dom/client';
|
|
|
5
5
|
// @ts-expect-error: The H5 build resolves this private App component.
|
|
6
6
|
import AppComponent from '\0vpt:app-component';
|
|
7
7
|
const browserWindow = window;
|
|
8
|
-
const config =
|
|
8
|
+
const config = __VPT_H5_APP_CONFIG__;
|
|
9
9
|
browserWindow.__taroAppConfig = config;
|
|
10
|
-
config.routes =
|
|
10
|
+
config.routes = __VPT_H5_ROUTES__;
|
|
11
11
|
const app = createReactApp(AppComponent, React, ReactDOM, config);
|
|
12
12
|
const history = createHashHistory({ window: browserWindow });
|
|
13
13
|
handleAppMount(config, history);
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import '../systemjs/system-core.js';
|
|
3
3
|
import { transport } from './transport.js';
|
|
4
4
|
/** Shares one App configuration object between the specialized bootstrap and App capsule. */
|
|
5
|
-
export const appConfig =
|
|
5
|
+
export const appConfig = __VPT_APP_CONFIG__;
|
|
6
6
|
// WX has no modulepreload transport. Genuine application import() boundaries retain System.import() and may load
|
|
7
7
|
// asynchronous subpackage or top-level-await graphs through this identity wrapper.
|
|
8
8
|
export const __vitePreload = (load) => load();
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
// Transport itself executes only as native CommonJS. It lives beside bootstrap because together they implement the
|
|
2
2
|
// amphibious boundary that publishes native namespaces to SystemJS without re-evaluating their module bodies.
|
|
3
3
|
/** Dispatches to one generated literal require and bridges amphibious CommonJS namespaces inline. */
|
|
4
|
-
export const transport =
|
|
4
|
+
export const transport = __VPT_TRANSPORT__;
|
|
@@ -3,5 +3,5 @@ import './app.js';
|
|
|
3
3
|
// @ts-expect-error: The wx build replaces this private import with the configured Page component.
|
|
4
4
|
import PageComponent from '\0vpt:page-component';
|
|
5
5
|
import { createPageConfig } from './taro-runtime.js';
|
|
6
|
-
const config = createPageConfig(PageComponent,
|
|
6
|
+
const config = createPageConfig(PageComponent, __VPT_PAGE_PATH__, { root: { cn: [] } }, __VPT_PAGE_CONFIG__);
|
|
7
7
|
export default config;
|
package/dist/vite.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { default } from './node/
|
|
2
|
-
export type {
|
|
1
|
+
export { default } from './node/vpt.ts';
|
|
2
|
+
export type { VptJsonObject, VptOptions, VptPageOption, VptTarget } from './options.ts';
|
package/dist/vite.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { default } from './node/
|
|
1
|
+
export { default } from './node/vpt.js';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vite-plugin-taro",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"author": "sep2",
|
|
5
5
|
"description": "Vite 8 plugin for building one React/Taro codebase for WeChat Mini Program and H5 targets.",
|
|
6
6
|
"type": "module",
|
|
@@ -76,8 +76,8 @@
|
|
|
76
76
|
"rxjs": "^7.8.2",
|
|
77
77
|
"tailwindcss": "^4.3.3",
|
|
78
78
|
"weapp-tailwindcss": "^5.2.11",
|
|
79
|
-
"@tarojs/
|
|
80
|
-
"@tarojs/react": "npm:vite-plugin-taro-react@0.
|
|
79
|
+
"@tarojs/react": "npm:vite-plugin-taro-react@0.6.0",
|
|
80
|
+
"@tarojs/plugin-framework-react": "npm:vite-plugin-taro-plugin-framework-react@0.6.0"
|
|
81
81
|
},
|
|
82
82
|
"peerDependencies": {
|
|
83
83
|
"react": "^19.0.0",
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { normalizePath, type Plugin } from 'vite'
|
|
2
|
-
import type {
|
|
2
|
+
import type { VptTarget } from '../../../options.ts'
|
|
3
3
|
import { normalizeModuleId } from '../../utils/modules.ts'
|
|
4
4
|
import { resolvePackageFile } from '../../utils/packages.ts'
|
|
5
5
|
import { clientTaroNativeId } from './constant.ts'
|
|
@@ -32,7 +32,7 @@ const clientTaroModules = new Map([
|
|
|
32
32
|
])
|
|
33
33
|
|
|
34
34
|
/** Creates the shared Taro facade backed by the selected target's API implementation. */
|
|
35
|
-
export function createClientTaroPlugin(target:
|
|
35
|
+
export function createClientTaroPlugin(target: VptTarget): Plugin {
|
|
36
36
|
const platformTaroId = resolvePlatformTaroId(target)
|
|
37
37
|
|
|
38
38
|
return {
|
|
@@ -62,7 +62,7 @@ export function createClientTaroPlugin(target: VitePluginTaroTarget): Plugin {
|
|
|
62
62
|
}
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
-
function resolvePlatformTaroId(target:
|
|
65
|
+
function resolvePlatformTaroId(target: VptTarget): string {
|
|
66
66
|
return target === 'h5' ? '@tarojs/plugin-platform-h5/dist/runtime/apis' : '@tarojs/taro'
|
|
67
67
|
}
|
|
68
68
|
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import type { Plugin } from 'vite'
|
|
2
|
-
import type {
|
|
2
|
+
import type { VptTarget } from '../../../options.ts'
|
|
3
3
|
import { normalizeModuleId } from '../../utils/modules.ts'
|
|
4
4
|
|
|
5
5
|
/** Creates source-level target conditional handling shared by H5 and WX. */
|
|
6
|
-
export function createConditionalDirectivePlugin(target:
|
|
6
|
+
export function createConditionalDirectivePlugin(target: VptTarget): Plugin {
|
|
7
7
|
return {
|
|
8
8
|
name: 'vpt:conditional-directives',
|
|
9
9
|
enforce: 'pre',
|
|
@@ -37,7 +37,7 @@ type DirectiveFrame = {
|
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
/** Keeps only the source branches active for one build target. */
|
|
40
|
-
function transformConditionalDirectives(code: string, target:
|
|
40
|
+
function transformConditionalDirectives(code: string, target: VptTarget): string {
|
|
41
41
|
const lines = code.match(/[^\n]*(?:\n|$)/g) ?? []
|
|
42
42
|
const frames: DirectiveFrame[] = []
|
|
43
43
|
let transformed = ''
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import babel, { defineRolldownBabelPreset } from '@rolldown/plugin-babel'
|
|
2
2
|
import type { HtmlTagDescriptor, Plugin, PluginOption } from 'vite'
|
|
3
3
|
import { WeappTailwindcss } from 'weapp-tailwindcss/vite'
|
|
4
|
-
import type {
|
|
4
|
+
import type { VptOptions } from '../../../options.ts'
|
|
5
5
|
import { esTarget } from '../../utils/constant.ts'
|
|
6
6
|
import { toViteFileImportPath } from '../../utils/modules.ts'
|
|
7
7
|
import { packageRequire } from '../../utils/packages.ts'
|
|
@@ -12,7 +12,7 @@ import { createStencilClientAdapter } from './create-stencil-client-adapter.ts'
|
|
|
12
12
|
import { createModuleResolver } from './resolver/module-resolver.ts'
|
|
13
13
|
|
|
14
14
|
/** Creates the plugins that own the H5 target. */
|
|
15
|
-
export function createH5TargetPlugins(options:
|
|
15
|
+
export function createH5TargetPlugins(options: VptOptions): PluginOption[] {
|
|
16
16
|
return [
|
|
17
17
|
WeappTailwindcss({
|
|
18
18
|
appType: 'weapp-vite',
|
|
@@ -36,7 +36,7 @@ export function createH5TargetPlugins(options: VitePluginTaroOptions): PluginOpt
|
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
/** Configures H5 resolution and supplies the specialized physical application entry. */
|
|
39
|
-
function createH5TargetPlugin(options:
|
|
39
|
+
function createH5TargetPlugin(options: VptOptions): Plugin {
|
|
40
40
|
const moduleResolver = createModuleResolver(options)
|
|
41
41
|
|
|
42
42
|
return {
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { normalizePath } from 'vite'
|
|
2
|
-
import type {
|
|
2
|
+
import type { VptOptions } from '../../../../options.ts'
|
|
3
3
|
import { normalizeModuleId, resolveAppComponentPath } from '../../../utils/modules.ts'
|
|
4
4
|
import { appComponentId } from '../../client/constant.ts'
|
|
5
5
|
import { h5AppPath } from '../constant.ts'
|
|
6
6
|
import { transformH5App } from '../transform-app.ts'
|
|
7
7
|
|
|
8
8
|
/** Creates H5 application module resolution and specialization. */
|
|
9
|
-
export function createModuleResolver(options:
|
|
9
|
+
export function createModuleResolver(options: VptOptions) {
|
|
10
10
|
return {
|
|
11
11
|
resolveId({ id, projectRoot }: { id: string; projectRoot: string }): string | undefined {
|
|
12
12
|
if (id === appComponentId) {
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { types } from '@babel/core'
|
|
2
|
-
import type {
|
|
2
|
+
import type { VptOptions, VptPageOption } from '../../../options.ts'
|
|
3
3
|
import { createPageComponentImportPath } from '../../utils/modules.ts'
|
|
4
4
|
import { createAppConfig } from '../../utils/project-config.ts'
|
|
5
5
|
import { type AstTransformResult, replaceWithAst } from '../../utils/transform.ts'
|
|
6
6
|
|
|
7
|
-
const appConfigPlaceholder = '
|
|
8
|
-
const routesPlaceholder = '
|
|
7
|
+
const appConfigPlaceholder = '__VPT_H5_APP_CONFIG__'
|
|
8
|
+
const routesPlaceholder = '__VPT_H5_ROUTES__'
|
|
9
9
|
|
|
10
10
|
/** Specializes the physical H5 App for one configured project. */
|
|
11
11
|
export async function transformH5App({
|
|
@@ -17,7 +17,7 @@ export async function transformH5App({
|
|
|
17
17
|
}: {
|
|
18
18
|
code: string
|
|
19
19
|
id: string
|
|
20
|
-
options:
|
|
20
|
+
options: VptOptions
|
|
21
21
|
projectRoot: string
|
|
22
22
|
sourcemap?: boolean
|
|
23
23
|
}): Promise<AstTransformResult> {
|
|
@@ -56,7 +56,7 @@ function createRoute({
|
|
|
56
56
|
page,
|
|
57
57
|
projectRoot
|
|
58
58
|
}: {
|
|
59
|
-
page:
|
|
59
|
+
page: VptPageOption
|
|
60
60
|
projectRoot: string
|
|
61
61
|
}): ReturnType<typeof types.objectExpression> {
|
|
62
62
|
const pageComponentPath = createPageComponentImportPath({ pagePath: page.path, projectRoot })
|
|
@@ -11,11 +11,14 @@ import {
|
|
|
11
11
|
} from '../styles/utils.ts'
|
|
12
12
|
import { globalWxssFileName, writeHmrFile } from './hmr-files.ts'
|
|
13
13
|
|
|
14
|
+
/** Final CSS extracted from Vite's transformed style module, before the shared WX compatibility pass. */
|
|
14
15
|
type ProcessedStyle = Readonly<{
|
|
15
16
|
css: string
|
|
17
|
+
/** Marks roots whose generated utilities must be refreshed when JavaScript changes Tailwind candidates. */
|
|
16
18
|
isTailwindRoot: boolean
|
|
17
19
|
}>
|
|
18
20
|
|
|
21
|
+
/** Minimal structural view of DevEngine output; style reconciliation does not own chunks or other asset metadata. */
|
|
19
22
|
type CompleteOutputFile =
|
|
20
23
|
| Readonly<{ type: 'asset'; fileName: string; source: string | Uint8Array }>
|
|
21
24
|
| Readonly<{ type: 'chunk'; fileName: string }>
|
|
@@ -25,10 +28,19 @@ export type StyleCaptureAction =
|
|
|
25
28
|
| Readonly<{ kind: 'capture-style'; id: string; style: ProcessedStyle }>
|
|
26
29
|
|
|
27
30
|
/**
|
|
28
|
-
*
|
|
31
|
+
* Captures final Vite CSS and composes the graph projection with its durable WXSS publisher.
|
|
29
32
|
*
|
|
30
|
-
* Rolldown remains authoritative for topology
|
|
31
|
-
*
|
|
33
|
+
* Rolldown remains authoritative for topology. Plugin hooks emit typed actions so the host serializes capture mutations with
|
|
34
|
+
* output and HMR publication; the projection and publisher below each own only one mutable concern.
|
|
35
|
+
*
|
|
36
|
+
* Complete-build path:
|
|
37
|
+
* final transform captures → DevEngine output write → graph reconciliation → App build rotation
|
|
38
|
+
*
|
|
39
|
+
* Incremental path:
|
|
40
|
+
* final transform captures → optional Tailwind root refresh → graph rendering → WXSS write → JavaScript patch publication
|
|
41
|
+
*
|
|
42
|
+
* Both paths render the same ordered App/Page graph projection. This prevents complete builds and HMR from implementing two
|
|
43
|
+
* subtly different CSS ownership policies, while keeping physical byte equality and atomic writes out of graph state.
|
|
32
44
|
*/
|
|
33
45
|
export function createStyleCapture({
|
|
34
46
|
applicationEntryIds,
|
|
@@ -41,45 +53,23 @@ export function createStyleCapture({
|
|
|
41
53
|
emit: (action: StyleCaptureAction) => void
|
|
42
54
|
transformTailwindRoot: (rootId: string, requestId: string) => Promise<Readonly<{ code: string }> | null>
|
|
43
55
|
}): Readonly<{
|
|
44
|
-
bindOutput: (output: readonly CompleteOutputFile[]) => void
|
|
45
56
|
captureGraph: (reader: GetModuleInfo) => void
|
|
46
57
|
captureStyle: (id: string, style: ProcessedStyle) => void
|
|
47
58
|
plugin: Plugin
|
|
48
59
|
publishChanged: (changedIds: readonly string[]) => Promise<void>
|
|
60
|
+
reconcileComplete: (output: readonly CompleteOutputFile[]) => Promise<void>
|
|
49
61
|
}> {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
*/
|
|
56
|
-
let getModuleInfo: GetModuleInfo | undefined
|
|
57
|
-
/*
|
|
58
|
-
* This mutable Map is the CSS projection Rolldown does not retain: successful final transform hooks replace one module's
|
|
59
|
-
* processed bytes, failed transforms intentionally leave its last valid generation, and a successful multi-root Tailwind
|
|
60
|
-
* refresh commits all replacements only after every sibling resolves. Entries are not deleted when topology changes because
|
|
61
|
-
* reachability comes from the live graph plan; eager deletion would need a duplicate reverse graph and could remove CSS still
|
|
62
|
-
* shared by another App/Page root. Its size is bounded by style module identities seen during this server lifecycle.
|
|
63
|
-
*/
|
|
64
|
-
const processedStyles = new Map<string, ProcessedStyle>()
|
|
65
|
-
/*
|
|
66
|
-
* This mutable value mirrors the WXSS bytes currently durable on disk. It has one owner but two real transition sources:
|
|
67
|
-
*
|
|
68
|
-
* 1. DevEngine physically writes complete output before onOutput, so bindOutput only observes and adopts that external
|
|
69
|
-
* commit. An omitted asset means DevEngine preserved the existing file and this value must remain unchanged.
|
|
70
|
-
* 2. Incremental HMR is physically written by this host, so publishChanged advances the value only after its atomic write
|
|
71
|
-
* succeeds (or after byte equality proves no write was needed).
|
|
72
|
-
*
|
|
73
|
-
* Combining these operations behind one generic update event would still require branching between “observe an existing
|
|
74
|
-
* write” and “perform a new write”, while hiding their different durability boundaries. A genuine single path would require
|
|
75
|
-
* preventing DevEngine from writing complete WXSS and transferring that entire output responsibility to the host, adding
|
|
76
|
-
* asset interception and ordering machinery. The two explicit methods are therefore the smallest accurate state model.
|
|
77
|
-
*/
|
|
78
|
-
let publishedWxss: string | undefined
|
|
62
|
+
const projection = createStyleProjection({
|
|
63
|
+
applicationEntryIds: applicationEntryIds,
|
|
64
|
+
transformTailwindRoot: transformTailwindRoot
|
|
65
|
+
})
|
|
66
|
+
const publication = createStylePublication(outDir)
|
|
79
67
|
|
|
80
68
|
const plugin: Plugin = {
|
|
81
69
|
name: 'vpt:wx-dev-style-capture',
|
|
82
70
|
buildStart() {
|
|
71
|
+
// Capture a live reader rather than a graph snapshot. Rolldown updates the capability as imports change, and a later
|
|
72
|
+
// complete generation replaces it through the host action queue before that generation can publish output.
|
|
83
73
|
emit({ kind: 'capture-graph', getModuleInfo: (moduleId) => this.getModuleInfo(moduleId) })
|
|
84
74
|
},
|
|
85
75
|
transform(code, id) {
|
|
@@ -87,6 +77,8 @@ export function createStyleCapture({
|
|
|
87
77
|
return
|
|
88
78
|
}
|
|
89
79
|
|
|
80
|
+
// This host plugin runs after Vite's CSS transform, so `code` is the JavaScript wrapper containing final PostCSS and
|
|
81
|
+
// CSS-Module output. Capturing source CSS instead would lose generated class names and framework transformations.
|
|
90
82
|
const css = extractViteCss(code, id)
|
|
91
83
|
emit({
|
|
92
84
|
kind: 'capture-style',
|
|
@@ -100,55 +92,132 @@ export function createStyleCapture({
|
|
|
100
92
|
}
|
|
101
93
|
|
|
102
94
|
return {
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
)
|
|
112
|
-
|
|
113
|
-
publishedWxss = typeof style.source === 'string' ? style.source : new TextDecoder().decode(style.source)
|
|
95
|
+
captureGraph: projection.captureGraph,
|
|
96
|
+
captureStyle: projection.captureStyle,
|
|
97
|
+
plugin: plugin,
|
|
98
|
+
async publishChanged(changedIds) {
|
|
99
|
+
// A CSS edit already carries updated processed bytes. Any non-CSS edit can alter both imports and Tailwind class
|
|
100
|
+
// candidates, so it requires a fresh graph plan and Tailwind-root generation even when no .css ID changed directly.
|
|
101
|
+
const styleChanged = changedIds.some(isGlobalStyleRequest)
|
|
102
|
+
const candidatesChanged = changedIds.some((id) => !isCSSRequest(id))
|
|
103
|
+
if (!styleChanged && !candidatesChanged) {
|
|
104
|
+
return
|
|
114
105
|
}
|
|
106
|
+
await publication.publish(await projection.render(candidatesChanged))
|
|
115
107
|
},
|
|
108
|
+
async reconcileComplete(output) {
|
|
109
|
+
// Bundled development can omit CSS Modules from the compiler asset even with cssCodeSplit disabled. Observe the
|
|
110
|
+
// physical output first, then reconcile the same graph projection used by incremental HMR before App rotation.
|
|
111
|
+
publication.observeOutput(output)
|
|
112
|
+
await publication.publish(await projection.render(false))
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Owns the live graph capability and final transformed bytes for every observed style module.
|
|
119
|
+
*
|
|
120
|
+
* Rendering is O(V + E + C): graph planning visits each reachable module and edge once, then composition and WX conversion
|
|
121
|
+
* process C CSS bytes once. The only persistent memory is one processed byte string per style identity observed by the server.
|
|
122
|
+
*/
|
|
123
|
+
function createStyleProjection({
|
|
124
|
+
applicationEntryIds,
|
|
125
|
+
transformTailwindRoot
|
|
126
|
+
}: {
|
|
127
|
+
applicationEntryIds: readonly string[]
|
|
128
|
+
transformTailwindRoot: (rootId: string, requestId: string) => Promise<Readonly<{ code: string }> | null>
|
|
129
|
+
}): Readonly<{
|
|
130
|
+
captureGraph: (reader: GetModuleInfo) => void
|
|
131
|
+
captureStyle: (id: string, style: ProcessedStyle) => void
|
|
132
|
+
render: (refreshTailwind: boolean) => Promise<string>
|
|
133
|
+
}> {
|
|
134
|
+
/*
|
|
135
|
+
* This mutable capability is rebound by buildStart for each complete generation. Rolldown keeps the function live across
|
|
136
|
+
* incremental graph edits, so rendering uses authoritative topology without maintaining a shadow graph.
|
|
137
|
+
*/
|
|
138
|
+
let getModuleInfo: GetModuleInfo | undefined
|
|
139
|
+
/*
|
|
140
|
+
* This mutable projection stores final CSS bytes that Rolldown does not retain. Successful transforms replace one entry;
|
|
141
|
+
* unreachable entries can remain because every render filters them through the current graph plan. Its size is bounded by
|
|
142
|
+
* style module identities observed during this server lifecycle.
|
|
143
|
+
*/
|
|
144
|
+
const processedStyles = new Map<string, ProcessedStyle>()
|
|
145
|
+
|
|
146
|
+
return {
|
|
116
147
|
captureGraph(reader) {
|
|
117
148
|
getModuleInfo = reader
|
|
118
149
|
},
|
|
119
150
|
captureStyle(id, style) {
|
|
120
151
|
processedStyles.set(id, style)
|
|
121
152
|
},
|
|
122
|
-
|
|
123
|
-
async publishChanged(changedIds) {
|
|
124
|
-
const styleChanged = changedIds.some(isGlobalStyleRequest)
|
|
125
|
-
const candidatesChanged = changedIds.some((id) => !isCSSRequest(id))
|
|
126
|
-
if (!styleChanged && !candidatesChanged) {
|
|
127
|
-
return
|
|
128
|
-
}
|
|
153
|
+
async render(refreshTailwind) {
|
|
129
154
|
if (!getModuleInfo) {
|
|
130
|
-
throw new Error('WX style graph is unavailable before
|
|
155
|
+
throw new Error('WX style graph is unavailable before publication')
|
|
131
156
|
}
|
|
132
157
|
|
|
133
|
-
//
|
|
158
|
+
// App first and configured Pages afterward define one deterministic global cascade. The plan also removes stale map
|
|
159
|
+
// entries implicitly: styles no longer reachable from these roots never enter composition.
|
|
134
160
|
const styleIds = createGraphStylePlan(applicationEntryIds, getModuleInfo, (styleId) =>
|
|
135
161
|
processedStyles.has(styleId)
|
|
136
162
|
)
|
|
137
|
-
if (
|
|
163
|
+
if (refreshTailwind) {
|
|
138
164
|
await refreshTailwindStyles(styleIds, processedStyles, transformTailwindRoot)
|
|
139
165
|
}
|
|
166
|
+
|
|
167
|
+
// Compose browser-facing transformed CSS first, then run one whole-file WX pass. Transforming modules independently
|
|
168
|
+
// would change cross-module cascade behavior and duplicate compatibility work.
|
|
140
169
|
const css = composeGraphStyleCss(styleIds, (styleId) => requireProcessedStyle(processedStyles, styleId).css)
|
|
141
|
-
|
|
170
|
+
return (await transformWxStyle(css)).css
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Owns the physical WXSS frontier independently from graph capture and rendering.
|
|
177
|
+
*
|
|
178
|
+
* DevEngine writes complete output itself; incremental HMR does not. Observing complete output before publishing the projection
|
|
179
|
+
* gives both writers one byte frontier, so equality avoids redundant filesystem notifications without pretending the host owns
|
|
180
|
+
* the compiler's write transaction.
|
|
181
|
+
*/
|
|
182
|
+
function createStylePublication(outDir: string): Readonly<{
|
|
183
|
+
observeOutput: (output: readonly CompleteOutputFile[]) => void
|
|
184
|
+
publish: (wxss: string) => Promise<void>
|
|
185
|
+
}> {
|
|
186
|
+
/*
|
|
187
|
+
* This mutable value mirrors bytes durable on disk. Complete output adopts the compiler's external write before graph
|
|
188
|
+
* reconciliation; host publication advances it only after an atomic write succeeds or byte equality proves none is needed.
|
|
189
|
+
*/
|
|
190
|
+
let publishedWxss: string | undefined
|
|
191
|
+
|
|
192
|
+
return {
|
|
193
|
+
observeOutput(output) {
|
|
194
|
+
// Missing WXSS means DevEngine intentionally reused the existing physical asset. Do not reset the frontier: doing so
|
|
195
|
+
// would force an identical rewrite and a spurious DevTools style event on every omitted complete generation.
|
|
196
|
+
const style = output.find(
|
|
197
|
+
(file): file is Extract<CompleteOutputFile, { type: 'asset' }> =>
|
|
198
|
+
file.type === 'asset' && file.fileName === globalWxssFileName
|
|
199
|
+
)
|
|
200
|
+
if (style) {
|
|
201
|
+
publishedWxss = typeof style.source === 'string' ? style.source : new TextDecoder().decode(style.source)
|
|
202
|
+
}
|
|
203
|
+
},
|
|
204
|
+
async publish(wxss) {
|
|
142
205
|
if (wxss !== publishedWxss) {
|
|
206
|
+
// writeHmrFile uses atomic replacement; advance the frontier only after durability so a failed write leaves the
|
|
207
|
+
// last known physical generation available for the next reconciliation attempt.
|
|
143
208
|
await writeHmrFile(outDir, globalWxssFileName, wxss)
|
|
144
209
|
}
|
|
145
|
-
// HMR is the second physical writer; advance the frontier only after its atomic write succeeds or was unnecessary.
|
|
146
210
|
publishedWxss = wxss
|
|
147
211
|
}
|
|
148
212
|
}
|
|
149
213
|
}
|
|
150
214
|
|
|
151
|
-
/**
|
|
215
|
+
/**
|
|
216
|
+
* Regenerates all reachable Tailwind roots and commits the cache only when every transform succeeds.
|
|
217
|
+
*
|
|
218
|
+
* Roots run concurrently because they are independent derivations of the same candidate generation. Results remain local until
|
|
219
|
+
* Promise.all fulfills; one failed root therefore preserves every prior root together instead of publishing a mixed generation.
|
|
220
|
+
*/
|
|
152
221
|
async function refreshTailwindStyles(
|
|
153
222
|
styleIds: readonly string[],
|
|
154
223
|
processedStyles: Map<string, ProcessedStyle>,
|
|
@@ -5,7 +5,7 @@ import colors from 'picocolors'
|
|
|
5
5
|
import { type DevEngine, type DevOptions, dev } from 'rolldown/experimental'
|
|
6
6
|
import { asyncScheduler } from 'rxjs'
|
|
7
7
|
import type { Connect, ViteDevServer } from 'vite'
|
|
8
|
-
import type {
|
|
8
|
+
import type { VptOptions } from '../../../../options.ts'
|
|
9
9
|
import { createHmrResultsStream } from './create-hmr-results-stream.ts'
|
|
10
10
|
import { createStyleCapture, type StyleCaptureAction } from './create-style-capture.ts'
|
|
11
11
|
import {
|
|
@@ -44,7 +44,7 @@ type HostAction =
|
|
|
44
44
|
| Readonly<{ kind: 'listening' }>
|
|
45
45
|
|
|
46
46
|
/** One short trailing-edge window absorbs editor bursts before style preparation and physical Page notification. */
|
|
47
|
-
const hmrSettleMilliseconds =
|
|
47
|
+
const hmrSettleMilliseconds = 16
|
|
48
48
|
|
|
49
49
|
/**
|
|
50
50
|
* Creates the wx dev host: the adapter that owns the physical Rolldown DevEngine (created
|
|
@@ -61,7 +61,7 @@ export async function createWxDevHost({
|
|
|
61
61
|
applicationEntryIds
|
|
62
62
|
}: {
|
|
63
63
|
server: ViteDevServer
|
|
64
|
-
options:
|
|
64
|
+
options: VptOptions
|
|
65
65
|
applicationEntryIds: readonly string[]
|
|
66
66
|
}): Promise<WxDevHost> {
|
|
67
67
|
const bundledDev = getBundledDev(server)
|
|
@@ -228,13 +228,24 @@ export async function createWxDevHost({
|
|
|
228
228
|
logWxError(server.config.logger, 'wx dev build failed', action.result)
|
|
229
229
|
return
|
|
230
230
|
}
|
|
231
|
-
|
|
232
|
-
return rotateBuildSession()
|
|
231
|
+
return reconcileCompleteOutput(action.result.output)
|
|
233
232
|
case 'listening':
|
|
234
233
|
return rotateBuildSession()
|
|
235
234
|
}
|
|
236
235
|
}
|
|
237
236
|
|
|
237
|
+
/**
|
|
238
|
+
* Reconciles graph-complete styles before rotating the App-visible build identity.
|
|
239
|
+
*
|
|
240
|
+
* DevEngine has already written its compiler asset when onOutput fires, but bundled development may have omitted CSS Modules
|
|
241
|
+
* from that asset. Awaiting reconciliation inside the serialized reducer guarantees the subsequent app.wxss rotation—the
|
|
242
|
+
* event that refreshes DevTools—can only expose a generation whose global WXSS already represents the complete App/Page graph.
|
|
243
|
+
*/
|
|
244
|
+
async function reconcileCompleteOutput(output: Exclude<DevOutputResult, Error>['output']): Promise<void> {
|
|
245
|
+
await styleCapture.reconcileComplete(output)
|
|
246
|
+
await rotateBuildSession()
|
|
247
|
+
}
|
|
248
|
+
|
|
238
249
|
/** Applies one runtime receipt to the active physical patch history. */
|
|
239
250
|
function processReport(report: RuntimeReport): void {
|
|
240
251
|
// Delayed reports from older builds must never prune the live build's cumulative patch history.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { normalizePath, type PluginOption, transformWithOxc } from 'vite'
|
|
2
|
-
import type {
|
|
2
|
+
import type { VptOptions } from '../../../../options.ts'
|
|
3
3
|
import { esTarget } from '../../../utils/constant.ts'
|
|
4
4
|
import { memoize } from '../../../utils/memoize.ts'
|
|
5
5
|
import { normalizeModuleId } from '../../../utils/modules.ts'
|
|
@@ -22,10 +22,7 @@ export function isWxClientEnvironment(environment: Readonly<{ name: string }>):
|
|
|
22
22
|
* The ordered application entries cross this configuration boundary unchanged so the host can compose global CSS without
|
|
23
23
|
* reconstructing the resolver's App/Page ownership policy from unrelated Rolldown shell and transport entries.
|
|
24
24
|
*/
|
|
25
|
-
export function createWxDevelopmentPlugin(
|
|
26
|
-
options: VitePluginTaroOptions,
|
|
27
|
-
applicationEntryIds: readonly string[]
|
|
28
|
-
): PluginOption[] {
|
|
25
|
+
export function createWxDevelopmentPlugin(options: VptOptions, applicationEntryIds: readonly string[]): PluginOption[] {
|
|
29
26
|
/*
|
|
30
27
|
* Vite creates this plugin descriptor before a server or DevEngine exists, then invokes configureServer and closeBundle on
|
|
31
28
|
* different lifecycle stacks. This mutable handle transfers the one client-owned host between those hooks: configureServer
|
|
@@ -3,7 +3,7 @@ import type { InputOptions, OutputOptions, Plugin } from 'rolldown'
|
|
|
3
3
|
import { build } from 'rolldown'
|
|
4
4
|
import { type DevEngine, viteReporterPlugin } from 'rolldown/experimental'
|
|
5
5
|
import type { ViteDevServer } from 'vite'
|
|
6
|
-
import type {
|
|
6
|
+
import type { VptOptions } from '../../../../options.ts'
|
|
7
7
|
import { once } from '../../../utils/once.ts'
|
|
8
8
|
import { resolvePackageFile } from '../../../utils/packages.ts'
|
|
9
9
|
import { appShellFileName } from '../module.ts'
|
|
@@ -35,7 +35,7 @@ export function installWxDevOptions({
|
|
|
35
35
|
}: {
|
|
36
36
|
bundledDev: BundledDev
|
|
37
37
|
server: ViteDevServer
|
|
38
|
-
options:
|
|
38
|
+
options: VptOptions
|
|
39
39
|
hostPlugins: Plugin[]
|
|
40
40
|
}): void {
|
|
41
41
|
/*
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Rolldown } from 'vite'
|
|
2
|
-
import type {
|
|
2
|
+
import type { VptOptions } from '../../../../options.ts'
|
|
3
3
|
import { createNativeComponentOutput } from '../native/create-native-component-output.ts'
|
|
4
4
|
import type { GeneratedSubpackage } from '../placement/placer.ts'
|
|
5
5
|
import { createJsonAssets } from './json.ts'
|
|
@@ -13,7 +13,7 @@ export async function createOutputFiles({
|
|
|
13
13
|
getModuleInfo
|
|
14
14
|
}: {
|
|
15
15
|
bundle: Rolldown.OutputBundle
|
|
16
|
-
options:
|
|
16
|
+
options: VptOptions
|
|
17
17
|
subpackages: readonly GeneratedSubpackage[]
|
|
18
18
|
getModuleInfo: (moduleId: string) => { meta: Rolldown.CustomPluginOptions } | null
|
|
19
19
|
}): Promise<Rolldown.EmittedFile[]> {
|