@tarojs/webpack5-runner 4.2.3-beta.1 → 4.3.1-alpha.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.
Files changed (41) hide show
  1. package/dist/index.mini.js +15 -4
  2. package/dist/index.mini.js.map +1 -1
  3. package/dist/plugins/AsyncSubPackagePlugin.js +46 -1
  4. package/dist/plugins/AsyncSubPackagePlugin.js.map +1 -1
  5. package/dist/plugins/BuildNativePlugin.js +9 -0
  6. package/dist/plugins/BuildNativePlugin.js.map +1 -1
  7. package/dist/plugins/HarmonyPlugin.js +3 -1
  8. package/dist/plugins/HarmonyPlugin.js.map +1 -1
  9. package/dist/plugins/MiniCompileModePlugin.js +8 -5
  10. package/dist/plugins/MiniCompileModePlugin.js.map +1 -1
  11. package/dist/plugins/MiniPlugin.js +73 -21
  12. package/dist/plugins/MiniPlugin.js.map +1 -1
  13. package/dist/plugins/SubPackageIndiePlugin.js +42 -4
  14. package/dist/plugins/SubPackageIndiePlugin.js.map +1 -1
  15. package/dist/plugins/TaroInjectSyncCorePlugin.js +39 -0
  16. package/dist/plugins/TaroInjectSyncCorePlugin.js.map +1 -0
  17. package/dist/plugins/TaroLoadChunksPlugin.js +27 -1
  18. package/dist/plugins/TaroLoadChunksPlugin.js.map +1 -1
  19. package/dist/shared-runtime/app-shim.js +305 -0
  20. package/dist/shared-runtime/async-provider.js +153 -0
  21. package/dist/shared-runtime/build-shared-runtime.js +479 -0
  22. package/dist/shared-runtime/build-shared-runtime.js.map +1 -0
  23. package/dist/shared-runtime/constants.js +51 -0
  24. package/dist/shared-runtime/constants.js.map +1 -0
  25. package/dist/shared-runtime/entry.sync.js +102 -0
  26. package/dist/shared-runtime/externals.js +96 -0
  27. package/dist/shared-runtime/externals.js.map +1 -0
  28. package/dist/shared-runtime/scan-imperative-api.js +267 -0
  29. package/dist/shared-runtime/scan-imperative-api.js.map +1 -0
  30. package/dist/template/comp-new-blended.js +5 -0
  31. package/dist/utils/platform.js +12 -0
  32. package/dist/utils/platform.js.map +1 -0
  33. package/dist/utils/webpack.js +42 -1
  34. package/dist/utils/webpack.js.map +1 -1
  35. package/dist/webpack/HarmonyWebpackPlugin.js +1 -3
  36. package/dist/webpack/HarmonyWebpackPlugin.js.map +1 -1
  37. package/dist/webpack/MiniCombination.js +51 -26
  38. package/dist/webpack/MiniCombination.js.map +1 -1
  39. package/dist/webpack/MiniWebpackPlugin.js +17 -1
  40. package/dist/webpack/MiniWebpackPlugin.js.map +1 -1
  41. package/package.json +15 -13
