vite-plugin-taro 0.5.16 → 0.6.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 +1 -1
- package/README.md +1 -1
- 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/chunk-path.d.ts +8 -0
- package/dist/node/plugins/wx/chunk-path.js +18 -0
- package/dist/node/plugins/wx/dev/dev-host.d.ts +2 -2
- 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/dev/wx-dev-options.js +21 -0
- package/dist/node/plugins/wx/native/create-native-component-output.d.ts +3 -1
- package/dist/node/plugins/wx/native/create-native-component-output.js +3 -5
- package/dist/node/plugins/wx/output/files.d.ts +5 -4
- package/dist/node/plugins/wx/output/files.js +2 -2
- package/dist/node/plugins/wx/output/json.d.ts +4 -4
- package/dist/node/plugins/wx/output/json.js +2 -2
- package/dist/node/plugins/wx/output/templates.d.ts +2 -2
- package/dist/node/plugins/wx/placer/placement.d.ts +50 -0
- package/dist/node/plugins/wx/placer/placement.js +245 -0
- package/dist/node/plugins/wx/placer/placer.d.ts +60 -0
- package/dist/node/plugins/wx/placer/placer.js +123 -0
- package/dist/node/plugins/wx/plugins.d.ts +2 -2
- package/dist/node/plugins/wx/plugins.js +16 -16
- package/dist/node/plugins/wx/render/capsule-wrapper.js +3 -3
- package/dist/node/plugins/wx/render/native.js +5 -5
- package/dist/node/plugins/wx/render/transport.d.ts +7 -3
- package/dist/node/plugins/wx/render/transport.js +18 -9
- 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/modules.d.ts +0 -2
- package/dist/node/utils/modules.js +0 -7
- 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/chunk-path.ts +22 -0
- package/src/node/plugins/wx/dev/dev-host.ts +2 -2
- package/src/node/plugins/wx/dev/plugins.ts +2 -5
- package/src/node/plugins/wx/dev/wx-dev-options.ts +23 -2
- package/src/node/plugins/wx/native/create-native-component-output.ts +6 -5
- package/src/node/plugins/wx/output/files.ts +7 -5
- package/src/node/plugins/wx/output/json.ts +9 -10
- package/src/node/plugins/wx/output/templates.ts +3 -3
- package/src/node/plugins/wx/placer/placement.ts +364 -0
- package/src/node/plugins/wx/placer/placer.ts +154 -0
- package/src/node/plugins/wx/plugins.ts +20 -20
- package/src/node/plugins/wx/render/capsule-wrapper.ts +3 -3
- package/src/node/plugins/wx/render/native.ts +5 -5
- package/src/node/plugins/wx/render/transport.ts +24 -8
- 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/modules.ts +0 -8
- 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/plugins/wx/placement/placer.d.ts +0 -78
- package/dist/node/plugins/wx/placement/placer.js +0 -158
- package/dist/node/plugins/wx/placement/plan.d.ts +0 -46
- package/dist/node/plugins/wx/placement/plan.js +0 -210
- package/dist/node/vite-plugin.d.ts +0 -4
- package/src/node/plugins/wx/placement/placer.ts +0 -187
- package/src/node/plugins/wx/placement/plan.ts +0 -306
package/README.en.md
CHANGED
|
@@ -36,7 +36,7 @@ Continue with the [Quick Start guide](https://vpt.js.org/guides/quick-start/).
|
|
|
36
36
|
- [Hot module replacement](https://vpt.js.org/guides/hot-module-replacement/)
|
|
37
37
|
- [Skyline mode](https://vpt.js.org/guides/skyline-mode/)
|
|
38
38
|
- [Migrate from Taro CLI](https://vpt.js.org/guides/migrate-from-taro/)
|
|
39
|
-
- [Configuration reference](https://vpt.js.org/
|
|
39
|
+
- [Configuration reference](https://vpt.js.org/guides/configuration/)
|
|
40
40
|
- [Repository management](https://vpt.js.org/references/repository-management/)
|
|
41
41
|
|
|
42
42
|
## License
|
package/README.md
CHANGED
|
@@ -37,7 +37,7 @@ npm create vite-taro@latest my-app
|
|
|
37
37
|
- [开发者工具热更新](https://vpt.js.org/guides/hot-module-replacement/)
|
|
38
38
|
- [Skyline 模式](https://vpt.js.org/guides/skyline-mode/)
|
|
39
39
|
- [从 Taro CLI 迁移](https://vpt.js.org/guides/migrate-from-taro/)
|
|
40
|
-
- [配置参考](https://vpt.js.org/
|
|
40
|
+
- [配置参考](https://vpt.js.org/guides/configuration/)
|
|
41
41
|
- [仓库维护](https://vpt.js.org/references/repository-management/)
|
|
42
42
|
|
|
43
43
|
## 许可证
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type Plugin } from 'vite';
|
|
2
|
-
import type {
|
|
2
|
+
import type { VptTarget } from '../../../options.ts';
|
|
3
3
|
/** Public facade used by transformed application API imports. */
|
|
4
4
|
export declare const clientTaroApiId = "virtual:taro/api";
|
|
5
5
|
/** Creates the shared Taro facade backed by the selected target's API implementation. */
|
|
6
|
-
export declare function createClientTaroPlugin(target:
|
|
6
|
+
export declare function createClientTaroPlugin(target: VptTarget): Plugin;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import type { Plugin } from 'vite';
|
|
2
|
-
import type {
|
|
2
|
+
import type { VptTarget } from '../../../options.ts';
|
|
3
3
|
/** Creates source-level target conditional handling shared by H5 and WX. */
|
|
4
|
-
export declare function createConditionalDirectivePlugin(target:
|
|
4
|
+
export declare function createConditionalDirectivePlugin(target: VptTarget): Plugin;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { PluginOption } from 'vite';
|
|
2
|
-
import type {
|
|
2
|
+
import type { VptOptions } from '../../../options.ts';
|
|
3
3
|
/** Creates the plugins that own the H5 target. */
|
|
4
|
-
export declare function createH5TargetPlugins(options:
|
|
4
|
+
export declare function createH5TargetPlugins(options: VptOptions): PluginOption[];
|
|
5
5
|
/**
|
|
6
6
|
* Coarse source prefilter for the upstream Taro API transform.
|
|
7
7
|
*
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { VptOptions } from '../../../../options.ts';
|
|
2
2
|
/** Creates H5 application module resolution and specialization. */
|
|
3
|
-
export declare function createModuleResolver(options:
|
|
3
|
+
export declare function createModuleResolver(options: VptOptions): {
|
|
4
4
|
resolveId({ id, projectRoot }: {
|
|
5
5
|
id: string;
|
|
6
6
|
projectRoot: string;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { VptOptions } from '../../../options.ts';
|
|
2
2
|
import { type AstTransformResult } from '../../utils/transform.ts';
|
|
3
3
|
/** Specializes the physical H5 App for one configured project. */
|
|
4
4
|
export declare function transformH5App({ code, id, options, projectRoot, sourcemap }: {
|
|
5
5
|
code: string;
|
|
6
6
|
id: string;
|
|
7
|
-
options:
|
|
7
|
+
options: VptOptions;
|
|
8
8
|
projectRoot: string;
|
|
9
9
|
sourcemap?: boolean;
|
|
10
10
|
}): Promise<AstTransformResult>;
|
|
@@ -2,8 +2,8 @@ import { types } from '@babel/core';
|
|
|
2
2
|
import { createPageComponentImportPath } from '../../utils/modules.js';
|
|
3
3
|
import { createAppConfig } from '../../utils/project-config.js';
|
|
4
4
|
import { replaceWithAst } from '../../utils/transform.js';
|
|
5
|
-
const appConfigPlaceholder = '
|
|
6
|
-
const routesPlaceholder = '
|
|
5
|
+
const appConfigPlaceholder = '__VPT_H5_APP_CONFIG__';
|
|
6
|
+
const routesPlaceholder = '__VPT_H5_ROUTES__';
|
|
7
7
|
/** Specializes the physical H5 App for one configured project. */
|
|
8
8
|
export async function transformH5App({ code, id, options, projectRoot, sourcemap = true }) {
|
|
9
9
|
const transformed = await replaceWithAst(code, id, {
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/** Physical directory in which Rolldown writes generated JavaScript chunks inside each native package. */
|
|
2
|
+
export declare const generatedChunkDirectory = "assets";
|
|
3
|
+
/** Projects one Rolldown-owned physical candidate path into the package-neutral SystemJS identity. */
|
|
4
|
+
export declare function toLogicalChunkId(physicalChunkId: string): string;
|
|
5
|
+
/** Resolves one relative Rolldown-generated import to its preliminary physical chunk path. */
|
|
6
|
+
export declare function resolvePhysicalChunkReference(importerChunkId: string, reference: string): string;
|
|
7
|
+
/** Projects one relative Rolldown-generated import into its package-neutral SystemJS identity. */
|
|
8
|
+
export declare function resolveLogicalChunkReference(importerChunkId: string, reference: string): string;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
/** Physical directory in which Rolldown writes generated JavaScript chunks inside each native package. */
|
|
3
|
+
export const generatedChunkDirectory = 'assets';
|
|
4
|
+
/** Projects one Rolldown-owned physical candidate path into the package-neutral SystemJS identity. */
|
|
5
|
+
export function toLogicalChunkId(physicalChunkId) {
|
|
6
|
+
return path.posix.relative(generatedChunkDirectory, physicalChunkId);
|
|
7
|
+
}
|
|
8
|
+
/** Resolves one relative Rolldown-generated import to its preliminary physical chunk path. */
|
|
9
|
+
export function resolvePhysicalChunkReference(importerChunkId, reference) {
|
|
10
|
+
if (!reference.startsWith('./') && !reference.startsWith('../')) {
|
|
11
|
+
throw new Error(`Expected a relative chunk reference in ${importerChunkId}: ${reference}`);
|
|
12
|
+
}
|
|
13
|
+
return path.posix.join(path.posix.dirname(importerChunkId), reference);
|
|
14
|
+
}
|
|
15
|
+
/** Projects one relative Rolldown-generated import into its package-neutral SystemJS identity. */
|
|
16
|
+
export function resolveLogicalChunkReference(importerChunkId, reference) {
|
|
17
|
+
return toLogicalChunkId(resolvePhysicalChunkReference(importerChunkId, reference));
|
|
18
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ViteDevServer } from 'vite';
|
|
2
|
-
import type {
|
|
2
|
+
import type { VptOptions } from '../../../../options.ts';
|
|
3
3
|
export type WxDevHost = Readonly<{
|
|
4
4
|
close: () => Promise<void>;
|
|
5
5
|
}>;
|
|
@@ -14,6 +14,6 @@ export type WxDevHost = Readonly<{
|
|
|
14
14
|
*/
|
|
15
15
|
export declare function createWxDevHost({ server, options, applicationEntryIds }: {
|
|
16
16
|
server: ViteDevServer;
|
|
17
|
-
options:
|
|
17
|
+
options: VptOptions;
|
|
18
18
|
applicationEntryIds: readonly string[];
|
|
19
19
|
}): Promise<WxDevHost>;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type PluginOption } from 'vite';
|
|
2
|
-
import type {
|
|
2
|
+
import type { VptOptions } from '../../../../options.ts';
|
|
3
3
|
/** Selects the sole Vite environment that owns the physical Mini Program development project. */
|
|
4
4
|
export declare function isWxClientEnvironment(environment: Readonly<{
|
|
5
5
|
name: string;
|
|
@@ -11,7 +11,7 @@ export declare function isWxClientEnvironment(environment: Readonly<{
|
|
|
11
11
|
* The ordered application entries cross this configuration boundary unchanged so the host can compose global CSS without
|
|
12
12
|
* reconstructing the resolver's App/Page ownership policy from unrelated Rolldown shell and transport entries.
|
|
13
13
|
*/
|
|
14
|
-
export declare function createWxDevelopmentPlugin(options:
|
|
14
|
+
export declare function createWxDevelopmentPlugin(options: VptOptions, applicationEntryIds: readonly string[]): PluginOption[];
|
|
15
15
|
/**
|
|
16
16
|
* Transfers development ownership of `app.wxss` from complete output to the dev host.
|
|
17
17
|
*
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { InputOptions, OutputOptions, Plugin } from 'rolldown';
|
|
2
2
|
import { type DevEngine } from 'rolldown/experimental';
|
|
3
3
|
import type { ViteDevServer } from 'vite';
|
|
4
|
-
import type {
|
|
4
|
+
import type { VptOptions } from '../../../../options.ts';
|
|
5
5
|
type BundledDevRolldownOptions = InputOptions & {
|
|
6
6
|
experimental?: {
|
|
7
7
|
[key: string]: unknown;
|
|
@@ -22,7 +22,7 @@ export type BundledDev = {
|
|
|
22
22
|
export declare function installWxDevOptions({ bundledDev, server, options, hostPlugins }: {
|
|
23
23
|
bundledDev: BundledDev;
|
|
24
24
|
server: ViteDevServer;
|
|
25
|
-
options:
|
|
25
|
+
options: VptOptions;
|
|
26
26
|
hostPlugins: Plugin[];
|
|
27
27
|
}): void;
|
|
28
28
|
/** Returns the configured output after rejecting states unsupported by the physical WX engine. */
|
|
@@ -35,12 +35,26 @@ export function installWxDevOptions({ bundledDev, server, options, hostPlugins }
|
|
|
35
35
|
* mutating configuredOutput itself would leak development normalization back into the user's resolved Vite config.
|
|
36
36
|
*/
|
|
37
37
|
Object.assign(output, configured, {
|
|
38
|
+
// Development output is overwritten in place after every complete build. Strip hash placeholders from the
|
|
39
|
+
// configured asset pattern so old files cannot accumulate and native JSON/WXML references remain stable.
|
|
38
40
|
assetFileNames: createStableFileNames(configured.assetFileNames, 'assets/[name][extname]'),
|
|
41
|
+
// Banners create physical CommonJS edges after graph analysis: App initializes the dev runtime and each Page
|
|
42
|
+
// consumes the stable patch journal without allowing those host-only files into the application chunk graph.
|
|
39
43
|
banner: createEntryBanner(pageFiles),
|
|
44
|
+
// Preserve the configured directory/name shape while removing content hashes. Stable chunk paths let DevTools
|
|
45
|
+
// overwrite executable files and let cumulative HMR patches address one persistent physical module identity.
|
|
40
46
|
chunkFileNames: createStableFileNames(configured.chunkFileNames, 'assets/[name].js'),
|
|
47
|
+
// Native entry paths are public Mini Program routes (`app.js`, `pages/.../index.js`); development must never hash
|
|
48
|
+
// or relocate them because DevTools determines App/Page reload behavior from those exact filenames.
|
|
41
49
|
entryFileNames: createStableFileNames(configured.entryFileNames, '[name]'),
|
|
50
|
+
// Keep ESM until the existing WX renderChunk pipeline classifies each final chunk and converts capsules to
|
|
51
|
+
// System.register data or native/amphibious entries to CommonJS. Choosing CommonJS here would erase that boundary.
|
|
42
52
|
format: 'es',
|
|
53
|
+
// Bundled development emits complete physical output repeatedly. Minifying bounds disk transfer and DevTools
|
|
54
|
+
// compile work; source-level HMR diagnostics still come from Vite/Rolldown before this final output pass.
|
|
43
55
|
minify: true,
|
|
56
|
+
// DevTools executes physical WX files and HMR applies module factories rather than browser source maps. Disabling
|
|
57
|
+
// maps avoids extra output files and prevents Vite's Oxc sourcemap transform from touching generated host code.
|
|
44
58
|
sourcemap: false
|
|
45
59
|
});
|
|
46
60
|
/*
|
|
@@ -50,9 +64,16 @@ export function installWxDevOptions({ bundledDev, server, options, hostPlugins }
|
|
|
50
64
|
rolldownOptions.experimental ??= {};
|
|
51
65
|
const existingDevMode = rolldownOptions.experimental.devMode;
|
|
52
66
|
rolldownOptions.experimental.devMode = {
|
|
67
|
+
// Retain unknown user/forward-compatible devMode fields while the three explicit WX invariants below win.
|
|
53
68
|
...(typeof existingDevMode === 'object' ? existingDevMode : {}),
|
|
69
|
+
// Install the WX-adapted self-contained Rolldown runtime. It consumes physical patch journals and reports
|
|
70
|
+
// acknowledgements/rebuild requests through the host bridge instead of relying on browser globals or sockets.
|
|
54
71
|
implement: await bundleRuntimeSource(),
|
|
72
|
+
// Produce a complete output graph on the initial build. Lazy per-request compilation cannot establish the closed
|
|
73
|
+
// App/Page graph, native companions, style sidecars, and build identity required before any patch is admitted.
|
|
55
74
|
lazy: false,
|
|
75
|
+
// Keep Rolldown's common runtime injection because generated application factories call its module registry and
|
|
76
|
+
// HMR primitives. Skipping it would leave the custom implementation without the runtime surface it extends.
|
|
56
77
|
skipCommonRuntimeInjection: false
|
|
57
78
|
};
|
|
58
79
|
/*
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import type { Rolldown } from 'vite';
|
|
2
|
+
import type { PackageLocation } from '../placer/placement.ts';
|
|
2
3
|
/** Creates opaque native files and their registrations from each surviving JSX interface module. */
|
|
3
|
-
export declare function createNativeComponentOutput({ bundle, getModuleInfo }: {
|
|
4
|
+
export declare function createNativeComponentOutput({ bundle, getModuleInfo, getPackageLocation }: {
|
|
4
5
|
bundle: Rolldown.OutputBundle;
|
|
5
6
|
getModuleInfo: (moduleId: string) => {
|
|
6
7
|
meta: Rolldown.CustomPluginOptions;
|
|
7
8
|
} | null;
|
|
9
|
+
getPackageLocation(chunk: Rolldown.OutputChunk): PackageLocation;
|
|
8
10
|
}): Promise<{
|
|
9
11
|
files: Rolldown.EmittedAsset[];
|
|
10
12
|
registrations: {
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import { readFile } from 'node:fs/promises';
|
|
2
2
|
import path from 'node:path';
|
|
3
|
-
import { isGeneratedSubpackageFile } from '../placement/plan.js';
|
|
4
3
|
import { getNativeComponentSources } from './native-component-assets.js';
|
|
5
4
|
/** Creates opaque native files and their registrations from each surviving JSX interface module. */
|
|
6
|
-
export async function createNativeComponentOutput({ bundle, getModuleInfo }) {
|
|
5
|
+
export async function createNativeComponentOutput({ bundle, getModuleInfo, getPackageLocation }) {
|
|
7
6
|
// Files and registrations accumulate in final chunk order for deterministic output.
|
|
8
7
|
const files = [];
|
|
9
8
|
const registrations = [];
|
|
@@ -11,9 +10,8 @@ export async function createNativeComponentOutput({ bundle, getModuleInfo }) {
|
|
|
11
10
|
if (output.type !== 'chunk') {
|
|
12
11
|
continue;
|
|
13
12
|
}
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
: undefined;
|
|
13
|
+
const location = getPackageLocation(output);
|
|
14
|
+
const packageRoot = location.kind === 'subpackage' ? location.root : undefined;
|
|
17
15
|
for (const moduleId of output.moduleIds) {
|
|
18
16
|
const sources = getNativeComponentSources(getModuleInfo(moduleId)?.meta);
|
|
19
17
|
for (const source of sources) {
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import type { Rolldown } from 'vite';
|
|
2
|
-
import type {
|
|
3
|
-
import type { GeneratedSubpackage } from '../placement
|
|
2
|
+
import type { VptOptions } from '../../../../options.ts';
|
|
3
|
+
import type { GeneratedSubpackage, PackageLocation } from '../placer/placement.ts';
|
|
4
4
|
/** Creates every compiler-owned WX file derived from the final Rolldown bundle. */
|
|
5
|
-
export declare function createOutputFiles({ bundle, options, subpackages, getModuleInfo }: {
|
|
5
|
+
export declare function createOutputFiles({ bundle, options, subpackages, getModuleInfo, getPackageLocation }: {
|
|
6
6
|
bundle: Rolldown.OutputBundle;
|
|
7
|
-
options:
|
|
7
|
+
options: VptOptions;
|
|
8
8
|
subpackages: readonly GeneratedSubpackage[];
|
|
9
9
|
getModuleInfo: (moduleId: string) => {
|
|
10
10
|
meta: Rolldown.CustomPluginOptions;
|
|
11
11
|
} | null;
|
|
12
|
+
getPackageLocation(chunk: Rolldown.OutputChunk): PackageLocation;
|
|
12
13
|
}): Promise<Rolldown.EmittedFile[]>;
|
|
@@ -2,8 +2,8 @@ import { createNativeComponentOutput } from '../native/create-native-component-o
|
|
|
2
2
|
import { createJsonAssets } from './json.js';
|
|
3
3
|
import { createTemplateAssets } from './templates.js';
|
|
4
4
|
/** Creates every compiler-owned WX file derived from the final Rolldown bundle. */
|
|
5
|
-
export async function createOutputFiles({ bundle, options, subpackages, getModuleInfo }) {
|
|
6
|
-
const nativeOutput = await createNativeComponentOutput({ bundle, getModuleInfo });
|
|
5
|
+
export async function createOutputFiles({ bundle, options, subpackages, getModuleInfo, getPackageLocation }) {
|
|
6
|
+
const nativeOutput = await createNativeComponentOutput({ bundle, getModuleInfo, getPackageLocation });
|
|
7
7
|
return [
|
|
8
8
|
{
|
|
9
9
|
type: 'asset',
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import type { Rolldown } from 'vite';
|
|
2
|
-
import type {
|
|
3
|
-
import type
|
|
2
|
+
import type { VptJsonObject, VptOptions } from '../../../../options.ts';
|
|
3
|
+
import { type GeneratedSubpackage } from '../placer/placement.ts';
|
|
4
4
|
/** Creates every configured native JSON asset. */
|
|
5
5
|
export declare function createJsonAssets({ options, subpackages, nativeComponents }: {
|
|
6
|
-
options:
|
|
6
|
+
options: VptOptions;
|
|
7
7
|
subpackages: readonly GeneratedSubpackage[];
|
|
8
8
|
nativeComponents: readonly {
|
|
9
9
|
name: string;
|
|
@@ -11,4 +11,4 @@ export declare function createJsonAssets({ options, subpackages, nativeComponent
|
|
|
11
11
|
}[];
|
|
12
12
|
}): Rolldown.EmittedAsset[];
|
|
13
13
|
/** Serializes one native JSON object with stable formatting. */
|
|
14
|
-
export declare function renderJson(value:
|
|
14
|
+
export declare function renderJson(value: VptJsonObject): string;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createAppConfig } from '../../../utils/project-config.js';
|
|
2
|
-
import { isGeneratedSubpackageFile } from '../placement
|
|
2
|
+
import { isGeneratedSubpackageFile } from '../placer/placement.js';
|
|
3
3
|
import { toRootRelativePath } from './relative-root.js';
|
|
4
4
|
/** Creates every configured native JSON asset. */
|
|
5
5
|
export function createJsonAssets({ options, subpackages, nativeComponents }) {
|
|
@@ -13,7 +13,7 @@ export function createJsonAssets({ options, subpackages, nativeComponents }) {
|
|
|
13
13
|
...(options.projectPrivateConfigJson
|
|
14
14
|
? [createJsonAsset('project.private.config.json', options.projectPrivateConfigJson)]
|
|
15
15
|
: []),
|
|
16
|
-
createJsonAsset('sitemap.json', options.sitemapJson)
|
|
16
|
+
...(options.sitemapJson ? [createJsonAsset('sitemap.json', options.sitemapJson)] : [])
|
|
17
17
|
];
|
|
18
18
|
}
|
|
19
19
|
/** Creates Page JSON with generated Taro and native component registrations. */
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { Rolldown } from 'vite';
|
|
2
|
-
import type {
|
|
2
|
+
import type { VptOptions } from '../../../../options.ts';
|
|
3
3
|
/** Creates Taro's shared WeChat templates and native WXML/WXSS companions for every Page. */
|
|
4
|
-
export declare function createTemplateAssets(bundle: Rolldown.OutputBundle, options:
|
|
4
|
+
export declare function createTemplateAssets(bundle: Rolldown.OutputBundle, options: VptOptions, nativeComponents: readonly {
|
|
5
5
|
name: string;
|
|
6
6
|
fields: readonly string[];
|
|
7
7
|
}[]): Rolldown.EmittedAsset[];
|
|
@@ -0,0 +1,50 @@
|
|
|
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 final Rolldown chunk. */
|
|
10
|
+
export type PackageLocation = {
|
|
11
|
+
kind: 'main';
|
|
12
|
+
} | SubpackageLocation;
|
|
13
|
+
/** Native app.json declaration for one generated code-only subpackage. */
|
|
14
|
+
export type GeneratedSubpackage = {
|
|
15
|
+
/** Stable native alias derived from the generated root hash. */
|
|
16
|
+
name: string;
|
|
17
|
+
/** Physical directory containing this subpackage's emitted capsules. */
|
|
18
|
+
root: string;
|
|
19
|
+
/** Marks this as a code-only subpackage with no native Page routes. */
|
|
20
|
+
pages: readonly [];
|
|
21
|
+
};
|
|
22
|
+
/** Immutable ownership and materialization operations for one complete final-chunk graph. */
|
|
23
|
+
export type Placement = Readonly<{
|
|
24
|
+
getPackageLocation(chunk: Rolldown.RenderedChunk | Rolldown.OutputChunk): PackageLocation;
|
|
25
|
+
getPhysicalChunkId(chunk: Rolldown.RenderedChunk): string;
|
|
26
|
+
getLoadMode(chunk: Rolldown.RenderedChunk): 'sync' | 'async';
|
|
27
|
+
finalize(bundle: Rolldown.OutputBundle): readonly GeneratedSubpackage[];
|
|
28
|
+
}>;
|
|
29
|
+
/**
|
|
30
|
+
* Applies Load-Transition Hypergraph Partitioning to Rolldown's final preliminary chunk graph:
|
|
31
|
+
*
|
|
32
|
+
* 1. Sort preliminary filenames to remove callback and object-enumeration order from every later decision.
|
|
33
|
+
* 2. Reserve every explicit entry and its complete static closure in main because native startup must load it synchronously.
|
|
34
|
+
* 3. Treat each dynamic-import edge as one load transition; the target's static closure is that transition's hyperedge.
|
|
35
|
+
* Nested dynamic edges remain separate transitions rather than being folded into the parent closure.
|
|
36
|
+
* 4. Index every lazy chunk by all transitions requiring it. Shared chunks therefore carry global demand rather than being
|
|
37
|
+
* assigned according to the first source module or dynamic root that happens to visit them.
|
|
38
|
+
* 5. Order chunks by transition demand, estimated emitted bytes, then preliminary filename. Place each chunk once into the
|
|
39
|
+
* fitting bin with maximum transition overlap, using best-fit remaining capacity only as a tie-breaker.
|
|
40
|
+
* 6. Hash each bin's sorted preliminary filenames into a deterministic physical package root and return unique ownership.
|
|
41
|
+
*
|
|
42
|
+
* Analysis costs the sum of transition static-closure traversals. Packing scans fitting bins and intersects sparse
|
|
43
|
+
* transition sets; its worst case is O(CBT), while practical graphs have few bins and sparse transition membership.
|
|
44
|
+
*/
|
|
45
|
+
export declare function createPlacement({ chunks, getAdditionalModuleBytes }: {
|
|
46
|
+
chunks: Readonly<Record<string, Rolldown.RenderedChunk>>;
|
|
47
|
+
getAdditionalModuleBytes(moduleId: string): number;
|
|
48
|
+
}): Placement;
|
|
49
|
+
/** Tests the plugin-owned output prefix that physically identifies every generated subpackage. */
|
|
50
|
+
export declare function isGeneratedSubpackageFile(fileName: string): boolean;
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
// Leave headroom below WeChat's 2M subpackage limit for rendered wrappers and native assets.
|
|
3
|
+
const subpackagePlanningBudget = 1_900_000;
|
|
4
|
+
const generatedSubpackageRootPrefix = 'sub/p_';
|
|
5
|
+
/** Shared main-package value used for every synchronously reachable chunk. */
|
|
6
|
+
const mainPackage = { kind: 'main' };
|
|
7
|
+
/**
|
|
8
|
+
* Applies Load-Transition Hypergraph Partitioning to Rolldown's final preliminary chunk graph:
|
|
9
|
+
*
|
|
10
|
+
* 1. Sort preliminary filenames to remove callback and object-enumeration order from every later decision.
|
|
11
|
+
* 2. Reserve every explicit entry and its complete static closure in main because native startup must load it synchronously.
|
|
12
|
+
* 3. Treat each dynamic-import edge as one load transition; the target's static closure is that transition's hyperedge.
|
|
13
|
+
* Nested dynamic edges remain separate transitions rather than being folded into the parent closure.
|
|
14
|
+
* 4. Index every lazy chunk by all transitions requiring it. Shared chunks therefore carry global demand rather than being
|
|
15
|
+
* assigned according to the first source module or dynamic root that happens to visit them.
|
|
16
|
+
* 5. Order chunks by transition demand, estimated emitted bytes, then preliminary filename. Place each chunk once into the
|
|
17
|
+
* fitting bin with maximum transition overlap, using best-fit remaining capacity only as a tie-breaker.
|
|
18
|
+
* 6. Hash each bin's sorted preliminary filenames into a deterministic physical package root and return unique ownership.
|
|
19
|
+
*
|
|
20
|
+
* Analysis costs the sum of transition static-closure traversals. Packing scans fitting bins and intersects sparse
|
|
21
|
+
* transition sets; its worst case is O(CBT), while practical graphs have few bins and sparse transition membership.
|
|
22
|
+
*/
|
|
23
|
+
export function createPlacement({ chunks, getAdditionalModuleBytes }) {
|
|
24
|
+
const chunkById = new Map(Object.entries(chunks).sort(([left], [right]) => left.localeCompare(right)));
|
|
25
|
+
const mainChunkIds = findMainChunkIds(chunkById);
|
|
26
|
+
const transitionsByChunk = collectTransitionsByChunk({ chunks: chunkById, mainChunkIds: mainChunkIds });
|
|
27
|
+
const placeableChunks = [...chunkById]
|
|
28
|
+
.filter(([chunkId]) => !mainChunkIds.has(chunkId))
|
|
29
|
+
.map(([chunkId, chunk]) => ({
|
|
30
|
+
chunkId: chunkId,
|
|
31
|
+
estimatedBytes: estimateChunkBytes(chunk) +
|
|
32
|
+
chunk.moduleIds.reduce((bytes, moduleId) => bytes + getAdditionalModuleBytes(moduleId), 0),
|
|
33
|
+
transitions: transitionsByChunk.get(chunkId) ?? new Set()
|
|
34
|
+
}));
|
|
35
|
+
const subpackages = packChunks({
|
|
36
|
+
chunks: placeableChunks,
|
|
37
|
+
planningBudgetBytes: subpackagePlanningBudget
|
|
38
|
+
}).map(createPackedSubpackage);
|
|
39
|
+
// This local map accumulates the immutable plan returned to output materialization.
|
|
40
|
+
const locationByChunk = new Map();
|
|
41
|
+
for (const chunkId of mainChunkIds) {
|
|
42
|
+
locationByChunk.set(chunkId, mainPackage);
|
|
43
|
+
}
|
|
44
|
+
for (const subpackage of subpackages) {
|
|
45
|
+
for (const chunkId of subpackage.chunkIds) {
|
|
46
|
+
locationByChunk.set(chunkId, subpackage);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
function getLocation(chunkId) {
|
|
50
|
+
const location = locationByChunk.get(chunkId);
|
|
51
|
+
if (!location) {
|
|
52
|
+
throw new Error(`wx placement is missing final chunk: ${chunkId}`);
|
|
53
|
+
}
|
|
54
|
+
return location;
|
|
55
|
+
}
|
|
56
|
+
/** Resolves typed ownership from Rolldown's preliminary physical filename before or after finalization. */
|
|
57
|
+
function getPackageLocation(chunk) {
|
|
58
|
+
return getLocation('preliminaryFileName' in chunk ? chunk.preliminaryFileName : chunk.fileName);
|
|
59
|
+
}
|
|
60
|
+
return {
|
|
61
|
+
getPackageLocation: getPackageLocation,
|
|
62
|
+
/** Adds the planned package root to a physical preliminary path without changing the chunk's SystemJS identity. */
|
|
63
|
+
getPhysicalChunkId(chunk) {
|
|
64
|
+
const location = getPackageLocation(chunk);
|
|
65
|
+
return location.kind === 'main' ? chunk.fileName : `${location.root}/${chunk.fileName}`;
|
|
66
|
+
},
|
|
67
|
+
/** Selects the native loading API directly from typed package ownership. */
|
|
68
|
+
getLoadMode(chunk) {
|
|
69
|
+
return getPackageLocation(chunk).kind === 'subpackage' ? 'async' : 'sync';
|
|
70
|
+
},
|
|
71
|
+
/** Assigns each final chunk's Rolldown-owned physical filename and declares typed owners that survived output. */
|
|
72
|
+
finalize(bundle) {
|
|
73
|
+
const outputChunks = Object.values(bundle).filter((output) => output.type === 'chunk');
|
|
74
|
+
// This local mutable set deduplicates typed package owners that retain at least one final output chunk.
|
|
75
|
+
const roots = new Set();
|
|
76
|
+
for (const chunk of outputChunks) {
|
|
77
|
+
// OutputChunk.fileName contains the resolved content hash. preliminaryFileName preserves the exact physical
|
|
78
|
+
// candidate with placeholders that identified this chunk when placement was created during renderChunk.
|
|
79
|
+
const location = getLocation(chunk.preliminaryFileName);
|
|
80
|
+
if (location.kind !== 'subpackage') {
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
// OutputChunk is mutable in generateBundle. Assigning fileName makes Rolldown retain all chunk metadata and
|
|
84
|
+
// write that same chunk at its physical package path; deleting bundle keys or re-emitting would lose identity.
|
|
85
|
+
chunk.fileName = `${location.root}/${chunk.fileName}`;
|
|
86
|
+
roots.add(location.root);
|
|
87
|
+
}
|
|
88
|
+
return [...roots].sort().map((root) => ({
|
|
89
|
+
name: root.slice(root.lastIndexOf('/') + 1),
|
|
90
|
+
root: root,
|
|
91
|
+
pages: []
|
|
92
|
+
}));
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
/** Keeps every explicit output entry and its complete static chunk closure in main. */
|
|
97
|
+
function findMainChunkIds(chunks) {
|
|
98
|
+
const mainChunkIds = new Set();
|
|
99
|
+
// The worklist avoids recursion and visits every eager static edge once.
|
|
100
|
+
const pending = [...chunks].filter(([, chunk]) => chunk.isEntry).map(([chunkId]) => chunkId);
|
|
101
|
+
while (pending.length > 0) {
|
|
102
|
+
const chunkId = pending.pop();
|
|
103
|
+
if (!chunkId || mainChunkIds.has(chunkId)) {
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
106
|
+
const chunk = chunks.get(chunkId);
|
|
107
|
+
if (!chunk) {
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
mainChunkIds.add(chunkId);
|
|
111
|
+
pending.push(...chunk.imports);
|
|
112
|
+
}
|
|
113
|
+
return mainChunkIds;
|
|
114
|
+
}
|
|
115
|
+
/** Creates every load-transition hyperedge and indexes its static closure by chunk. */
|
|
116
|
+
function collectTransitionsByChunk({ chunks, mainChunkIds }) {
|
|
117
|
+
const transitionsByChunk = new Map();
|
|
118
|
+
let transitionId = 0;
|
|
119
|
+
for (const chunk of chunks.values()) {
|
|
120
|
+
for (const targetId of [...chunk.dynamicImports].sort()) {
|
|
121
|
+
if (!chunks.has(targetId) || mainChunkIds.has(targetId)) {
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
for (const chunkId of collectStaticClosure({
|
|
125
|
+
rootId: targetId,
|
|
126
|
+
chunks: chunks,
|
|
127
|
+
mainChunkIds: mainChunkIds
|
|
128
|
+
})) {
|
|
129
|
+
const transitions = transitionsByChunk.get(chunkId) ?? new Set();
|
|
130
|
+
transitions.add(transitionId);
|
|
131
|
+
transitionsByChunk.set(chunkId, transitions);
|
|
132
|
+
}
|
|
133
|
+
transitionId++;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
return transitionsByChunk;
|
|
137
|
+
}
|
|
138
|
+
/** Collects one transition's static closure; nested dynamic imports remain independent transitions. */
|
|
139
|
+
function collectStaticClosure({ rootId, chunks, mainChunkIds }) {
|
|
140
|
+
const closure = new Set();
|
|
141
|
+
// The worklist follows static edges only; the visited set terminates cycles.
|
|
142
|
+
const pending = [rootId];
|
|
143
|
+
while (pending.length > 0) {
|
|
144
|
+
const chunkId = pending.pop();
|
|
145
|
+
if (!chunkId || closure.has(chunkId) || mainChunkIds.has(chunkId)) {
|
|
146
|
+
continue;
|
|
147
|
+
}
|
|
148
|
+
const chunk = chunks.get(chunkId);
|
|
149
|
+
if (!chunk) {
|
|
150
|
+
continue;
|
|
151
|
+
}
|
|
152
|
+
closure.add(chunkId);
|
|
153
|
+
pending.push(...chunk.imports);
|
|
154
|
+
}
|
|
155
|
+
return [...closure].sort();
|
|
156
|
+
}
|
|
157
|
+
/** Partitions final chunks by transition overlap before best-fit capacity. */
|
|
158
|
+
function packChunks({ chunks, planningBudgetBytes }) {
|
|
159
|
+
const bins = [];
|
|
160
|
+
const orderedChunks = [...chunks].sort(compareChunks);
|
|
161
|
+
for (const chunk of orderedChunks) {
|
|
162
|
+
const bin = chunk.estimatedBytes <= planningBudgetBytes
|
|
163
|
+
? (findBestBin({ bins: bins, chunk: chunk, planningBudgetBytes: planningBudgetBytes }) ??
|
|
164
|
+
createBin(bins))
|
|
165
|
+
: createBin(bins);
|
|
166
|
+
placeChunk(bin, chunk);
|
|
167
|
+
}
|
|
168
|
+
return bins;
|
|
169
|
+
}
|
|
170
|
+
/** Gives globally shared transition demand priority, then size and stable preliminary filename. */
|
|
171
|
+
function compareChunks(left, right) {
|
|
172
|
+
return (right.transitions.size - left.transitions.size ||
|
|
173
|
+
right.estimatedBytes - left.estimatedBytes ||
|
|
174
|
+
left.chunkId.localeCompare(right.chunkId));
|
|
175
|
+
}
|
|
176
|
+
/** Chooses maximum transition overlap, then the fullest fitting package and stable creation order. */
|
|
177
|
+
function findBestBin({ bins, chunk, planningBudgetBytes }) {
|
|
178
|
+
let best;
|
|
179
|
+
for (const bin of bins) {
|
|
180
|
+
if (bin.estimatedBytes + chunk.estimatedBytes > planningBudgetBytes) {
|
|
181
|
+
continue;
|
|
182
|
+
}
|
|
183
|
+
const candidate = {
|
|
184
|
+
bin: bin,
|
|
185
|
+
overlap: countOverlap(bin.transitions, chunk.transitions),
|
|
186
|
+
remainingBytes: planningBudgetBytes - bin.estimatedBytes - chunk.estimatedBytes
|
|
187
|
+
};
|
|
188
|
+
if (!best ||
|
|
189
|
+
candidate.overlap > best.overlap ||
|
|
190
|
+
(candidate.overlap === best.overlap && candidate.remainingBytes < best.remainingBytes)) {
|
|
191
|
+
best = candidate;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
return best?.bin;
|
|
195
|
+
}
|
|
196
|
+
/** Counts transition-package incidences removed by one candidate placement. */
|
|
197
|
+
function countOverlap(left, right) {
|
|
198
|
+
const [smaller, larger] = left.size <= right.size ? [left, right] : [right, left];
|
|
199
|
+
let overlap = 0;
|
|
200
|
+
for (const transition of smaller) {
|
|
201
|
+
if (larger.has(transition)) {
|
|
202
|
+
overlap++;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
return overlap;
|
|
206
|
+
}
|
|
207
|
+
/** Creates one planner-local mutable package. */
|
|
208
|
+
function createBin(bins) {
|
|
209
|
+
const bin = {
|
|
210
|
+
chunkIds: [],
|
|
211
|
+
estimatedBytes: 0,
|
|
212
|
+
transitions: new Set()
|
|
213
|
+
};
|
|
214
|
+
bins.push(bin);
|
|
215
|
+
return bin;
|
|
216
|
+
}
|
|
217
|
+
/** Applies one irreversible, non-duplicating final chunk assignment. */
|
|
218
|
+
function placeChunk(bin, chunk) {
|
|
219
|
+
bin.chunkIds.push(chunk.chunkId);
|
|
220
|
+
bin.estimatedBytes += chunk.estimatedBytes;
|
|
221
|
+
for (const transition of chunk.transitions) {
|
|
222
|
+
bin.transitions.add(transition);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
/** Estimates final output bytes from tree-shaken modules plus a bounded generated-chunk allowance. */
|
|
226
|
+
function estimateChunkBytes(chunk) {
|
|
227
|
+
const renderedModuleBytes = Object.values(chunk.modules).reduce((bytes, module) => bytes + (module.code ? Buffer.byteLength(module.code, 'utf8') : 0), 0);
|
|
228
|
+
const moduleWrapperBytes = chunk.moduleIds.length * 64;
|
|
229
|
+
const referenceBytes = (chunk.imports.length + chunk.dynamicImports.length) * 32;
|
|
230
|
+
return renderedModuleBytes + moduleWrapperBytes + referenceBytes + 64;
|
|
231
|
+
}
|
|
232
|
+
/** Freezes membership and derives a stable root from sorted preliminary filenames. */
|
|
233
|
+
function createPackedSubpackage(bin) {
|
|
234
|
+
const chunkIds = [...bin.chunkIds].sort();
|
|
235
|
+
const hash = createHash('sha256').update(chunkIds.join('\0')).digest('hex').slice(0, 8);
|
|
236
|
+
return {
|
|
237
|
+
kind: 'subpackage',
|
|
238
|
+
root: `${generatedSubpackageRootPrefix}${hash}`,
|
|
239
|
+
chunkIds: chunkIds
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
/** Tests the plugin-owned output prefix that physically identifies every generated subpackage. */
|
|
243
|
+
export function isGeneratedSubpackageFile(fileName) {
|
|
244
|
+
return fileName.startsWith(generatedSubpackageRootPrefix);
|
|
245
|
+
}
|