vite-plugin-taro 0.3.2 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.en.md +44 -0
- package/README.md +22 -497
- package/client.d.ts +9 -0
- package/dist/node/plugins/client/client-taro.d.ts +4 -0
- package/dist/node/plugins/client/client-taro.js +19 -0
- package/dist/node/plugins/client/constant.d.ts +4 -0
- package/dist/node/plugins/client/constant.js +4 -0
- package/dist/node/plugins/conditional/conditional-directives.d.ts +4 -0
- package/dist/node/plugins/{conditional-directives.js → conditional/conditional-directives.js} +27 -11
- package/dist/node/plugins/css/plugins.d.ts +4 -0
- package/dist/node/plugins/css/plugins.js +84 -0
- package/dist/node/plugins/h5/constant.d.ts +2 -0
- package/dist/node/plugins/h5/constant.js +3 -0
- package/dist/node/plugins/h5/plugins.d.ts +4 -0
- package/dist/node/plugins/h5/plugins.js +161 -0
- package/dist/node/plugins/h5/resolver/module-resolver.d.ts +14 -0
- package/dist/node/plugins/h5/resolver/module-resolver.js +19 -0
- package/dist/node/plugins/h5/transform-app.d.ts +10 -0
- package/dist/node/plugins/h5/transform-app.js +48 -0
- package/dist/node/plugins/wx/dev/dev-host.d.ts +15 -0
- package/dist/node/plugins/wx/dev/dev-host.js +352 -0
- package/dist/node/plugins/wx/dev/hmr-files.d.ts +28 -0
- package/dist/node/plugins/wx/dev/hmr-files.js +34 -0
- package/dist/node/plugins/wx/dev/patch-publisher.d.ts +22 -0
- package/dist/node/plugins/wx/dev/patch-publisher.js +40 -0
- package/dist/node/plugins/wx/dev/plugin.d.ts +7 -0
- package/dist/node/plugins/wx/dev/plugin.js +73 -0
- package/dist/node/plugins/wx/dev/react-refresh.d.ts +20 -0
- package/dist/node/plugins/wx/dev/react-refresh.js +198 -0
- package/dist/node/plugins/wx/module.d.ts +45 -0
- package/dist/node/plugins/wx/module.js +67 -0
- package/dist/node/plugins/wx/native/compile-native-component-interface.d.ts +21 -0
- package/dist/node/plugins/wx/native/compile-native-component-interface.js +29 -0
- package/dist/node/plugins/wx/native/create-native-component-output.d.ts +15 -0
- package/dist/node/plugins/wx/native/create-native-component-output.js +39 -0
- package/dist/node/plugins/wx/native/native-component-assets.d.ts +26 -0
- package/dist/node/plugins/wx/native/native-component-assets.js +76 -0
- package/dist/node/plugins/wx/native/native-component-interface.d.ts +12 -0
- package/dist/node/plugins/wx/native/native-component-interface.js +201 -0
- package/dist/node/plugins/wx/output/files.d.ts +12 -0
- package/dist/node/plugins/wx/output/files.js +12 -0
- package/dist/node/plugins/wx/output/json.d.ts +14 -0
- package/dist/node/plugins/wx/output/json.js +52 -0
- package/dist/node/plugins/wx/output/relative-root.d.ts +2 -0
- package/dist/node/plugins/wx/output/relative-root.js +6 -0
- package/dist/node/plugins/wx/output/templates.d.ts +7 -0
- package/dist/node/plugins/wx/output/templates.js +100 -0
- package/dist/node/plugins/wx/placement/placer.d.ts +78 -0
- package/dist/node/plugins/wx/placement/placer.js +145 -0
- package/dist/node/plugins/wx/placement/plan.d.ts +46 -0
- package/dist/node/plugins/wx/placement/plan.js +210 -0
- package/dist/node/plugins/wx/plugins.d.ts +4 -0
- package/dist/node/plugins/wx/plugins.js +137 -0
- package/dist/node/plugins/wx/render/capsule-wrapper.d.ts +3 -0
- package/dist/node/plugins/wx/render/capsule-wrapper.js +64 -0
- package/dist/node/plugins/wx/render/capsule.d.ts +4 -0
- package/dist/node/plugins/wx/render/capsule.js +13 -0
- package/dist/node/plugins/wx/render/native.d.ts +9 -0
- package/dist/node/plugins/wx/render/native.js +45 -0
- package/dist/node/plugins/wx/render/transport.d.ts +17 -0
- package/dist/node/plugins/wx/render/transport.js +94 -0
- package/dist/node/plugins/wx/resolve/resolver.d.ts +7 -0
- package/dist/node/plugins/wx/resolve/resolver.js +86 -0
- package/dist/node/plugins/wx/resolve/specialize-bootstrap.d.ts +9 -0
- package/dist/node/plugins/wx/resolve/specialize-bootstrap.js +9 -0
- package/dist/node/plugins/wx/resolve/specialize-page-capsule.d.ts +9 -0
- package/dist/node/plugins/wx/resolve/specialize-page-capsule.js +11 -0
- package/dist/node/utils/constant.d.ts +1 -0
- package/dist/node/utils/constant.js +1 -0
- package/dist/node/utils/memoize.d.ts +122 -0
- package/dist/node/utils/memoize.js +86 -0
- package/dist/node/utils/modules.d.ts +20 -24
- package/dist/node/utils/modules.js +21 -34
- package/dist/node/utils/once.d.ts +10 -0
- package/dist/node/utils/once.js +20 -0
- package/dist/node/utils/packages.d.ts +1 -0
- package/dist/node/utils/packages.js +3 -2
- package/dist/node/utils/project-config.d.ts +3 -0
- package/dist/node/utils/project-config.js +8 -0
- package/dist/node/utils/serialized-task-queue.d.ts +9 -0
- package/dist/node/utils/serialized-task-queue.js +17 -0
- package/dist/node/utils/transform.d.ts +11 -0
- package/dist/node/utils/transform.js +58 -0
- package/dist/node/vite-plugin.d.ts +1 -1
- package/dist/node/vite-plugin.js +11 -27
- package/dist/options.d.ts +3 -4
- package/dist/runtime/{taro → client/taro}/api.d.ts +0 -1
- package/dist/runtime/client/taro/api.js +9 -0
- package/dist/runtime/client/taro/component.d.ts +1 -0
- package/dist/runtime/client/taro/component.js +1 -0
- package/dist/runtime/client/taro/define-native-component.d.ts +7 -0
- package/dist/runtime/client/taro/define-native-component.js +4 -0
- package/dist/runtime/h5/app.d.ts +2 -0
- package/dist/runtime/h5/app.js +15 -0
- package/dist/runtime/h5/taro-runtime.d.ts +1 -1
- package/dist/runtime/h5/taro-runtime.js +1 -4
- package/dist/runtime/wx/amphibious/bootstrap.d.ts +4 -0
- package/dist/runtime/wx/amphibious/bootstrap.js +16 -0
- package/dist/runtime/wx/amphibious/transport.d.ts +2 -0
- package/dist/runtime/wx/amphibious/transport.js +4 -0
- package/dist/runtime/wx/capsule/app.d.ts +2 -0
- package/dist/runtime/wx/capsule/app.js +7 -0
- package/dist/runtime/wx/capsule/component.d.ts +3 -0
- package/dist/runtime/wx/capsule/component.js +4 -0
- package/dist/runtime/wx/capsule/page.d.ts +3 -0
- package/dist/runtime/wx/capsule/page.js +68 -0
- package/dist/runtime/wx/capsule/taro-runtime.d.ts +6 -0
- package/dist/runtime/wx/capsule/taro-runtime.js +6 -0
- package/dist/runtime/wx/dev/dev-runtime.d.ts +1 -0
- package/dist/runtime/wx/dev/dev-runtime.js +246 -0
- package/dist/runtime/wx/native/app.d.ts +1 -0
- package/dist/runtime/wx/native/app.js +3 -0
- package/dist/runtime/wx/native/component.d.ts +1 -0
- package/dist/runtime/wx/native/component.js +3 -0
- package/dist/runtime/wx/native/page.d.ts +1 -0
- package/dist/runtime/wx/native/page.js +4 -0
- package/dist/runtime/wx/systemjs/system-core.d.ts +4 -0
- package/dist/runtime/wx/systemjs/system-core.js +331 -0
- package/package.json +21 -14
- package/src/node/plugins/client/client-taro.ts +23 -0
- package/src/node/plugins/client/constant.ts +5 -0
- package/src/node/plugins/{conditional-directives.ts → conditional/conditional-directives.ts} +33 -13
- package/src/node/plugins/css/plugins.ts +96 -0
- package/src/node/plugins/h5/constant.ts +4 -0
- package/src/node/plugins/h5/plugins.ts +197 -0
- package/src/node/plugins/h5/resolver/module-resolver.ts +32 -0
- package/src/node/plugins/h5/transform-app.ts +90 -0
- package/src/node/plugins/wx/dev/dev-host.ts +448 -0
- package/src/node/plugins/wx/dev/hmr-files.ts +55 -0
- package/src/node/plugins/wx/dev/patch-publisher.ts +49 -0
- package/src/node/plugins/wx/dev/plugin.ts +82 -0
- package/src/node/plugins/wx/dev/react-refresh.ts +227 -0
- package/src/node/plugins/wx/module.ts +98 -0
- package/src/node/plugins/wx/native/compile-native-component-interface.ts +47 -0
- package/src/node/plugins/wx/native/create-native-component-output.ts +57 -0
- package/src/node/plugins/wx/native/native-component-assets.ts +114 -0
- package/src/node/plugins/wx/native/native-component-interface.ts +265 -0
- package/src/node/plugins/wx/output/files.ts +27 -0
- package/src/node/plugins/wx/output/json.ts +79 -0
- package/src/node/plugins/wx/output/relative-root.ts +7 -0
- package/src/node/plugins/wx/output/templates.ts +141 -0
- package/src/node/plugins/wx/placement/placer.ts +172 -0
- package/src/node/plugins/wx/placement/plan.ts +306 -0
- package/src/node/plugins/wx/plugins.ts +165 -0
- package/src/node/plugins/wx/render/capsule-wrapper.ts +86 -0
- package/src/node/plugins/wx/render/capsule.ts +21 -0
- package/src/node/plugins/wx/render/native.ts +84 -0
- package/src/node/plugins/wx/render/transport.ts +157 -0
- package/src/node/plugins/wx/resolve/resolver.ts +125 -0
- package/src/node/plugins/wx/resolve/specialize-bootstrap.ts +27 -0
- package/src/node/plugins/wx/resolve/specialize-page-capsule.ts +29 -0
- package/src/node/utils/constant.ts +1 -0
- package/src/node/utils/memoize.ts +149 -0
- package/src/node/utils/modules.ts +36 -38
- package/src/node/utils/once.ts +21 -0
- package/src/node/utils/packages.ts +3 -2
- package/src/node/utils/project-config.ts +10 -0
- package/src/node/utils/serialized-task-queue.ts +20 -0
- package/src/node/utils/transform.ts +82 -0
- package/src/node/vite-plugin.ts +12 -32
- package/src/options.ts +3 -4
- package/src/runtime/client/taro/api.ts +11 -0
- package/src/runtime/client/taro/component.ts +1 -0
- package/src/runtime/client/taro/define-native-component.ts +15 -0
- package/src/runtime/h5/app.ts +25 -0
- package/src/runtime/h5/taro-runtime.ts +1 -4
- package/src/runtime/wx/amphibious/bootstrap.ts +22 -0
- package/src/runtime/wx/amphibious/transport.ts +10 -0
- package/src/runtime/wx/capsule/app.ts +9 -0
- package/src/runtime/wx/capsule/component.ts +6 -0
- package/src/runtime/wx/capsule/page.ts +96 -0
- package/src/runtime/wx/capsule/taro-runtime.ts +14 -0
- package/src/runtime/wx/dev/dev-runtime.ts +317 -0
- package/src/runtime/wx/native/app.ts +4 -0
- package/src/runtime/wx/native/component.ts +4 -0
- package/src/runtime/wx/native/page.ts +6 -0
- package/src/runtime/wx/systemjs/LICENSE +10 -0
- package/src/runtime/wx/systemjs/system-core.js +370 -0
- package/src/runtime/wx/systemjs/system.d.ts +55 -0
- package/src/runtime/wx/wechat.d.ts +52 -0
- package/README.zh.md +0 -521
- package/dist/node/build-context.d.ts +0 -25
- package/dist/node/build-context.js +0 -47
- package/dist/node/css/css-pipeline.d.ts +0 -35
- package/dist/node/css/css-pipeline.js +0 -154
- package/dist/node/plugins/conditional-directives.d.ts +0 -3
- package/dist/node/plugins/taro-runtime.d.ts +0 -5
- package/dist/node/plugins/taro-runtime.js +0 -18
- package/dist/node/targets/h5/plugin.d.ts +0 -6
- package/dist/node/targets/h5/plugin.js +0 -117
- package/dist/node/targets/h5/virtual-modules.d.ts +0 -5
- package/dist/node/targets/h5/virtual-modules.js +0 -60
- package/dist/node/targets/wx/companion-assets.d.ts +0 -19
- package/dist/node/targets/wx/companion-assets.js +0 -129
- package/dist/node/targets/wx/dev-server/development-session.d.ts +0 -32
- package/dist/node/targets/wx/dev-server/development-session.js +0 -215
- package/dist/node/targets/wx/dev-server/full-build-scheduler.d.ts +0 -14
- package/dist/node/targets/wx/dev-server/full-build-scheduler.js +0 -60
- package/dist/node/targets/wx/dev-server/js-utils.d.ts +0 -5
- package/dist/node/targets/wx/dev-server/js-utils.js +0 -28
- package/dist/node/targets/wx/dev-server/output.d.ts +0 -19
- package/dist/node/targets/wx/dev-server/output.js +0 -44
- package/dist/node/targets/wx/dev-server/rolldown-runtime-source.d.ts +0 -8
- package/dist/node/targets/wx/dev-server/rolldown-runtime-source.js +0 -95
- package/dist/node/targets/wx/dev-server/update-server-state.d.ts +0 -65
- package/dist/node/targets/wx/dev-server/update-server-state.js +0 -116
- package/dist/node/targets/wx/dev-server/update-transport.d.ts +0 -28
- package/dist/node/targets/wx/dev-server/update-transport.js +0 -212
- package/dist/node/targets/wx/dev-server/vite-bundled-dev-adapter.d.ts +0 -44
- package/dist/node/targets/wx/dev-server/vite-bundled-dev-adapter.js +0 -145
- package/dist/node/targets/wx/development-files.d.ts +0 -8
- package/dist/node/targets/wx/development-files.js +0 -8
- package/dist/node/targets/wx/plugin.d.ts +0 -6
- package/dist/node/targets/wx/plugin.js +0 -144
- package/dist/node/targets/wx/react-refresh.d.ts +0 -4
- package/dist/node/targets/wx/react-refresh.js +0 -38
- package/dist/node/targets/wx/virtual-modules.d.ts +0 -16
- package/dist/node/targets/wx/virtual-modules.js +0 -120
- package/dist/node/utils/async.d.ts +0 -8
- package/dist/node/utils/async.js +0 -16
- package/dist/node/utils/filesystem.d.ts +0 -13
- package/dist/node/utils/filesystem.js +0 -43
- package/dist/runtime/taro/api.js +0 -11
- package/dist/runtime/taro/components.d.ts +0 -2
- package/dist/runtime/taro/components.js +0 -2
- package/dist/runtime/wx/page-update.d.ts +0 -6
- package/dist/runtime/wx/page-update.js +0 -157
- package/dist/runtime/wx/taro-runtime.d.ts +0 -5
- package/dist/runtime/wx/taro-runtime.js +0 -6
- package/dist/runtime/wx/update-client-state.d.ts +0 -68
- package/dist/runtime/wx/update-client-state.js +0 -84
- package/dist/runtime/wx/update-client.d.ts +0 -1
- package/dist/runtime/wx/update-client.js +0 -171
- package/src/node/build-context.ts +0 -62
- package/src/node/css/css-pipeline.ts +0 -171
- package/src/node/plugins/taro-runtime.ts +0 -22
- package/src/node/targets/h5/plugin.ts +0 -135
- package/src/node/targets/h5/virtual-modules.ts +0 -71
- package/src/node/targets/wx/companion-assets.ts +0 -174
- package/src/node/targets/wx/dev-server/development-session.ts +0 -271
- package/src/node/targets/wx/dev-server/full-build-scheduler.ts +0 -62
- package/src/node/targets/wx/dev-server/js-utils.ts +0 -33
- package/src/node/targets/wx/dev-server/output.ts +0 -56
- package/src/node/targets/wx/dev-server/rolldown-runtime-source.ts +0 -95
- package/src/node/targets/wx/dev-server/update-server-state.ts +0 -183
- package/src/node/targets/wx/dev-server/update-transport.ts +0 -261
- package/src/node/targets/wx/dev-server/vite-bundled-dev-adapter.ts +0 -203
- package/src/node/targets/wx/development-files.ts +0 -11
- package/src/node/targets/wx/plugin.ts +0 -164
- package/src/node/targets/wx/react-refresh.ts +0 -51
- package/src/node/targets/wx/virtual-modules.ts +0 -152
- package/src/node/utils/async.ts +0 -19
- package/src/node/utils/filesystem.ts +0 -45
- package/src/runtime/taro/api.ts +0 -13
- package/src/runtime/taro/components.ts +0 -2
- package/src/runtime/wx/page-update.ts +0 -230
- package/src/runtime/wx/react-refresh.d.ts +0 -20
- package/src/runtime/wx/taro-runtime.ts +0 -7
- package/src/runtime/wx/update-client-state.ts +0 -138
- package/src/runtime/wx/update-client.ts +0 -223
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { Rolldown } from 'vite';
|
|
2
|
+
/** Identifies one generated code-only subpackage by its physical output root. */
|
|
3
|
+
export type SubpackageLocation = {
|
|
4
|
+
/** Discriminates generated subpackages from main. */
|
|
5
|
+
kind: 'subpackage';
|
|
6
|
+
/** Native subpackage root relative to the Mini Program output directory. */
|
|
7
|
+
root: string;
|
|
8
|
+
};
|
|
9
|
+
/** Physical package ownership for one transformed module. */
|
|
10
|
+
export type PackageLocation = {
|
|
11
|
+
kind: 'main';
|
|
12
|
+
} | SubpackageLocation;
|
|
13
|
+
/** Immutable module-to-package ownership produced before Rolldown creates chunks. */
|
|
14
|
+
export type PlacementPlan = ReadonlyMap<string, PackageLocation>;
|
|
15
|
+
/** Minimal Rolldown graph interface consumed by the subpackage planner. */
|
|
16
|
+
export type ModuleGraph = {
|
|
17
|
+
/** Every transformed module known after graph construction. */
|
|
18
|
+
moduleIds: Iterable<string>;
|
|
19
|
+
/** Reads static edges, dynamic edges, transformed code, and entry ownership. */
|
|
20
|
+
getModuleInfo(moduleId: string): Rolldown.ModuleInfo | null;
|
|
21
|
+
/** Adds non-JavaScript output owned by a transformed module to its package weight. */
|
|
22
|
+
getAdditionalModuleBytes?: (info: Rolldown.ModuleInfo) => number;
|
|
23
|
+
};
|
|
24
|
+
/** Shared main-package value used for every eager or output-generated module. */
|
|
25
|
+
export declare const mainPackage: {
|
|
26
|
+
readonly kind: 'main';
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* Creates one deterministic subpackage placement plan:
|
|
30
|
+
*
|
|
31
|
+
* 1. Snapshot Rolldown's transformed module graph.
|
|
32
|
+
* 2. Reserve every explicit shell and capsule entry together with its static closure in main.
|
|
33
|
+
* 3. Treat dynamic imports as asynchronous roots, then annotate their modules with affinity.
|
|
34
|
+
* 4. Pack those lazy modules independently under the planning budget.
|
|
35
|
+
* 5. Return only module ownership; chunks and native manifests are reconciled later.
|
|
36
|
+
*
|
|
37
|
+
* Static cycles are deliberately not atomic only after a genuine nested dynamic boundary. System.import() may obtain their
|
|
38
|
+
* registrations from several packages and await top-level execution while preserving the original static ESM graph.
|
|
39
|
+
*/
|
|
40
|
+
export declare function createPlacementPlan({ moduleIds, getModuleInfo, getAdditionalModuleBytes, planningBudgetBytes }: ModuleGraph & {
|
|
41
|
+
planningBudgetBytes?: number;
|
|
42
|
+
}): PlacementPlan;
|
|
43
|
+
/** Uses the generated root directory itself as the native subpackage alias. */
|
|
44
|
+
export declare function getSubpackageName(root: string): string;
|
|
45
|
+
/** Tests the plugin-owned output prefix that physically identifies every generated subpackage. */
|
|
46
|
+
export declare function isGeneratedSubpackageFile(fileName: string): boolean;
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
// Leave headroom below WeChat's 2M subpackage limit for capsule wrappers and bundler-generated code.
|
|
3
|
+
const subpackagePlanningBudget = 1_900_000;
|
|
4
|
+
const generatedSubpackageRootPrefix = 'sub/p_';
|
|
5
|
+
/** Shared main-package value used for every eager or output-generated module. */
|
|
6
|
+
export const mainPackage = { kind: 'main' };
|
|
7
|
+
/**
|
|
8
|
+
* Creates one deterministic subpackage placement plan:
|
|
9
|
+
*
|
|
10
|
+
* 1. Snapshot Rolldown's transformed module graph.
|
|
11
|
+
* 2. Reserve every explicit shell and capsule entry together with its static closure in main.
|
|
12
|
+
* 3. Treat dynamic imports as asynchronous roots, then annotate their modules with affinity.
|
|
13
|
+
* 4. Pack those lazy modules independently under the planning budget.
|
|
14
|
+
* 5. Return only module ownership; chunks and native manifests are reconciled later.
|
|
15
|
+
*
|
|
16
|
+
* Static cycles are deliberately not atomic only after a genuine nested dynamic boundary. System.import() may obtain their
|
|
17
|
+
* registrations from several packages and await top-level execution while preserving the original static ESM graph.
|
|
18
|
+
*/
|
|
19
|
+
export function createPlacementPlan({ moduleIds, getModuleInfo, getAdditionalModuleBytes, planningBudgetBytes = subpackagePlanningBudget }) {
|
|
20
|
+
// Materialize the iterable once because every later phase needs stable random access by module ID.
|
|
21
|
+
const infos = new Map();
|
|
22
|
+
for (const moduleId of moduleIds) {
|
|
23
|
+
const info = getModuleInfo(moduleId);
|
|
24
|
+
if (info) {
|
|
25
|
+
infos.set(moduleId, info);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
// Eager ownership is a hard constraint; consumer and neighbor sets below are soft packing preferences only.
|
|
29
|
+
const eagerModules = findEagerModules(infos);
|
|
30
|
+
const consumersByModule = findLazyConsumers({ infos, eagerModules });
|
|
31
|
+
const neighborsByModule = findLazyNeighbors({ infos, eagerModules });
|
|
32
|
+
const placeableModules = [...infos.entries()]
|
|
33
|
+
.filter(([moduleId]) => !eagerModules.has(moduleId))
|
|
34
|
+
.map(([moduleId, info]) => ({
|
|
35
|
+
moduleId,
|
|
36
|
+
estimatedBytes: Buffer.byteLength(info.code ?? '', 'utf8') + (getAdditionalModuleBytes?.(info) ?? 0),
|
|
37
|
+
consumers: consumersByModule.get(moduleId) ?? new Set([moduleId]),
|
|
38
|
+
neighbors: neighborsByModule.get(moduleId) ?? new Set()
|
|
39
|
+
}));
|
|
40
|
+
// Packing operates at module granularity, so a large lazy closure or cycle may span several subpackages.
|
|
41
|
+
const subpackages = packSubpackages({ modules: placeableModules, planningBudgetBytes }).map(createPackedSubpackage);
|
|
42
|
+
const locationByModule = new Map();
|
|
43
|
+
for (const moduleId of eagerModules) {
|
|
44
|
+
locationByModule.set(moduleId, mainPackage);
|
|
45
|
+
}
|
|
46
|
+
for (const subpackage of subpackages) {
|
|
47
|
+
for (const moduleId of subpackage.moduleIds) {
|
|
48
|
+
locationByModule.set(moduleId, subpackage);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return locationByModule;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Finds modules that must remain in main. Native shells and capsules are explicit entries, and static traversal keeps their
|
|
55
|
+
* complete eager closures synchronous. Every dynamic import is therefore a genuine lazy boundary whose graph may use
|
|
56
|
+
* subpackages and top-level await.
|
|
57
|
+
*/
|
|
58
|
+
function findEagerModules(infos) {
|
|
59
|
+
const eagerModules = new Set();
|
|
60
|
+
const pending = [...infos.values()].filter((info) => info.isEntry).map((info) => info.id);
|
|
61
|
+
while (pending.length > 0) {
|
|
62
|
+
const moduleId = pending.pop();
|
|
63
|
+
if (!moduleId || eagerModules.has(moduleId)) {
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
const info = infos.get(moduleId);
|
|
67
|
+
if (!info) {
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
eagerModules.add(moduleId);
|
|
71
|
+
pending.push(...info.importedIds);
|
|
72
|
+
}
|
|
73
|
+
return eagerModules;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Records demand after the eager importSync closure has been removed. Every remaining dynamic target starts one lazy root
|
|
77
|
+
* traversal; that traversal follows static edges only and stops before another dynamic boundary. A shared module records
|
|
78
|
+
* every root that can request it. These consumer sets improve co-location but never prevent subpackage splitting.
|
|
79
|
+
*/
|
|
80
|
+
function findLazyConsumers({ infos, eagerModules }) {
|
|
81
|
+
const dynamicRoots = new Set();
|
|
82
|
+
for (const info of infos.values()) {
|
|
83
|
+
for (const importedId of info.dynamicallyImportedIds) {
|
|
84
|
+
if (infos.has(importedId) && !eagerModules.has(importedId)) {
|
|
85
|
+
dynamicRoots.add(importedId);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
const consumersByModule = new Map();
|
|
90
|
+
for (const dynamicRoot of [...dynamicRoots].sort()) {
|
|
91
|
+
const visited = new Set();
|
|
92
|
+
const pending = [dynamicRoot];
|
|
93
|
+
while (pending.length > 0) {
|
|
94
|
+
const moduleId = pending.pop();
|
|
95
|
+
if (!moduleId || visited.has(moduleId) || eagerModules.has(moduleId)) {
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
const info = infos.get(moduleId);
|
|
99
|
+
if (!info) {
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
102
|
+
visited.add(moduleId);
|
|
103
|
+
const consumers = consumersByModule.get(moduleId) ?? new Set();
|
|
104
|
+
consumers.add(dynamicRoot);
|
|
105
|
+
consumersByModule.set(moduleId, consumers);
|
|
106
|
+
pending.push(...info.importedIds);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return consumersByModule;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Converts each lazy static edge into an undirected affinity. Direction is irrelevant for co-location scoring, while the
|
|
113
|
+
* original directed dependency remains in Rolldown and later in SystemJS. Cycles are therefore preferences, not atoms.
|
|
114
|
+
*/
|
|
115
|
+
function findLazyNeighbors({ infos, eagerModules }) {
|
|
116
|
+
const neighborsByModule = new Map();
|
|
117
|
+
for (const [moduleId, info] of infos) {
|
|
118
|
+
if (eagerModules.has(moduleId)) {
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
for (const importedId of info.importedIds) {
|
|
122
|
+
if (!infos.has(importedId) || eagerModules.has(importedId)) {
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
125
|
+
addNeighbor(neighborsByModule, moduleId, importedId);
|
|
126
|
+
addNeighbor(neighborsByModule, importedId, moduleId);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
return neighborsByModule;
|
|
130
|
+
}
|
|
131
|
+
/** Adds one side of an undirected lazy-module affinity edge. */
|
|
132
|
+
function addNeighbor(neighborsByModule, moduleId, neighborId) {
|
|
133
|
+
const neighbors = neighborsByModule.get(moduleId) ?? new Set();
|
|
134
|
+
neighbors.add(neighborId);
|
|
135
|
+
neighborsByModule.set(moduleId, neighbors);
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Packs lazy modules with deterministic best-fit decreasing:
|
|
139
|
+
*
|
|
140
|
+
* 1. Visit larger transformed modules first, with module ID as the stable tie-breaker.
|
|
141
|
+
* 2. Consider only existing bins that stay within the planning budget.
|
|
142
|
+
* 3. Prefer the bin with the least remaining space, minimizing subpackage count in the usual best-fit heuristic.
|
|
143
|
+
* 4. When remaining space ties, prefer shared dynamic consumers and then static neighbors.
|
|
144
|
+
* 5. Create a new bin when no existing bin fits; an individually oversized module receives its own bin.
|
|
145
|
+
*/
|
|
146
|
+
function packSubpackages({ modules, planningBudgetBytes }) {
|
|
147
|
+
const bins = [];
|
|
148
|
+
const sortedModules = [...modules].sort((left, right) => {
|
|
149
|
+
return right.estimatedBytes - left.estimatedBytes || left.moduleId.localeCompare(right.moduleId);
|
|
150
|
+
});
|
|
151
|
+
for (const module of sortedModules) {
|
|
152
|
+
const candidate = bins
|
|
153
|
+
.filter((bin) => bin.estimatedBytes + module.estimatedBytes <= planningBudgetBytes)
|
|
154
|
+
.map((bin) => ({
|
|
155
|
+
bin,
|
|
156
|
+
remainingBytes: planningBudgetBytes - bin.estimatedBytes - module.estimatedBytes,
|
|
157
|
+
affinity: getAffinity(bin, module)
|
|
158
|
+
}))
|
|
159
|
+
.sort((left, right) => {
|
|
160
|
+
return left.remainingBytes - right.remainingBytes || right.affinity - left.affinity;
|
|
161
|
+
})[0]?.bin;
|
|
162
|
+
const bin = candidate ?? {
|
|
163
|
+
moduleIds: [],
|
|
164
|
+
estimatedBytes: 0,
|
|
165
|
+
consumers: new Set()
|
|
166
|
+
};
|
|
167
|
+
if (!candidate) {
|
|
168
|
+
bins.push(bin);
|
|
169
|
+
}
|
|
170
|
+
bin.moduleIds.push(module.moduleId);
|
|
171
|
+
bin.estimatedBytes += module.estimatedBytes;
|
|
172
|
+
for (const consumer of module.consumers) {
|
|
173
|
+
bin.consumers.add(consumer);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
return bins;
|
|
177
|
+
}
|
|
178
|
+
/** Scores dynamic-root overlap above direct static adjacency when equally full bins compete. */
|
|
179
|
+
function getAffinity(bin, module) {
|
|
180
|
+
let affinity = 0;
|
|
181
|
+
for (const consumer of module.consumers) {
|
|
182
|
+
if (bin.consumers.has(consumer)) {
|
|
183
|
+
affinity += 2;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
for (const neighbor of module.neighbors) {
|
|
187
|
+
if (bin.moduleIds.includes(neighbor)) {
|
|
188
|
+
affinity += 1;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
return affinity;
|
|
192
|
+
}
|
|
193
|
+
/** Freezes bin membership and derives a stable subpackage root from sorted module IDs. */
|
|
194
|
+
function createPackedSubpackage(bin) {
|
|
195
|
+
const moduleIds = [...bin.moduleIds].sort();
|
|
196
|
+
const hash = createHash('sha256').update(moduleIds.join('\0')).digest('hex').slice(0, 8);
|
|
197
|
+
return {
|
|
198
|
+
kind: 'subpackage',
|
|
199
|
+
root: `${generatedSubpackageRootPrefix}${hash}`,
|
|
200
|
+
moduleIds
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
/** Uses the generated root directory itself as the native subpackage alias. */
|
|
204
|
+
export function getSubpackageName(root) {
|
|
205
|
+
return root.slice(root.lastIndexOf('/') + 1);
|
|
206
|
+
}
|
|
207
|
+
/** Tests the plugin-owned output prefix that physically identifies every generated subpackage. */
|
|
208
|
+
export function isGeneratedSubpackageFile(fileName) {
|
|
209
|
+
return fileName.startsWith(generatedSubpackageRootPrefix);
|
|
210
|
+
}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { esTarget } from '../../utils/constant.js';
|
|
2
|
+
import { packageRequire } from '../../utils/packages.js';
|
|
3
|
+
import { clientTaroNativeId } from '../client/constant.js';
|
|
4
|
+
import { createWxDevelopmentPlugin } from './dev/plugin.js';
|
|
5
|
+
import { getWxExecutionKind, isTransportModule } from './module.js';
|
|
6
|
+
import { compileNativeComponentInterface } from './native/compile-native-component-interface.js';
|
|
7
|
+
import { getNativeComponentAssetBytes } from './native/native-component-assets.js';
|
|
8
|
+
import { createOutputFiles } from './output/files.js';
|
|
9
|
+
import { createPlacer } from './placement/placer.js';
|
|
10
|
+
import { renderCapsule } from './render/capsule.js';
|
|
11
|
+
import { renderNative } from './render/native.js';
|
|
12
|
+
import { materializeTransport } from './render/transport.js';
|
|
13
|
+
import { createResolver } from './resolve/resolver.js';
|
|
14
|
+
/** Creates the complete plugin set for the wx target. */
|
|
15
|
+
export function createWxTargetPlugins(options) {
|
|
16
|
+
return [createWxPlugin(options), createWxDevelopmentPlugin(options)];
|
|
17
|
+
}
|
|
18
|
+
/** Configures the complete wx target build pipeline. */
|
|
19
|
+
function createWxPlugin(options) {
|
|
20
|
+
const resolver = createResolver(options);
|
|
21
|
+
const placer = createPlacer();
|
|
22
|
+
return {
|
|
23
|
+
name: 'vpt:wx',
|
|
24
|
+
config(_config, _env) {
|
|
25
|
+
return {
|
|
26
|
+
define: createTaroDefines(),
|
|
27
|
+
appType: 'custom',
|
|
28
|
+
oxc: { target: esTarget },
|
|
29
|
+
resolve: {
|
|
30
|
+
alias: [
|
|
31
|
+
{
|
|
32
|
+
find: /^@tarojs\/components$/,
|
|
33
|
+
replacement: packageRequire.resolve('@tarojs/plugin-platform-weapp/dist/components-react')
|
|
34
|
+
}
|
|
35
|
+
]
|
|
36
|
+
},
|
|
37
|
+
build: {
|
|
38
|
+
modulePreload: false,
|
|
39
|
+
cssCodeSplit: false,
|
|
40
|
+
// Let weapp-tailwindcss own final WXSS transformation.
|
|
41
|
+
cssMinify: false,
|
|
42
|
+
// No base64 assets: Taro warns on image srcs above ~2KB, and inlined
|
|
43
|
+
// images bloat the JS bundle toward the mini program package limit.
|
|
44
|
+
assetsInlineLimit: 0,
|
|
45
|
+
target: esTarget,
|
|
46
|
+
rolldownOptions: {
|
|
47
|
+
...placer.rolldownOptions,
|
|
48
|
+
input: resolver.input
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
},
|
|
53
|
+
resolveId(id, importer) {
|
|
54
|
+
return resolver.resolveId(id, importer, this.environment.config.root);
|
|
55
|
+
},
|
|
56
|
+
transform: {
|
|
57
|
+
order: 'pre',
|
|
58
|
+
async handler(code, id) {
|
|
59
|
+
const sourcemap = Boolean(this.environment.config.build.sourcemap);
|
|
60
|
+
if (code.includes(clientTaroNativeId)) {
|
|
61
|
+
return compileNativeComponentInterface({
|
|
62
|
+
code,
|
|
63
|
+
id,
|
|
64
|
+
sourcemap,
|
|
65
|
+
addWatchFile: (file) => this.addWatchFile(file)
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
return resolver.specialize(code, id, sourcemap);
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
renderStart() {
|
|
72
|
+
placer.analyze({
|
|
73
|
+
moduleIds: this.getModuleIds(),
|
|
74
|
+
getModuleInfo: (moduleId) => this.getModuleInfo(moduleId),
|
|
75
|
+
getAdditionalModuleBytes: (info) => getNativeComponentAssetBytes(info.meta)
|
|
76
|
+
});
|
|
77
|
+
},
|
|
78
|
+
renderChunk: {
|
|
79
|
+
order: 'post',
|
|
80
|
+
async handler(code, chunk, outputOptions, meta) {
|
|
81
|
+
const executionKind = getWxExecutionKind(chunk);
|
|
82
|
+
const sourcemap = Boolean(outputOptions.sourcemap);
|
|
83
|
+
if (executionKind === 'capsule') {
|
|
84
|
+
return renderCapsule(code, chunk, sourcemap);
|
|
85
|
+
}
|
|
86
|
+
// Native and amphibious modules share the CommonJS renderer. Amphibious transport exposure is a
|
|
87
|
+
// separate concern materialized from final output paths after the physical transport itself is rendered.
|
|
88
|
+
const native = renderNative({ code, chunk, chunks: meta.chunks, sourcemap });
|
|
89
|
+
if (isTransportModule(chunk)) {
|
|
90
|
+
return materializeTransport({
|
|
91
|
+
code: native.code,
|
|
92
|
+
transportChunk: chunk,
|
|
93
|
+
chunks: meta.chunks,
|
|
94
|
+
getLoadMode: placer.getLoadMode,
|
|
95
|
+
sourcemap
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
return native;
|
|
99
|
+
}
|
|
100
|
+
},
|
|
101
|
+
generateBundle: {
|
|
102
|
+
order: 'post',
|
|
103
|
+
async handler(_, bundle) {
|
|
104
|
+
const subpackages = placer.getSubpackages(bundle);
|
|
105
|
+
const outputFiles = await createOutputFiles({
|
|
106
|
+
bundle,
|
|
107
|
+
options,
|
|
108
|
+
subpackages,
|
|
109
|
+
getModuleInfo: (moduleId) => this.getModuleInfo(moduleId)
|
|
110
|
+
});
|
|
111
|
+
outputFiles.forEach((file) => {
|
|
112
|
+
this.emitFile(file);
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
/** Creates the build-time constants required by Taro's legacy feature gates. */
|
|
119
|
+
function createTaroDefines() {
|
|
120
|
+
const taroVersion = String(packageRequire('@tarojs/runtime/package.json').version);
|
|
121
|
+
return {
|
|
122
|
+
'process.env.FRAMEWORK': JSON.stringify('react'),
|
|
123
|
+
'process.env.SUPPORT_TARO_POLYFILL': JSON.stringify('disabled'),
|
|
124
|
+
'process.env.TARO_ENV': JSON.stringify('weapp'),
|
|
125
|
+
'process.env.TARO_PLATFORM': JSON.stringify('mini'),
|
|
126
|
+
'process.env.TARO_VERSION': JSON.stringify(taroVersion),
|
|
127
|
+
// React's development-only Suspense diagnostics call this browser API without guards.
|
|
128
|
+
'performance.now': 'Date.now',
|
|
129
|
+
ENABLE_ADJACENT_HTML: 'false',
|
|
130
|
+
ENABLE_CLONE_NODE: 'false',
|
|
131
|
+
ENABLE_CONTAINS: 'false',
|
|
132
|
+
ENABLE_INNER_HTML: 'false',
|
|
133
|
+
ENABLE_MUTATION_OBSERVER: 'false',
|
|
134
|
+
ENABLE_SIZE_APIS: 'false',
|
|
135
|
+
ENABLE_TEMPLATE_CONTENT: 'false'
|
|
136
|
+
};
|
|
137
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { types } from '@babel/core';
|
|
2
|
+
import { resolveChunkReference } from '../../../utils/modules.js';
|
|
3
|
+
/** Wraps System.register as an inert CommonJS capsule tuple with canonical final dependency IDs. */
|
|
4
|
+
export function wrapCapsulePlugin(fileName) {
|
|
5
|
+
return {
|
|
6
|
+
name: 'vpt:wrap-capsule',
|
|
7
|
+
visitor: {},
|
|
8
|
+
post(file) {
|
|
9
|
+
const program = file.ast.program;
|
|
10
|
+
const [statement] = program.body;
|
|
11
|
+
const registration = statement && types.isExpressionStatement(statement) ? statement.expression : undefined;
|
|
12
|
+
if (program.body.length !== 1 ||
|
|
13
|
+
!types.isCallExpression(registration) ||
|
|
14
|
+
!types.isMemberExpression(registration.callee) ||
|
|
15
|
+
registration.callee.computed ||
|
|
16
|
+
!types.isIdentifier(registration.callee.object, { name: 'System' }) ||
|
|
17
|
+
!types.isIdentifier(registration.callee.property, { name: 'register' })) {
|
|
18
|
+
throw new Error(`Expected one anonymous System.register call in ${fileName}`);
|
|
19
|
+
}
|
|
20
|
+
const [dependencies, declaration] = registration.arguments;
|
|
21
|
+
if (registration.arguments.length !== 2 ||
|
|
22
|
+
!types.isArrayExpression(dependencies) ||
|
|
23
|
+
!types.isFunctionExpression(declaration)) {
|
|
24
|
+
throw new Error(`Expected System.register(dependencies, declaration) in ${fileName}`);
|
|
25
|
+
}
|
|
26
|
+
dependencies.elements.forEach((dependency) => {
|
|
27
|
+
canonicalizeStaticReference(dependency, fileName);
|
|
28
|
+
});
|
|
29
|
+
const context = declaration.params[1];
|
|
30
|
+
if (types.isIdentifier(context)) {
|
|
31
|
+
file.path.traverse({
|
|
32
|
+
CallExpression(callPath) {
|
|
33
|
+
const callee = callPath.node.callee;
|
|
34
|
+
if (!types.isMemberExpression(callee) ||
|
|
35
|
+
callee.computed ||
|
|
36
|
+
!types.isIdentifier(callee.object, { name: context.name }) ||
|
|
37
|
+
!types.isIdentifier(callee.property, { name: 'import' })) {
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
const [dependency] = callPath.node.arguments;
|
|
41
|
+
canonicalizeDynamicReference(dependency, fileName);
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
program.directives = [];
|
|
46
|
+
program.body = [
|
|
47
|
+
types.expressionStatement(types.assignmentExpression('=', types.memberExpression(types.identifier('module'), types.identifier('exports')), types.arrayExpression([dependencies, declaration])))
|
|
48
|
+
];
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
/** Resolves one generated static reference while the final importing chunk filename is known. */
|
|
53
|
+
function canonicalizeStaticReference(reference, fileName) {
|
|
54
|
+
if (!types.isStringLiteral(reference)) {
|
|
55
|
+
throw new Error(`Expected a literal System.register dependency in ${fileName}`);
|
|
56
|
+
}
|
|
57
|
+
reference.value = resolveChunkReference(fileName, reference.value);
|
|
58
|
+
}
|
|
59
|
+
/** Resolves application literals while preserving runtime-computed IDs injected by the development runtime. */
|
|
60
|
+
function canonicalizeDynamicReference(reference, fileName) {
|
|
61
|
+
if (types.isStringLiteral(reference) && (reference.value.startsWith('./') || reference.value.startsWith('../'))) {
|
|
62
|
+
reference.value = resolveChunkReference(fileName, reference.value);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { Rolldown } from 'vite';
|
|
2
|
+
import { type AstTransformResult } from '../../../utils/transform.ts';
|
|
3
|
+
/** Renders one ESM chunk as an inert SystemJS capsule. */
|
|
4
|
+
export declare function renderCapsule(code: string, chunk: Rolldown.RenderedChunk, sourcemap?: boolean): AstTransformResult;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import transformDynamicImport from '@babel/plugin-transform-dynamic-import';
|
|
2
|
+
import transformModulesSystemjs from '@babel/plugin-transform-modules-systemjs';
|
|
3
|
+
import { transformWithBabel } from '../../../utils/transform.js';
|
|
4
|
+
import { wrapCapsulePlugin } from './capsule-wrapper.js';
|
|
5
|
+
/** Renders one ESM chunk as an inert SystemJS capsule. */
|
|
6
|
+
export function renderCapsule(code, chunk, sourcemap = true) {
|
|
7
|
+
return transformWithBabel(code, chunk.fileName, [
|
|
8
|
+
transformDynamicImport,
|
|
9
|
+
// Erase Babel's internal plugin pass type.
|
|
10
|
+
transformModulesSystemjs,
|
|
11
|
+
wrapCapsulePlugin(chunk.fileName)
|
|
12
|
+
], sourcemap);
|
|
13
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Rolldown } from 'vite';
|
|
2
|
+
import { type AstTransformResult } from '../../../utils/transform.ts';
|
|
3
|
+
/** Renders a native module while activating its statically imported capsules through SystemJS. */
|
|
4
|
+
export declare function renderNative({ code, chunk, chunks, sourcemap }: {
|
|
5
|
+
code: string;
|
|
6
|
+
chunk: Rolldown.RenderedChunk;
|
|
7
|
+
chunks: Readonly<Record<string, Rolldown.RenderedChunk>>;
|
|
8
|
+
sourcemap: boolean;
|
|
9
|
+
}): AstTransformResult;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { types } from '@babel/core';
|
|
2
|
+
import transformModulesCommonjs from '@babel/plugin-transform-modules-commonjs';
|
|
3
|
+
import { resolveChunkReference } from '../../../utils/modules.js';
|
|
4
|
+
import { transformWithBabel } from '../../../utils/transform.js';
|
|
5
|
+
import { getWxEntryRole } from '../module.js';
|
|
6
|
+
/** Renders a native module while activating its statically imported capsules through SystemJS. */
|
|
7
|
+
export function renderNative({ code, chunk, chunks, sourcemap }) {
|
|
8
|
+
return transformWithBabel(code, chunk.fileName, [connectNativeCapsulesPlugin(chunk.fileName, chunks), transformModulesCommonjs], sourcemap);
|
|
9
|
+
}
|
|
10
|
+
/** Converts only cross-runtime static imports; ordinary native dependencies remain CommonJS imports. */
|
|
11
|
+
function connectNativeCapsulesPlugin(fileName, chunks) {
|
|
12
|
+
return {
|
|
13
|
+
name: 'vpt:connect-native-capsules',
|
|
14
|
+
visitor: {
|
|
15
|
+
ImportDeclaration(importPath) {
|
|
16
|
+
const reference = importPath.node.source.value;
|
|
17
|
+
if (!reference.startsWith('./') && !reference.startsWith('../')) {
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
const chunkId = resolveChunkReference(fileName, reference);
|
|
21
|
+
const importedChunk = chunks[chunkId];
|
|
22
|
+
if (!importedChunk || getWxEntryRole(importedChunk) !== 'capsule') {
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
const [specifier] = importPath.node.specifiers;
|
|
26
|
+
if (importPath.node.specifiers.length !== 1 ||
|
|
27
|
+
!specifier ||
|
|
28
|
+
types.isImportNamespaceSpecifier(specifier)) {
|
|
29
|
+
throw new Error(`Expected one capsule value import from ${chunkId} in ${fileName}`);
|
|
30
|
+
}
|
|
31
|
+
const imported = types.isImportDefaultSpecifier(specifier)
|
|
32
|
+
? types.identifier('default')
|
|
33
|
+
: specifier.imported;
|
|
34
|
+
const importedConfig = types.memberExpression(createSyncImport(chunkId), types.cloneNode(imported), types.isStringLiteral(imported));
|
|
35
|
+
importPath.replaceWith(types.variableDeclaration('const', [
|
|
36
|
+
types.variableDeclarator(types.cloneNode(specifier.local), importedConfig)
|
|
37
|
+
]));
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
/** Creates one synchronous lookup through the canonical output chunk ID. */
|
|
43
|
+
function createSyncImport(chunkId) {
|
|
44
|
+
return types.callExpression(types.memberExpression(types.memberExpression(types.identifier('global'), types.identifier('System')), types.identifier('importSync')), [types.stringLiteral(chunkId)]);
|
|
45
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { Rolldown } from 'vite';
|
|
2
|
+
import { type AstTransformResult } from '../../../utils/transform.ts';
|
|
3
|
+
/**
|
|
4
|
+
* Materializes transport while Rolldown's preliminary hash placeholders are still active, so every injected physical
|
|
5
|
+
* reference participates in final hash calculation instead of changing code after its filename has been fixed.
|
|
6
|
+
*
|
|
7
|
+
* This intentionally creates broad hash invalidation: changing one capsule can rename transport, then bootstrap, then
|
|
8
|
+
* chunks that import bootstrap. A Mini Program ships one application package rather than independently cached HTTP
|
|
9
|
+
* chunks, so honest content hashes and automatic graph linking are more valuable than minimizing that hash fan-out.
|
|
10
|
+
*/
|
|
11
|
+
export declare function materializeTransport({ code, transportChunk, chunks, getLoadMode, sourcemap }: {
|
|
12
|
+
code: string;
|
|
13
|
+
transportChunk: Rolldown.RenderedChunk;
|
|
14
|
+
chunks: Readonly<Record<string, Rolldown.RenderedChunk>>;
|
|
15
|
+
getLoadMode(chunk: Rolldown.RenderedChunk): 'sync' | 'async';
|
|
16
|
+
sourcemap?: boolean;
|
|
17
|
+
}): Promise<AstTransformResult>;
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { types } from '@babel/core';
|
|
3
|
+
import { replaceWithAst } from '../../../utils/transform.js';
|
|
4
|
+
import { getWxExecutionKind } from '../module.js';
|
|
5
|
+
const transportPlaceholder = '__VITE_PLUGIN_TARO_TRANSPORT__';
|
|
6
|
+
const moduleIdParameter = 'moduleId';
|
|
7
|
+
const exportBindingParameter = 'exportBinding';
|
|
8
|
+
/**
|
|
9
|
+
* Materializes transport while Rolldown's preliminary hash placeholders are still active, so every injected physical
|
|
10
|
+
* reference participates in final hash calculation instead of changing code after its filename has been fixed.
|
|
11
|
+
*
|
|
12
|
+
* This intentionally creates broad hash invalidation: changing one capsule can rename transport, then bootstrap, then
|
|
13
|
+
* chunks that import bootstrap. A Mini Program ships one application package rather than independently cached HTTP
|
|
14
|
+
* chunks, so honest content hashes and automatic graph linking are more valuable than minimizing that hash fan-out.
|
|
15
|
+
*/
|
|
16
|
+
export async function materializeTransport({ code, transportChunk, chunks, getLoadMode, sourcemap = true }) {
|
|
17
|
+
// Babel constructs and safely serializes an expression shaped like:
|
|
18
|
+
// (moduleId) => {
|
|
19
|
+
// switch (moduleId) {
|
|
20
|
+
// case 'assets/app.js': return require('./app.js')
|
|
21
|
+
// case 'sub/p_account/page.js': return require.async('../sub/p_account/page.js')
|
|
22
|
+
// case 'assets/bootstrap.js':
|
|
23
|
+
// return [[], (exportBinding) => ({ execute() { exportBinding(require('./bootstrap.js')) } })]
|
|
24
|
+
// default: throw new Error(`Unknown System module: ${moduleId}`)
|
|
25
|
+
// }
|
|
26
|
+
// }
|
|
27
|
+
const cases = getTransportedChunks(chunks)
|
|
28
|
+
.sort((left, right) => left.chunk.fileName.localeCompare(right.chunk.fileName))
|
|
29
|
+
.map(({ chunk, kind }) => {
|
|
30
|
+
const loadMode = getLoadMode(chunk);
|
|
31
|
+
if (kind === 'amphibious' && loadMode !== 'sync') {
|
|
32
|
+
throw new Error(`Amphibious wx module must be in the main package: ${chunk.fileName}`);
|
|
33
|
+
}
|
|
34
|
+
return createTransportCase({
|
|
35
|
+
chunkId: chunk.fileName,
|
|
36
|
+
transportFileName: transportChunk.fileName,
|
|
37
|
+
loadMode,
|
|
38
|
+
kind
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
return await replaceWithAst(code, transportChunk.fileName, {
|
|
42
|
+
[transportPlaceholder]: types.arrowFunctionExpression([types.identifier(moduleIdParameter)], types.blockStatement([
|
|
43
|
+
types.switchStatement(types.identifier(moduleIdParameter), [
|
|
44
|
+
...cases,
|
|
45
|
+
createUnknownModuleCase(moduleIdParameter)
|
|
46
|
+
])
|
|
47
|
+
]))
|
|
48
|
+
}, sourcemap);
|
|
49
|
+
}
|
|
50
|
+
/** Keeps only capsule and amphibious chunks and carries their narrowed kind into source generation. */
|
|
51
|
+
function getTransportedChunks(chunks) {
|
|
52
|
+
const transportedChunks = [];
|
|
53
|
+
for (const chunk of Object.values(chunks)) {
|
|
54
|
+
const kind = getWxExecutionKind(chunk);
|
|
55
|
+
if (kind !== 'native') {
|
|
56
|
+
transportedChunks.push({ chunk, kind });
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return transportedChunks;
|
|
60
|
+
}
|
|
61
|
+
/** Creates one canonical-ID switch case while keeping its native require argument literal. */
|
|
62
|
+
function createTransportCase({ chunkId, transportFileName, loadMode, kind }) {
|
|
63
|
+
const requirePath = toNativeRequirePath(transportFileName, chunkId);
|
|
64
|
+
const requireCallee = loadMode === 'sync'
|
|
65
|
+
? types.identifier('require')
|
|
66
|
+
: types.memberExpression(types.identifier('require'), types.identifier('async'));
|
|
67
|
+
const loadedModule = types.callExpression(requireCallee, [types.stringLiteral(requirePath)]);
|
|
68
|
+
const registration = kind === 'capsule' ? loadedModule : createAmphibiousRegistrationExpression(loadedModule);
|
|
69
|
+
return types.switchCase(types.stringLiteral(chunkId), [types.returnStatement(registration)]);
|
|
70
|
+
}
|
|
71
|
+
/** Creates a registration that loads and publishes an amphibious CommonJS namespace only when executed. */
|
|
72
|
+
function createAmphibiousRegistrationExpression(namespace) {
|
|
73
|
+
return types.arrayExpression([
|
|
74
|
+
types.arrayExpression([]),
|
|
75
|
+
types.arrowFunctionExpression([types.identifier(exportBindingParameter)], types.objectExpression([
|
|
76
|
+
types.objectMethod('method', types.identifier('execute'), [], types.blockStatement([
|
|
77
|
+
types.expressionStatement(types.callExpression(types.identifier(exportBindingParameter), [namespace]))
|
|
78
|
+
]))
|
|
79
|
+
]))
|
|
80
|
+
]);
|
|
81
|
+
}
|
|
82
|
+
/** Rejects module IDs absent from the closed output graph. */
|
|
83
|
+
function createUnknownModuleCase(moduleId) {
|
|
84
|
+
return types.switchCase(null, [
|
|
85
|
+
types.throwStatement(types.newExpression(types.identifier('Error'), [
|
|
86
|
+
types.binaryExpression('+', types.stringLiteral('Unknown System module: '), types.identifier(moduleId))
|
|
87
|
+
]))
|
|
88
|
+
]);
|
|
89
|
+
}
|
|
90
|
+
/** Converts one preliminary output path to a literal require path relative to transport. */
|
|
91
|
+
function toNativeRequirePath(fromFileName, toFileName) {
|
|
92
|
+
const relativePath = path.posix.relative(path.posix.dirname(fromFileName), toFileName);
|
|
93
|
+
return relativePath.startsWith('.') ? relativePath : `./${relativePath}`;
|
|
94
|
+
}
|