@@ -0,0 +1,153 @@
1
+ /* global __TARO_GLOBAL_OBJECT__, __TARO_SHARED_GLOBAL__, __TARO_RUNTIME_VERSION__ */
2
+ /**
3
+ * 共享运行时(split 模式) · async-provider —— 落在 shared-async 子包,被 require.async 加载后执行。
4
+ * 把 react 协调链 + framework + api 真身原地 mutate 进同步核预放的占位对象(保引用),再 flush。
5
+ *
6
+ * 分工(关键):
7
+ * - react / react/jsx-runtime / @tarojs/runtime / @tarojs/shared / 平台 runtime
8
+ * 由 webpack config external 到全局(读同步核那份),避免双实例(react/document 双份)。
9
+ * - react-reconciler / scheduler / react-dom(reconciler 适配) / framework / @tarojs/api
10
+ * 真实打进本异步核 bundle,并在此注册到全局,供业务包读取。
11
+ *
12
+ * 全局名 / 版本号由 DefinePlugin 注入的宏提供(单一来源为 constants.ts)。
13
+ */
14
+
15
+ // React 页面/App 生命周期 hook 名称约定:`use[A-Z]` 前缀(与 B6 scan-imperative-api 同款约定)。
16
+ // 用正则动态从 framework runtime 导出中提取所有匹配项,避免维护硬编码清单——framework 新增/重命名
17
+ // hook 时零改动,天然消除跨版本漂移(早期曾有两处硬编码列表漂移过)。
18
+ var REACT_HOOK_NAME_RE = /^use[A-Z]/
19
+
20
+ function fill (target, real) {
21
+ if (!target || !real) return
22
+ Object.keys(real).forEach(function (k) { target[k] = real[k] })
23
+ if (real.default && !target.default) target.default = real.default
24
+ }
25
+
26
+ function share (shared, name, mod) { if (!shared[name]) shared[name] = mod }
27
+
28
+ function activate () {
29
+ var GLOBAL_KEY = __TARO_SHARED_GLOBAL__
30
+ var shared = __TARO_GLOBAL_OBJECT__[GLOBAL_KEY] || (__TARO_GLOBAL_OBJECT__[GLOBAL_KEY] = {})
31
+
32
+ // 占位就绪守卫:正常时序下同步核已跑(runtime/占位齐全)。若 activate 早于同步核
33
+ // (如宿主 onLaunch 主动 require.async 预热),此时占位对象尚不存在——只登记,不 fill,
34
+ // 真正 fill 仍由业务页同步核的 require.async().then(__activateAsync) 触发。
35
+ if (!shared['@tarojs/runtime'] || !shared['@tarojs/taro']) {
36
+ return
37
+ }
38
+ // 幂等:避免重复激活(预热 + 正常触发各调一次)
39
+ if (shared.__rtActivated) return
40
+
41
+ // 版本一致性校验 fail-fast:同步核与异步核必须同一运行时协议版本,否则接口可能错配。
42
+ if (shared.__rtVersion !== __TARO_RUNTIME_VERSION__) {
43
+ throw new Error(
44
+ '[taro-shared] 运行时协议版本不一致:同步核 v' + shared.__rtVersion +
45
+ ' 与异步核 v' + __TARO_RUNTIME_VERSION__ + ' 不匹配。请确保业务包与共享运行时用同一版本重新编译。'
46
+ )
47
+ }
48
+
49
+ // 先置激活标记:占位 Proxy 的 realFlag 依赖它。置位后 provider 自身对占位对象的
50
+ // 读写(含下方读 taroObj.showToast)不会被 Proxy 拦截。
51
+ shared.__rtActivated = true
52
+
53
+ // react 协调链真身:react-dom(小程序下=@tarojs/react reconciler 适配)
54
+ var reactDom = require('@tarojs/react')
55
+ var framework = require('@tarojs/plugin-framework-react/dist/runtime')
56
+ var taro = require('@tarojs/taro') // 触发 initNativeApi(平台 runtime 已同步注册)
57
+
58
+ // 注册 reconciler / scheduler 到全局:业务包 external 了这两个,真身在本异步核,必须显式挂全局,
59
+ // 否则业务包 require('react-reconciler')/require('scheduler') 读到 undefined(运行时崩)。
60
+ //
61
+ // 单一真理源:externals.ts::ASYNC_REACT_MEMBERS。webpack CommonJS 静态分析要求 require 参数为
62
+ // 字面量字符串——故此处不能用宏或数组遍历,改动本对时必须同步 externals.ts 的 ASYNC_REACT_MEMBERS。
63
+ share(shared, 'react-reconciler', require('react-reconciler'))
64
+ share(shared, 'scheduler', require('scheduler'))
65
+
66
+ // react-dom 真身填进同步核预放的占位对象(保引用)
67
+ fill(shared['react-dom'], reactDom)
68
+
69
+ // framework-runtime 真身填进占位。fill 后 fw.createReactApp 指向真身,
70
+ // 后续业务包 app.js 顶层 `createReactApp(App_B, ...)` 直接走真身,内部 last-writer
71
+ // 覆盖 Current.app,与 Taro 单份 runtime 原生语义一致(见 packages/taro-framework-react
72
+ // /src/runtime/connect.ts:434 `Current.app = appObj` 无守卫赋值)。
73
+ var fw = shared['@tarojs/plugin-framework-react/dist/runtime']
74
+ fill(fw, framework)
75
+
76
+ // F5 多包 App 隔离:异步核激活后再加载的业务包会直接调 fw.createReactApp 走真身,
77
+ // 但真身不知道 pkgId、不存表。用 wrapper 兜底:走真身 + 按 pkgId 存进 __pkgApps 表,
78
+ // 使异步核激活后加载的包也能被 page loader onLoad 前查回本包 App。
79
+ // (早前拆掉的 "重定向到首包" 兜底与此不同——那是 first-wins 违反 last-writer;这里只
80
+ // "存表",不改 Current.app 的 last-writer 结果。)
81
+ var realCreateReactApp = fw.createReactApp
82
+ fw.createReactApp = function (App, react, reactDom, config) {
83
+ var realAppObj = realCreateReactApp(App, react, reactDom, config)
84
+ var pkgId = shared.__currentPkgId
85
+ if (pkgId) {
86
+ shared.__pkgApps = shared.__pkgApps || {}
87
+ shared.__pkgApps[pkgId] = realAppObj
88
+ }
89
+ return realAppObj
90
+ }
91
+
92
+ // @tarojs/taro 真身填进占位(命令式 API 就位)
93
+ var taroObj = shared['@tarojs/taro']
94
+ fill(taroObj, taro)
95
+ // 合并 framework hooks(useLoad 等)进 @tarojs/taro,业务 `import { useLoad } from '@tarojs/taro'` 才有值。
96
+ // 动态扫 framework 所有 `use[A-Z]*` 导出,避免硬编码清单跨版本漂移。
97
+ Object.keys(framework).forEach(function (n) {
98
+ if (REACT_HOOK_NAME_RE.test(n) && typeof framework[n] === 'function') {
99
+ taroObj[n] = framework[n]
100
+ }
101
+ })
102
+
103
+ // 平台 API 兜底:若 taro 命令式 API 尚未注入,触发 initNativeApi
104
+ var runtime = shared['@tarojs/runtime']
105
+ if (typeof taroObj.showToast !== 'function' && runtime.hooks && runtime.hooks.isExist('initNativeApi')) {
106
+ runtime.hooks.call('initNativeApi', taroObj)
107
+ }
108
+
109
+ // 补跑 initPxTransform(同步核占位阶段存的参数)。
110
+ // 注意 taro/taroObj 是两个对象:taro 是异步核内打包的 @tarojs/taro 真身(initPxTransform 把
111
+ // config 写在它自己身上);taroObj 是同步核预放、fill 后的共享占位对象——业务页面 require
112
+ // ('@tarojs/taro') external 到的是**占位对象**。只调 taro.initPxTransform 会把 config 留在
113
+ // 真身上,页面侧读占位对象的 config 拿到 null → 运行时 pxTransform 落回默认 750 基准,
114
+ // root font-size 算小一半(字号整体缩小)。补跑后必须把 config 原地同步给占位对象。
115
+ if (shared.__pxTransformOpts && typeof taro.initPxTransform === 'function') {
116
+ taro.initPxTransform(shared.__pxTransformOpts)
117
+ if (taro.config) {
118
+ taroObj.config = taroObj.config || {}
119
+ Object.keys(taro.config).forEach(function (k) { taroObj.config[k] = taro.config[k] })
120
+ }
121
+ }
122
+
123
+ // 建真 appObj + flush 生命周期/mount 队列。
124
+ // 用真身 framework 建 realAppObj,内部覆盖 Current.app = realAppObj。
125
+ if (typeof shared.__activateReal === 'function') {
126
+ shared.__activateReal(framework)
127
+ }
128
+
129
+ // F6 native-components:同步核阶段 native-comp 产物顶层调的是占位 createNativeComponentConfig
130
+ // (app-shim 装的),返回占位描述符、生命周期(created/attached/ready…)全被缓存。此刻真身就位,
131
+ // 用真身 framework.createNativeComponentConfig 为每个已注册组件重建真描述符,并按序重放缓存的
132
+ // 生命周期调用(created 建 Entry → attached 挂载 → ready 触发)。这是 native-comp 能渲染的关键——
133
+ // 缺它则占位描述符只是空转发器,组件永不 mount。
134
+ if (typeof shared.__replayNativeCompConfigs === 'function') {
135
+ shared.__replayNativeCompConfigs(framework)
136
+ }
137
+
138
+ // F6 兜底:flush 遗留的 native-comp mount 队列(占位+重放路径下 created 已同步建 Entry,
139
+ // attached 重放时 resolveApp 已能查回 App,此队列通常为空;保留作纵深防御,空队列时无副作用)。
140
+ if (typeof shared.__flushNativeCompQueue === 'function') {
141
+ shared.__flushNativeCompQueue()
142
+ }
143
+ }
144
+
145
+ // 被同步核 require.async 加载时,把 activate 挂到全局供同步核回调。
146
+ // 顶层防御:即使全局未初始化(预热早于同步核)也能安全挂载。
147
+ (function () {
148
+ var GLOBAL_KEY = __TARO_SHARED_GLOBAL__
149
+ var g = __TARO_GLOBAL_OBJECT__[GLOBAL_KEY] || (__TARO_GLOBAL_OBJECT__[GLOBAL_KEY] = {})
150
+ g.__activateAsync = activate
151
+ })()
152
+
153
+ module.exports = { activate: activate }
@@ -0,0 +1,479 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
26
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
27
+ return new (P || (P = Promise))(function (resolve, reject) {
28
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
29
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
30
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
31
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
32
+ });
33
+ };
34
+ var __importDefault = (this && this.__importDefault) || function (mod) {
35
+ return (mod && mod.__esModule) ? mod : { "default": mod };
36
+ };
37
+ Object.defineProperty(exports, "__esModule", { value: true });
38
+ exports.buildSharedRuntime = void 0;
39
+ const path = __importStar(require("node:path"));
40
+ const helper_1 = require("@tarojs/helper");
41
+ const webpack_1 = __importDefault(require("webpack"));
42
+ const webpack_chain_1 = __importDefault(require("webpack-chain"));
43
+ const constants_1 = require("./constants");
44
+ const externals_1 = require("./externals");
45
+ /**
46
+ * 主构建成功后,额外跑独立 webpack 子构建产出共享运行时(split 模式):
47
+ * - sync-core(taro-shared-sync.js):随业务包,emit 到 outputDir 根,同步 require。
48
+ * - async-provider:放异步子包 shared-async-v1/,全局共享一份。
49
+ *
50
+ * 为何独立 webpack 而非 child compiler:主构建 externals 把 @tarojs/*+react 外置了,
51
+ * 而这些 bundle 要把它们真正打进产物,依赖集正相反。独立 compiler 自带反向 external。
52
+ * 依赖解析:react/@tarojs/* 从用户项目 node_modules 解析(resolve.modules 指向 appPath)。
53
+ *
54
+ * 产物语法(ES5):本子构建内置 babel-loader 转译规则(见 buildSharedRuntime 内注释),
55
+ * 保证打进两核的 @tarojs/*(tsc 产物为 ES2015/2017,含 class/let/模板串)、extraPackages
56
+ * 与运行时模板全部降为 ES5——与主构建对业务代码的转译基线一致(宿主宿主侧开发者工具
57
+ * 常配 "es6": false,ES6+ 产物在低版本基础库真机会语法报错)。同步核/异步核各有一个
58
+ * webpack-chain,接入方可经 config.mini.sharedRuntimeWebpackChain 对各自定义微调。
59
+ */
60
+ function buildSharedRuntime(combination) {
61
+ return __awaiter(this, void 0, void 0, function* () {
62
+ var _a, _b, _c;
63
+ const { appPath, outputDir } = combination;
64
+ const config = combination.config;
65
+ const globalObject = ((_a = config.output) === null || _a === void 0 ? void 0 : _a.globalObject) || 'wx';
66
+ const shimDir = path.resolve(__dirname); // dist/shared-runtime(运行时模板所在)
67
+ const userNodeModules = path.resolve(appPath, 'node_modules');
68
+ const asyncRequest = getAsyncRequest(config);
69
+ // 共享运行时模板子构建的 DefinePlugin 常量:按 config 重建 runtime 分支常量(保 DOM 分支与主构建一致),
70
+ // 叠加运行时模板所需的宏。
71
+ const defineConstants = Object.assign(Object.assign(Object.assign({}, collectUserDefineConstants(combination)), buildDefineConstants(config)), {
72
+ // 运行时模板(entry.sync.js / async-provider.js)引用的宏,单一来源为 constants.ts + globalObject 配置:
73
+ // 注意:__TARO_GLOBAL_OBJECT__ 是**标识符**(不 JSON.stringify),其它是**字符串常量**(JSON.stringify)。
74
+ __TARO_GLOBAL_OBJECT__: globalObject, __TARO_SHARED_GLOBAL__: JSON.stringify(constants_1.SHARED_GLOBAL_ASYNC), __TARO_SHARED_ASYNC_REQUEST__: JSON.stringify(asyncRequest), __TARO_RUNTIME_VERSION__: JSON.stringify(constants_1.RUNTIME_GLOBAL_VERSION) });
75
+ // 接入方声明的额外共享包(CLI 不认识具体包名),按加载时机分两类:
76
+ // - sharedRuntimeExtraPackages: 随异步核加载,多业务包共享(不参与首屏时序的 API 定义/异步初始化)
77
+ // - sharedRuntimeSyncExtraPackages: 随同步核加载,每业务包各带一份(必须在首屏 window INIT
78
+ // 广播前注册监听器/写全局状态等——异步核 .then 晚于首屏 onLoad,时机敏感副作用放这里)
79
+ // 两者都被 shouldShareExternal 识别为共享 external,不进业务包主 bundle,仅执行时机不同。
80
+ const extraPackages = config.sharedRuntimeExtraPackages || [];
81
+ const syncExtraPackages = config.sharedRuntimeSyncExtraPackages || [];
82
+ // 平台插件(plugin-html/plugin-inject/plugin-http/*-devtools 等)通过 platform.runtimePath 注入的
83
+ // side-effect runtime 也是 @tarojs/*,被主构建 external 成读共享全局,但运行时核只注册固定清单,
84
+ // 会漏掉它们 → 业务包读到 undefined → 其 hooks.tap 从未执行(如 plugin-html 的 <i> 标签映射失效,
85
+ // 报 `Template tmpl_0_i not found`)。这里从 runtimePath 挑出漏网项,一并作为同步核额外入口打包执行,
86
+ // 使其副作用在同步核内(与模板消费方同一 @tarojs/shared 单例)就位。对业务透明,无需手动声明。
87
+ const missingRuntimes = (0, externals_1.computeMissingRuntimes)(config.runtimePath, extraPackages, syncExtraPackages);
88
+ // entry 用数组多入口:extras 先执行副作用,最后核心 entry.
89
+ // webpack 会按 __webpack_exec__ 序列依次执行,extras 顶层副作用(mergeReconciler 等)必然先于
90
+ // 核心 entry 完成——mock-exec 已实测证实(Node vm 跑产物 + mock @tarojs/shared,验证 hostConfig
91
+ // 被 tap、initNativeApi hook 就位)。
92
+ const buildEntry = (coreEntryFile, extras) => {
93
+ const core = path.join(shimDir, coreEntryFile);
94
+ return extras.length ? [...extras, core] : core;
95
+ };
96
+ /**
97
+ * 子构建的 babel-loader 转译选项——复用业务项目的 babel 配置(与主构建给业务代码用的
98
+ * 同一套 preset/targets,默认 ios 9 / android 5),保证两核与业务包语法基线一致:
99
+ * - cwd/root 指向用户项目(appPath):babel 从业务项目找 babel.config.js / babel-preset-taro
100
+ * (node_modules 靠 resolve.modules 的 appPath 定位)。
101
+ * - babelrc: false + 显式 configFile 查找:两核的输入含 node_modules 里的运行时包,
102
+ * .babelrc 是 legacy 的**就近生效**文件——node_modules 深处或业务目录里残留的 .babelrc
103
+ * 会意外改变两核转译行为,显式关掉,只认项目根的 babel.config.js 系列。
104
+ * (这是有意与主构建不同的偏离:主构建的 babel-loader 未关 babelrc,但业务源码都在
105
+ * 项目内、离残留 .babelrc 距离可控;两核输入面更广,收紧更稳。)
106
+ * - 未找到 configFile 时 babel 落回 root=appPath 的默认查找(含 babel.config.json),
107
+ * 与无 babel 配置项目的主构建行为一致,不引入新分歧。
108
+ * - 不开 cacheDirectory:与主构建 script rule 保持一致(主构建未开),且 babel-loader 8.2.1
109
+ * 的缓存哈希在 Node 17+(OpenSSL 3)下有 md4 报错风险,避免给两核引入环境相关的坑。
110
+ */
111
+ const getBabelLoaderOptions = () => {
112
+ const findConfigFile = (basename) => {
113
+ const file = path.join(appPath, basename);
114
+ return helper_1.fs.existsSync(file) ? file : undefined;
115
+ };
116
+ return {
117
+ cwd: appPath,
118
+ root: appPath,
119
+ // .babelrc 是 legacy 就近生效文件,业务目录下残留会意外改变两核的转译行为;显式关掉。
120
+ babelrc: false,
121
+ // babel.config.js / .babelrc.js / .cjs 均可(与 babel 默认查找一致),找到哪个用哪个。
122
+ configFile: findConfigFile('babel.config.js') || findConfigFile('babel.config.cjs') || findConfigFile('babel.config.mjs') || findConfigFile('.babelrc.js'),
123
+ compact: false,
124
+ };
125
+ };
126
+ /**
127
+ * 同步核/异步核共用的 webpack-chain 骨架。
128
+ *
129
+ * 为什么改用 webpack-chain 而非继续拼裸 config:接入方此前对这两个子构建**没有任何定制入口**
130
+ * (主构建的 webpackChain/modifyWebpackChain 只作用于主 chain),extraPackages 带来的私有
131
+ * runtime 需要 loader/resolve 级定制(如私有语法插件)时无从下手。现在两核各有 chain,
132
+ * 接入方经 config.mini.sharedRuntimeWebpackChain 拿到 (chain, webpack, data) 可自由微调,
133
+ * 与主构建 webpackChain 的签名约定一致(data 携带核心信息,见 ISharedRuntimeChainData)。
134
+ *
135
+ * 内置规则只有一条:script 全量过 babel-loader(无 include 限制——两核的输入全是被主构建
136
+ * external 掉的运行时包,主构建从不转译它们,这里必须兜底转全量),产出 ES5。
137
+ * regenerator-runtime alias 与主构建 MiniBaseConfig 同源:值都解析到 runner 自带的那份
138
+ * regenerator-runtime@0.11(require.resolve 不带 paths,从 runner 自身 node_modules 解析,
139
+ * 不依赖业务项目依赖布局);不设 alias 时它反而可能经 resolve.modules(userNodeModules
140
+ * 在前)解析到业务项目的另一份,alias 把这个不确定性钉死。
141
+ */
142
+ const base = (name, entry, emitTo, extras) => {
143
+ const chain = new webpack_chain_1.default();
144
+ chain.merge({
145
+ name,
146
+ mode: 'production',
147
+ target: ['web', 'es5'],
148
+ entry: { [name]: buildEntry(entry, extras) },
149
+ output: {
150
+ path: path.join(outputDir, emitTo),
151
+ filename: `${name}.js`,
152
+ globalObject,
153
+ iife: true,
154
+ },
155
+ optimization: { minimize: true, splitChunks: false, runtimeChunk: false },
156
+ resolve: {
157
+ modules: [userNodeModules, 'node_modules'],
158
+ alias: {
159
+ // 与主构建 MiniBaseConfig 同源(require.resolve 不带 paths,从 runner 自身 node_modules
160
+ // 解析 regenerator-runtime@0.11,不依赖业务项目依赖布局)
161
+ 'regenerator-runtime': require.resolve('regenerator-runtime'),
162
+ },
163
+ },
164
+ module: {
165
+ rule: {
166
+ script: {
167
+ test: helper_1.REG_SCRIPTS,
168
+ use: {
169
+ babelLoader: {
170
+ loader: require.resolve('babel-loader'),
171
+ options: getBabelLoaderOptions(),
172
+ },
173
+ },
174
+ },
175
+ },
176
+ },
177
+ plugin: {
178
+ define: { plugin: webpack_1.default.DefinePlugin, args: [defineConstants] },
179
+ limitChunkCount: { plugin: webpack_1.default.optimize.LimitChunkCountPlugin, args: [{ maxChunks: 1 }] },
180
+ },
181
+ });
182
+ // 内置 externals:先把骨架的 externals/externalsType 装配完,再调接入方钩子——
183
+ // 与主构建同构(主构建在 process() 写完 externals 后才在 post() 里跑 webpackChain,
184
+ // 钩子因此可以覆盖/追加 externals)。若钩子先跑,此处 externals() 会用 deepmerge
185
+ // 合并甚至盖掉钩子写入的条目,接入方定制被静默丢弃。
186
+ // webpack-chain v6 未内置 externalsType 快捷键(extend 列表里没有),直接 set 写 store。
187
+ if (name === constants_1.SHARED_SYNC_CORE_NAME) {
188
+ // require.async(shared-async-v1/index) 由 externalsType='promise' 编译得到。
189
+ chain.set('externalsType', 'promise');
190
+ chain.externals({ [asyncRequest]: `require.async(${JSON.stringify(asyncRequest)})` });
191
+ }
192
+ else {
193
+ // async-provider:凡同步核已提供的包都读共享运行时全局,不打副本,避免双实例。
194
+ chain.externals(reverseExternals(globalObject));
195
+ }
196
+ // 接入方钩子:对两核的 chain 做最终定制(签名与主构建 webpackChain 同构)。
197
+ // 在内置装配之后调用——最后写的赢,接入方可覆盖/追加 externals、loader、plugin 等。
198
+ if (typeof config.sharedRuntimeWebpackChain === 'function') {
199
+ config.sharedRuntimeWebpackChain(chain, webpack_1.default, {
200
+ name,
201
+ emitTo,
202
+ asyncRequest,
203
+ extraPackages,
204
+ syncExtraPackages,
205
+ missingRuntimes,
206
+ appPath,
207
+ outputDir,
208
+ globalObject,
209
+ });
210
+ }
211
+ return chain;
212
+ };
213
+ // sync-core:放 outputDir 根。SyncExtraPackages 走同步核入口(时机敏感副作用)。
214
+ // missingRuntimes 前置:它们是平台级 side-effect runtime,tap 幂等无顺序依赖,前置更符合语义。
215
+ const syncCoreChain = base(constants_1.SHARED_SYNC_CORE_NAME, 'entry.sync.js', '', [...missingRuntimes, ...syncExtraPackages]);
216
+ // async-provider:放 shared-async-v1/。extraPackages(异步)以数组多入口在核心 entry 前先执行副作用。
217
+ const asyncChain = base(constants_1.SHARED_ASYNC_PROVIDER_NAME, 'async-provider.js', constants_1.SHARED_ASYNC_ROOT, extraPackages);
218
+ yield runWebpack([syncCoreChain.toConfig(), asyncChain.toConfig()]);
219
+ // subPackageIndie 自包含:把刚产出的同步核 taro-shared-sync.js 拷进每个 mainPackageRoot。
220
+ // subPackageIndie 会把 app.js 等 runtime chunks 搬进 mainPackageRoot,app.js 头部的
221
+ // require("./taro-shared-sync") 是"同级"引用——同步核也必须在同目录。根级那份保留
222
+ // (ENTRY / F6 native-components 仍从根级 require)。mainPackageRoots 由 MiniPlugin.apply
223
+ // 反向挂在 combination 上;非 subPackageIndie 场景该列表为空,此步跳过。
224
+ copySyncCoreIntoMainPackageRoots(outputDir, ((_c = (_b = combination.subPackageIndiePlugin) === null || _b === void 0 ? void 0 : _b.getAllMainPackageRoots) === null || _c === void 0 ? void 0 : _c.call(_b)) || []);
225
+ // 生成 shared-async 占位入口:index.js 同步 require 真实 chunk(async-provider.js),
226
+ // 微信 require.async 只能加载 app.json 注册过的分包页面入口。
227
+ const asyncDir = path.join(outputDir, constants_1.SHARED_ASYNC_ROOT);
228
+ const fileType = config.fileType || { templ: '.wxml', config: '.json' };
229
+ helper_1.fs.writeFileSync(path.join(asyncDir, 'index.js'), `require('./${constants_1.SHARED_ASYNC_PROVIDER_NAME}.js');\n`);
230
+ helper_1.fs.writeFileSync(path.join(asyncDir, `index${fileType.config || '.json'}`), '{"usingComponents":{}}\n');
231
+ helper_1.fs.writeFileSync(path.join(asyncDir, `index${fileType.templ || '.wxml'}`), '<view/>\n');
232
+ // 产物元数据 manifest:记录本次共享运行时用到的 react 全家桶精确版本 + 运行时协议版本。
233
+ // 供宿主/接入方排查版本一致性(多业务包 + 宿主 provider 的 react 单例必须版本一致)。
234
+ writeRuntimeManifest(asyncDir, userNodeModules, extraPackages, syncExtraPackages);
235
+ // dist 自带运行时:把 shared-async 注册进本项目 dist/app.json + 配 preloadRule,使 dist 可直接被开发者工具打开。
236
+ registerAsyncSubPackage(outputDir, fileType.config || '.json');
237
+ });
238
+ }
239
+ exports.buildSharedRuntime = buildSharedRuntime;
240
+ /**
241
+ * subPackageIndie 自包含:把 outputDir 根的 taro-shared-sync.js(及其 .LICENSE.txt)拷进每个
242
+ * mainPackageRoot,使其与被 subPackageIndie 搬进去的 app.js 同级(app.js 头部 require 的是
243
+ * "./taro-shared-sync",天然同级)。mainPackageRoots 为空时(非 subPackageIndie)直接跳过。
244
+ *
245
+ * 拷贝后清理根级冗余:subPackageIndie 的 optimizeAssets 已删根级 app.js(SubPackageIndiePlugin
246
+ * 接管了根级 ENTRY),故根级 taro-shared-sync.js 不再有消费者(ENTRY app.js 没了;native-components
247
+ * 是互斥的另一种构建,不会有 mainPackageRoot)。此时删根级那份,与 taro-blended-project@main 的
248
+ * 产物结构对齐(businessRoot 根不含同步核)。保守判断:仅当根级确无 app.js 时才删,避免误伤。
249
+ */
250
+ function copySyncCoreIntoMainPackageRoots(outputDir, mainPackageRoots) {
251
+ if (!mainPackageRoots.length)
252
+ return;
253
+ const syncCoreFile = `${constants_1.SHARED_SYNC_CORE_NAME}.js`;
254
+ const src = path.join(outputDir, syncCoreFile);
255
+ if (!helper_1.fs.existsSync(src))
256
+ return;
257
+ const licenseFile = `${syncCoreFile}.LICENSE.txt`;
258
+ const licenseSrc = path.join(outputDir, licenseFile);
259
+ const hasLicense = helper_1.fs.existsSync(licenseSrc);
260
+ for (const root of mainPackageRoots) {
261
+ const destDir = path.join(outputDir, root);
262
+ if (!helper_1.fs.existsSync(destDir))
263
+ continue;
264
+ helper_1.fs.copySync(src, path.join(destDir, syncCoreFile), { overwrite: true });
265
+ if (hasLicense)
266
+ helper_1.fs.copySync(licenseSrc, path.join(destDir, licenseFile), { overwrite: true });
267
+ }
268
+ // 根级冗余清理:根级 app.js 已被 subPackageIndie 删除 → 根级同步核无消费者,删之对齐 main。
269
+ if (!helper_1.fs.existsSync(path.join(outputDir, 'app.js'))) {
270
+ helper_1.fs.removeSync(src);
271
+ if (hasLicense)
272
+ helper_1.fs.removeSync(licenseSrc);
273
+ }
274
+ }
275
+ /**
276
+ * 写产物元数据 manifest(runtime-manifest.json)到异步子包目录。
277
+ * 记录 react 全家桶(React 单例敏感、版本错配会真出错)精确版本 + 运行时协议版本号。
278
+ * 定位:仅产物元数据,供宿主/人工排查;运行时跨包错配由同步核/异步核的 __rtVersion 校验兜底。
279
+ *
280
+ * extraPackages(config.mini.sharedRuntimeExtraPackages,如某私有插件的 runtime)的版本也一并记录:
281
+ * 随异步核打包共享,多业务包若声明不同版本会静默漂移(不像 react 全家桶有 __rtVersion 硬 gate)。
282
+ * 这里只做**记录**供人工排查,不做编译期 gate(这些包的版本差异未必出错,硬 gate 易误报,与
283
+ * react 全家桶策略一致:只 react 全家桶做硬校验)。
284
+ */
285
+ function writeRuntimeManifest(asyncDir, userNodeModules, extraPackages = [], syncExtraPackages = []) {
286
+ const REACT_FAMILY = ['react', 'react-dom', 'react-reconciler', 'scheduler', '@tarojs/react'];
287
+ const versions = {};
288
+ REACT_FAMILY.forEach((pkg) => {
289
+ const v = readPackageVersion(userNodeModules, pkg);
290
+ if (v)
291
+ versions[pkg] = v;
292
+ });
293
+ // extraPackages 可能带子路径(如 '@scope/my-shared-plugin/runtime-mini'),
294
+ // 版本要从包根 package.json 读——取 scope/包名部分(前 1 或 2 段)作为 readPackageVersion 的 key。
295
+ const collectVersions = (pkgs) => {
296
+ const out = {};
297
+ pkgs.forEach((pkg) => {
298
+ const pkgRoot = pkg.startsWith('@') ? pkg.split('/').slice(0, 2).join('/') : pkg.split('/')[0];
299
+ const v = readPackageVersion(userNodeModules, pkgRoot);
300
+ if (v)
301
+ out[pkgRoot] = v;
302
+ });
303
+ return out;
304
+ };
305
+ const extraVersions = collectVersions(extraPackages);
306
+ const syncExtraVersions = collectVersions(syncExtraPackages);
307
+ const manifest = {
308
+ runtimeProtocolVersion: constants_1.RUNTIME_GLOBAL_VERSION,
309
+ global: constants_1.SHARED_GLOBAL_ASYNC,
310
+ subPackage: constants_1.SHARED_ASYNC_ROOT,
311
+ reactFamilyVersions: versions,
312
+ extraPackageVersions: extraVersions,
313
+ syncExtraPackageVersions: syncExtraVersions,
314
+ };
315
+ helper_1.fs.writeFileSync(path.join(asyncDir, 'runtime-manifest.json'), JSON.stringify(manifest, null, 2) + '\n');
316
+ }
317
+ /** 从指定 node_modules 读取包的 version(读不到返回空串,不阻断构建) */
318
+ function readPackageVersion(nodeModules, pkg) {
319
+ try {
320
+ const pkgJson = helper_1.fs.readJSONSync(path.join(nodeModules, pkg, 'package.json'));
321
+ return pkgJson.version || '';
322
+ }
323
+ catch (_a) {
324
+ return '';
325
+ }
326
+ }
327
+ /** 把 shared-async 注册进 dist/app.json 的 subPackages(幂等),并配 preloadRule 预下载 */
328
+ function registerAsyncSubPackage(outputDir, configExt) {
329
+ const appConfigPath = path.join(outputDir, `app${configExt}`);
330
+ if (!helper_1.fs.existsSync(appConfigPath))
331
+ return;
332
+ const appConfig = helper_1.fs.readJSONSync(appConfigPath);
333
+ // 保留项目原用的大小写键:subPackages(默认)或小写 subpackages。避免两种大小写同时写回导致微信双注册冲突。
334
+ const key = appConfig.subpackages && !appConfig.subPackages ? 'subpackages' : 'subPackages';
335
+ const subPackages = appConfig[key] || [];
336
+ if (!subPackages.some((s) => s.root === constants_1.SHARED_ASYNC_ROOT)) {
337
+ subPackages.push({ root: constants_1.SHARED_ASYNC_ROOT, pages: ['index'], independent: false });
338
+ }
339
+ appConfig[key] = subPackages;
340
+ addPreloadRule(appConfig);
341
+ helper_1.fs.writeJSONSync(appConfigPath, appConfig, { spaces: 2 });
342
+ }
343
+ /**
344
+ * 配 preloadRule:进入业务页面前预下载 shared-async 分包,缩小首屏异步窗口。
345
+ * 仅对 dist 自带运行时场景(本项目 dist 可直接被开发者工具打开);宿主场景由接入方按布局自配。
346
+ * 幂等:已存在的 preloadRule 项不覆盖,只对未声明的业务页补 shared-async。
347
+ */
348
+ function addPreloadRule(appConfig) {
349
+ const preloadRule = appConfig.preloadRule || {};
350
+ // 收集业务页面路径:主包 pages + 各业务子包页面(排除 shared-async 自身)
351
+ const triggerPages = [];
352
+ (appConfig.pages || []).forEach((p) => triggerPages.push(p));
353
+ (appConfig.subPackages || appConfig.subpackages || []).forEach((sub) => {
354
+ if (sub.root === constants_1.SHARED_ASYNC_ROOT)
355
+ return;
356
+ (sub.pages || []).forEach((pg) => triggerPages.push(`${sub.root}/${pg}`.replace(/\/+/g, '/')));
357
+ });
358
+ triggerPages.forEach((page) => {
359
+ const existing = preloadRule[page];
360
+ if (!existing) {
361
+ preloadRule[page] = { packages: [constants_1.SHARED_ASYNC_ROOT], network: 'all' };
362
+ }
363
+ else if (Array.isArray(existing.packages) && !existing.packages.includes(constants_1.SHARED_ASYNC_ROOT)) {
364
+ existing.packages.push(constants_1.SHARED_ASYNC_ROOT);
365
+ }
366
+ });
367
+ if (Object.keys(preloadRule).length)
368
+ appConfig.preloadRule = preloadRule;
369
+ }
370
+ /**
371
+ * async-provider 的反向 external:凡同步核已提供的包都读共享运行时全局,不打副本,避免双实例。
372
+ * react 全家桶部分(含开发模式 jsx-dev-runtime)与 entry.sync.js 同步注册的清单保持一致——
373
+ * 单一真理源为 externals.ts 的 SYNC_REACT_MEMBERS,改动只需改那一处。
374
+ */
375
+ function reverseExternals(globalObject) {
376
+ const g = `${globalObject}.${constants_1.SHARED_GLOBAL_ASYNC}`;
377
+ const ext = (key) => `var ${g}[${JSON.stringify(key)}]`;
378
+ const result = {
379
+ // 非 react 部分:@tarojs/* 运行时和平台 runtime,同步核已提供
380
+ '@tarojs/runtime': ext('@tarojs/runtime'),
381
+ '@tarojs/shared': ext('@tarojs/shared'),
382
+ '@tarojs/plugin-platform-weapp/dist/runtime': ext('@tarojs/plugin-platform-weapp/dist/runtime'),
383
+ };
384
+ // react 全家桶部分:从 externals.ts 单一清单展开
385
+ for (const m of externals_1.SYNC_REACT_MEMBERS)
386
+ result[m] = ext(m);
387
+ return result;
388
+ }
389
+ function getAsyncRequest(config) {
390
+ // 允许接入方通过 config.mini.sharedRuntimeAsyncRequest 覆盖(业务独立编译不预知宿主布局)
391
+ const custom = config.sharedRuntimeAsyncRequest;
392
+ if (typeof custom === 'string' && custom)
393
+ return custom;
394
+ // 默认值:相对路径(业务被拷进宿主子包后由接入方按实际布局配置覆盖)
395
+ return `${constants_1.SHARED_ASYNC_ROOT}/index`;
396
+ }
397
+ /**
398
+ * 从主构建 webpack chain 收集接入方注入的自定义 DefinePlugin 常量,透传给异步核子构建。
399
+ *
400
+ * 场景:某私有插件通过 webpackChain 独立 new DefinePlugin 注入 `process.env.SOME_RUNTIME_FLAG`
401
+ * 等编译期开关控制其 runtime 行为。其 runtime 被 sharedRuntimeExtraPackages 打进异步核,但异步核
402
+ * 是独立子构建、不继承主构建 DefinePlugin,若不透传,这些 `process.env.X` 会被兜底的
403
+ * 'process.env':'({})' 吞成 undefined,致特性静默失效(真机现象:根字号开关失效 → root-font-size
404
+ * 空 → 字体变小)。
405
+ *
406
+ * 仅收集**具名精确键**(如 'process.env.X'、裸标识符),显式跳过 'process' / 'process.env' 这类
407
+ * 前缀/裸键——它们由 buildDefineConstants 兜底统一处理,不能被业务值覆盖。调用时机在主构建结束后
408
+ * (chain 已 finalize,业务 DefinePlugin 都已装配),从 combination.chain 遍历。
409
+ */
410
+ function collectUserDefineConstants(combination) {
411
+ var _a;
412
+ const result = {};
413
+ const chain = combination.chain;
414
+ const store = (_a = chain === null || chain === void 0 ? void 0 : chain.plugins) === null || _a === void 0 ? void 0 : _a.store;
415
+ if (!store || typeof store.forEach !== 'function')
416
+ return result;
417
+ store.forEach((plugin) => {
418
+ var _a;
419
+ try {
420
+ // 识别 DefinePlugin:优先引用相等(同一 webpack 实例时成立);兜底按构造器名——业务插件自行
421
+ // require('webpack') 解析到未被 pnpm 去重的另一实例时引用相等会失败,靠 .name === 'DefinePlugin'
422
+ // 仍能命中,避免静默漏收其 define 常量。
423
+ const ctor = (_a = plugin === null || plugin === void 0 ? void 0 : plugin.get) === null || _a === void 0 ? void 0 : _a.call(plugin, 'plugin');
424
+ if (ctor !== webpack_1.default.DefinePlugin && (ctor === null || ctor === void 0 ? void 0 : ctor.name) !== 'DefinePlugin')
425
+ return;
426
+ const defs = (plugin.get('args') || [])[0];
427
+ if (!defs || typeof defs !== 'object')
428
+ return;
429
+ Object.keys(defs).forEach((key) => {
430
+ // 跳过前缀/裸键,交给兜底;其余具名键透传(后续 buildDefineConstants 会覆盖同名核心键)
431
+ if (key === 'process' || key === 'process.env')
432
+ return;
433
+ result[key] = defs[key];
434
+ });
435
+ }
436
+ catch (_b) {
437
+ /* 单个插件读取失败不影响整体,跳过 */
438
+ }
439
+ });
440
+ return result;
441
+ }
442
+ /** 主构建 DefinePlugin 不可得时,按 config 重建 runtime 分支常量 */
443
+ function buildDefineConstants(config) {
444
+ var _a, _b, _c, _d, _e, _f, _g;
445
+ const runtime = config.runtime || {};
446
+ const framework = config.framework || 'react';
447
+ const buildAdapter = config.buildAdapter || 'weapp';
448
+ return {
449
+ 'process.env.FRAMEWORK': JSON.stringify(framework),
450
+ 'process.env.TARO_ENV': JSON.stringify(buildAdapter),
451
+ 'process.env.TARO_PLATFORM': JSON.stringify(process.env.TARO_PLATFORM || 'mini'),
452
+ 'process.env.SUPPORT_TARO_POLYFILL': '"disabled"',
453
+ 'process.env.NODE_ENV': JSON.stringify(config.mode || 'production'),
454
+ ENABLE_INNER_HTML: (_a = runtime.enableInnerHTML) !== null && _a !== void 0 ? _a : true,
455
+ ENABLE_ADJACENT_HTML: (_b = runtime.enableAdjacentHTML) !== null && _b !== void 0 ? _b : false,
456
+ ENABLE_SIZE_APIS: (_c = runtime.enableSizeAPIs) !== null && _c !== void 0 ? _c : false,
457
+ ENABLE_TEMPLATE_CONTENT: (_d = runtime.enableTemplateContent) !== null && _d !== void 0 ? _d : false,
458
+ ENABLE_CLONE_NODE: (_e = runtime.enableCloneNode) !== null && _e !== void 0 ? _e : false,
459
+ ENABLE_CONTAINS: (_f = runtime.enableContains) !== null && _f !== void 0 ? _f : false,
460
+ ENABLE_MUTATION_OBSERVER: (_g = runtime.enableMutationObserver) !== null && _g !== void 0 ? _g : false,
461
+ // 兜底:额外共享包可能用未知的 process.env.X 或裸 process,
462
+ // 小程序无 process 全局 → 未显式定义的都替换掉,避免 "process is not defined"。
463
+ // webpack DefinePlugin 精确键(上面的 process.env.NODE_ENV 等)优先于 'process.env' 前缀键。
464
+ 'process.env': '({})',
465
+ process: '({"env":{}})',
466
+ };
467
+ }
468
+ function runWebpack(configs) {
469
+ return new Promise((resolve, reject) => {
470
+ (0, webpack_1.default)(configs, (err, stats) => {
471
+ if (err)
472
+ return reject(err);
473
+ if (stats === null || stats === void 0 ? void 0 : stats.hasErrors())
474
+ return reject(new Error(stats.toString({ errors: true })));
475
+ resolve();
476
+ });
477
+ });
478
+ }
479
+ //# sourceMappingURL=build-shared-runtime.js.map