@tarojs/webpack5-runner 4.2.1 → 4.2.2-alpha.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/dist/index.mini.js +15 -4
- package/dist/index.mini.js.map +1 -1
- package/dist/plugins/AsyncSubPackagePlugin.js +489 -0
- package/dist/plugins/AsyncSubPackagePlugin.js.map +1 -0
- package/dist/plugins/BuildNativePlugin.js +22 -11
- package/dist/plugins/BuildNativePlugin.js.map +1 -1
- package/dist/plugins/HarmonyPlugin.js +1 -1
- package/dist/plugins/HarmonyPlugin.js.map +1 -1
- package/dist/plugins/MiniCompileModePlugin.js +49 -4
- package/dist/plugins/MiniCompileModePlugin.js.map +1 -1
- package/dist/plugins/MiniPlugin.js +282 -58
- package/dist/plugins/MiniPlugin.js.map +1 -1
- package/dist/plugins/SubPackageIndiePlugin.js +1060 -0
- package/dist/plugins/SubPackageIndiePlugin.js.map +1 -0
- package/dist/plugins/TaroInjectSyncCorePlugin.js +39 -0
- package/dist/plugins/TaroInjectSyncCorePlugin.js.map +1 -0
- package/dist/plugins/TaroNormalModule.js +16 -0
- package/dist/plugins/TaroNormalModule.js.map +1 -1
- package/dist/plugins/TaroNormalModulesPlugin.js +127 -6
- package/dist/plugins/TaroNormalModulesPlugin.js.map +1 -1
- package/dist/plugins/TaroSingleEntryPlugin.js +1 -1
- package/dist/plugins/TaroSingleEntryPlugin.js.map +1 -1
- package/dist/shared-runtime/app-shim.js +305 -0
- package/dist/shared-runtime/async-provider.js +144 -0
- package/dist/shared-runtime/build-shared-runtime.js +377 -0
- package/dist/shared-runtime/build-shared-runtime.js.map +1 -0
- package/dist/shared-runtime/constants.js +50 -0
- package/dist/shared-runtime/constants.js.map +1 -0
- package/dist/shared-runtime/entry.sync.js +102 -0
- package/dist/shared-runtime/externals.js +96 -0
- package/dist/shared-runtime/externals.js.map +1 -0
- package/dist/shared-runtime/scan-imperative-api.js +267 -0
- package/dist/shared-runtime/scan-imperative-api.js.map +1 -0
- package/dist/template/comp.js +2 -1
- package/dist/utils/asyncSubPackage.js +106 -0
- package/dist/utils/asyncSubPackage.js.map +1 -0
- package/dist/utils/component.js +2 -1
- package/dist/utils/component.js.map +1 -1
- package/dist/utils/forceCustomWrapper.js +17 -0
- package/dist/utils/forceCustomWrapper.js.map +1 -0
- package/dist/utils/webpack.js +40 -1
- package/dist/utils/webpack.js.map +1 -1
- package/dist/webpack/HarmonyWebpackPlugin.js +3 -1
- package/dist/webpack/HarmonyWebpackPlugin.js.map +1 -1
- package/dist/webpack/MiniBaseConfig.js +2 -0
- package/dist/webpack/MiniBaseConfig.js.map +1 -1
- package/dist/webpack/MiniCombination.js +51 -26
- package/dist/webpack/MiniCombination.js.map +1 -1
- package/dist/webpack/MiniWebpackPlugin.js +17 -1
- package/dist/webpack/MiniWebpackPlugin.js.map +1 -1
- package/package.json +14 -13
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 共享运行时(split 模式) · app-shim —— 占位 framework-runtime + 占位 @tarojs/taro
|
|
3
|
+
*
|
|
4
|
+
* 业务 app.js 产物真实调用序列(顶层同步执行):
|
|
5
|
+
* var o = SHARED["@tarojs/plugin-framework-react/dist/runtime"]
|
|
6
|
+
* var x = o.createReactApp(App, React, ReactDOM, config) // 此刻 framework 是占位
|
|
7
|
+
* x.onLaunch() // 立即调返回对象的 onLaunch
|
|
8
|
+
* i.initPxTransform({...}) // 占位 taro
|
|
9
|
+
*
|
|
10
|
+
* 故占位 createReactApp 必须同步返回 appObj(生命周期/mount 全排队),存下 App+config;
|
|
11
|
+
* 异步核到达后由 provider 用真身 react 重跑 createReactApp、flush 队列。
|
|
12
|
+
*
|
|
13
|
+
* 命令式 API 未就位保护:@tarojs/taro 命令式 API(getSystemInfoSync/showToast 等)在异步核,
|
|
14
|
+
* 同步核阶段只是占位。业务在异步核到位前(尤其模块顶层)同步调用会拿到 undefined 静默失效。
|
|
15
|
+
* 故给占位包一层 Proxy:未就位时访问未知成员,
|
|
16
|
+
* - 打印醒目告警(含成员名 + 修复建议),每成员只警告一次,避免刷屏;
|
|
17
|
+
* - 返回链式安全的空操作值(可当函数调用、可继续读属性/链式调用),不抛错、不崩页面。
|
|
18
|
+
* 关键:绝不 throw —— app.js 初始化早于任何异步加载,抛错会直接崩 app(连 webpack 模块 interop
|
|
19
|
+
* 读 __esModule 都会触发),且会打断业务用 `?.`/`|| {}` 写的容错代码。异步核 fill 真身后,
|
|
20
|
+
* 占位对象的键被真身覆盖,Proxy 陷阱不再触发。
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
// 占位阶段允许同步访问的成员(业务 app.js 顶层会同步用到,非命令式 API)。
|
|
24
|
+
var TARO_PLACEHOLDER_WHITELIST = {
|
|
25
|
+
initPxTransform: true,
|
|
26
|
+
// 内部标记 / 探针可能被读取,放行避免误报
|
|
27
|
+
__isTaroPlaceholder: true,
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// 框架/JS/webpack 内部属性:模块加载与对象操作会无条件读取这些(非业务命令式 API),一律放行为 undefined。
|
|
31
|
+
// 关键:webpack interop helper `__webpack_require__.n` 会读 external 模块的 __esModule/default 判断
|
|
32
|
+
// 是否 ES module——这发生在业务顶层 `import ReactDOM/Taro` 时,无关业务是否真调用 API。
|
|
33
|
+
var INTERNAL_PASS = {
|
|
34
|
+
__esModule: true,
|
|
35
|
+
default: true,
|
|
36
|
+
then: true, // 模块 interop / thenable 检测
|
|
37
|
+
toString: true,
|
|
38
|
+
valueOf: true,
|
|
39
|
+
toJSON: true, // 对象转换 / 序列化
|
|
40
|
+
constructor: true,
|
|
41
|
+
prototype: true,
|
|
42
|
+
__proto__: true,
|
|
43
|
+
nodeType: true, // 部分序列化/DOM 探测
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* 链式安全的空操作值:既能被当函数调用(返回自身),读任意属性也返回自身。
|
|
48
|
+
* 使 `Taro.getSystemInfoSync().screenWidth`、`Taro.a().b().c` 这类未就位链式调用不崩,
|
|
49
|
+
* 全程返回 noop(noop 本身可被 `?.`/`|| {}` 容错)。
|
|
50
|
+
*
|
|
51
|
+
* 关键:基元强制转换(字符串拼接 / 模板串 / Number())绝不能抛。JS 引擎转对象为基元时会读
|
|
52
|
+
* Symbol.toPrimitive / valueOf / toString,若它们返回非函数(undefined)会抛
|
|
53
|
+
* "Cannot convert object to primitive value" —— 故这几个键必须返回产出基元的函数。
|
|
54
|
+
*/
|
|
55
|
+
function makeChainableNoop () {
|
|
56
|
+
if (typeof Proxy === 'undefined') {
|
|
57
|
+
// 兜底:环境无 Proxy 则退回裸函数(仅单层安全)
|
|
58
|
+
return function () { return undefined }
|
|
59
|
+
}
|
|
60
|
+
var toEmpty = function () { return '' } // 基元转换回退:统一产出空字符串
|
|
61
|
+
var NOOP // 前置声明:Proxy handler 需在 NOOP 定义前引用它(get/apply 返回自身实现链式)
|
|
62
|
+
var noop = function () { return NOOP }
|
|
63
|
+
NOOP = new Proxy(noop, {
|
|
64
|
+
get: function (_t, key) {
|
|
65
|
+
// 基元强制转换钩子:返回产出空串的函数,保证 '' + NOOP / `${NOOP}` / Number(NOOP) 不抛
|
|
66
|
+
if (key === Symbol.toPrimitive || key === 'toString' || key === 'valueOf') return toEmpty
|
|
67
|
+
// 其余框架/JS 内部属性放行为 undefined,避免干扰 interop(如 then/__esModule 被误判)
|
|
68
|
+
if (INTERNAL_PASS[key]) return undefined
|
|
69
|
+
if (typeof key === 'symbol') return undefined
|
|
70
|
+
return NOOP // 任意属性访问返回自身,支持无限链式
|
|
71
|
+
},
|
|
72
|
+
apply: function () { return NOOP }, // 调用返回自身,支持链式调用
|
|
73
|
+
})
|
|
74
|
+
return NOOP
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// F6 native-components 占位描述符构造器。
|
|
78
|
+
// native-comp 产物顶层同步调 fw.createNativeComponentConfig(Component, react, reactDOM, config),
|
|
79
|
+
// 把返回值传给 WeChat Component() 注册。同步核阶段 framework/reactDOM 是占位,无法立刻建真描述符;
|
|
80
|
+
// 故返回一个「形状与真描述符一致」的占位描述符——WeChat 注册所需的
|
|
81
|
+
// created/attached/ready/detached/pageLifetimes/methods/properties 全部就位,每个都是 deferred
|
|
82
|
+
// 转发器:真描述符(record.realObj)到位则转发到对应方法,否则按调用顺序缓存到 record.pending,
|
|
83
|
+
// 异步核到达时由 shared.__replayNativeCompConfigs 用真身重建描述符并按序重放。
|
|
84
|
+
//
|
|
85
|
+
// 关键:WeChat 要求 Component() 在模块顶层同步调用且描述符形状完整,故不能延迟注册,只能
|
|
86
|
+
// 「同步返回占位描述符 + 生命周期延迟到真身」。这是 createReactApp 占位的 native 版对应物。
|
|
87
|
+
function makePlaceholderNativeComp (record, componentConfig, Component) {
|
|
88
|
+
// deferred(getReal):返回转发器——真描述符就绪则调其对应方法,否则按序缓存(生命周期顺序即数组顺序)。
|
|
89
|
+
// 生命周期返回值 WeChat 忽略;onShareAppMessage/onShareTimeline 有返回值但仅用户点击触发(必在
|
|
90
|
+
// 异步核之后,realObj 已就位),故缓存分支丢返回值无害。
|
|
91
|
+
function deferred (getReal) {
|
|
92
|
+
return function () {
|
|
93
|
+
var args = arguments; var self = this
|
|
94
|
+
if (record.realObj) {
|
|
95
|
+
var fn = getReal(record.realObj)
|
|
96
|
+
return typeof fn === 'function' ? fn.apply(self, args) : undefined
|
|
97
|
+
}
|
|
98
|
+
record.pending.push({ getReal: getReal, self: self, args: args })
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
var obj = {
|
|
102
|
+
options: componentConfig,
|
|
103
|
+
properties: {
|
|
104
|
+
props: {
|
|
105
|
+
type: null,
|
|
106
|
+
value: null,
|
|
107
|
+
observer: deferred(function (r) { return r.properties && r.properties.props && r.properties.props.observer }),
|
|
108
|
+
},
|
|
109
|
+
},
|
|
110
|
+
created: deferred(function (r) { return r.created }),
|
|
111
|
+
attached: deferred(function (r) { return r.attached }),
|
|
112
|
+
ready: deferred(function (r) { return r.ready }),
|
|
113
|
+
detached: deferred(function (r) { return r.detached }),
|
|
114
|
+
pageLifetimes: {
|
|
115
|
+
show: deferred(function (r) { return r.pageLifetimes && r.pageLifetimes.show }),
|
|
116
|
+
hide: deferred(function (r) { return r.pageLifetimes && r.pageLifetimes.hide }),
|
|
117
|
+
},
|
|
118
|
+
methods: {
|
|
119
|
+
eh: deferred(function (r) { return r.methods && r.methods.eh }),
|
|
120
|
+
onLoad: deferred(function (r) { return r.methods && r.methods.onLoad }),
|
|
121
|
+
onUnload: deferred(function (r) { return r.methods && r.methods.onUnload }),
|
|
122
|
+
},
|
|
123
|
+
}
|
|
124
|
+
// 分享生命周期:真描述符按 Component 声明条件添加;占位期用同一条件补 deferred 转发器,
|
|
125
|
+
// 保证 WeChat 注册时右上角分享按钮选项与真身一致(否则真身到位也补不回注册期已定的选项)。
|
|
126
|
+
var hasShareMsg = Component && (Component.onShareAppMessage || (Component.prototype && Component.prototype.onShareAppMessage) || Component.enableShareAppMessage)
|
|
127
|
+
if (hasShareMsg) {
|
|
128
|
+
obj.methods.onShareAppMessage = deferred(function (r) { return r.methods && r.methods.onShareAppMessage })
|
|
129
|
+
}
|
|
130
|
+
var hasShareTimeline = Component && (Component.onShareTimeline || (Component.prototype && Component.prototype.onShareTimeline) || Component.enableShareTimeline)
|
|
131
|
+
if (hasShareTimeline) {
|
|
132
|
+
obj.methods.onShareTimeline = deferred(function (r) { return r.methods && r.methods.onShareTimeline })
|
|
133
|
+
}
|
|
134
|
+
// 支付宝别名:真描述符在 alipay 下设 onInit/didMount/didUpdate/didUnmount。占位期同 gate 补转发器。
|
|
135
|
+
// process.env.TARO_ENV 由 build-shared-runtime 的 DefinePlugin 注入,非 alipay 时整段被 DCE 移除。
|
|
136
|
+
if (process.env.TARO_ENV === 'alipay') {
|
|
137
|
+
obj.onInit = deferred(function (r) { return r.onInit })
|
|
138
|
+
obj.didMount = deferred(function (r) { return r.didMount })
|
|
139
|
+
obj.didUpdate = deferred(function (r) { return r.didUpdate })
|
|
140
|
+
obj.didUnmount = deferred(function (r) { return r.didUnmount })
|
|
141
|
+
}
|
|
142
|
+
return obj
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// 给占位对象包 Proxy:未就位时访问未知成员 → 醒目告警(每成员一次)+ 返回链式安全空操作,绝不抛错。
|
|
146
|
+
// realFlag() 返回 true 表示真身已 fill(键已被覆盖),此时不干预、走原生取值。
|
|
147
|
+
function guardPlaceholder (target, label, whitelist, realFlag) {
|
|
148
|
+
if (typeof Proxy === 'undefined') return target // 兜底:环境无 Proxy 则退回裸对象
|
|
149
|
+
var warned = {}
|
|
150
|
+
return new Proxy(target, {
|
|
151
|
+
get: function (t, key) {
|
|
152
|
+
if (key in t) return t[key]
|
|
153
|
+
if (typeof key === 'symbol') return undefined
|
|
154
|
+
if (INTERNAL_PASS[key]) return undefined // 框架/webpack 内部属性,放行
|
|
155
|
+
if (whitelist && whitelist[key]) return undefined
|
|
156
|
+
if (realFlag && realFlag()) return undefined // 真身已到位:拼错的 key 走原生 undefined,不干预
|
|
157
|
+
if (!warned[key]) {
|
|
158
|
+
warned[key] = true
|
|
159
|
+
console.warn(
|
|
160
|
+
'[taro-shared] ' + label + '.' + String(key) + ' 尚未就位:' +
|
|
161
|
+
'共享运行时下命令式 API 在运行时核加载完成前(尤其模块顶层)被调用,本次返回空操作、不生效。' +
|
|
162
|
+
'请挪到组件函数体内 / useReady / useEffect / 事件回调,或改用异步版 API;' +
|
|
163
|
+
'也可在宿主用 preloadRule 预下载运行时分包以缩小窗口。'
|
|
164
|
+
)
|
|
165
|
+
}
|
|
166
|
+
return makeChainableNoop() // 返回链式安全空操作:Taro.getSystemInfoSync().x 不崩
|
|
167
|
+
},
|
|
168
|
+
})
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function install (shared, Current) {
|
|
172
|
+
// 纵深防御:即使 entry.sync 的 __syncCoreInstalled 守卫被绕过(如 install 被直接调用),
|
|
173
|
+
// 也不重复覆盖 Current.app / 占位对象。首包胜出的架构约束见 entry.sync.js 顶部说明。
|
|
174
|
+
if (shared.__appShimInstalled) return
|
|
175
|
+
shared.__appShimInstalled = true
|
|
176
|
+
|
|
177
|
+
var realApp = null
|
|
178
|
+
var queue = []
|
|
179
|
+
function whenReal (fn) { realApp ? fn(realApp) : queue.push(fn) }
|
|
180
|
+
|
|
181
|
+
var LIFECYCLES = ['onLaunch', 'onShow', 'onHide', 'onError', 'onPageNotFound', 'onUnhandledRejection']
|
|
182
|
+
var placeholderApp = { __isTaroPlaceholder: true }
|
|
183
|
+
LIFECYCLES.forEach(function (name) {
|
|
184
|
+
placeholderApp[name] = function () {
|
|
185
|
+
var args = arguments; var self = this
|
|
186
|
+
whenReal(function (real) {
|
|
187
|
+
if (typeof real[name] !== 'function') return
|
|
188
|
+
// blended/newBlended 模式下 taro-loader 生成的是无参 `app.onLaunch()`(见本文件头文档
|
|
189
|
+
// 与 taro-loader/src/app.ts)。vanilla 下它在任何页面 onLoad 之前同步执行,其真身 ONLAUNCH
|
|
190
|
+
// 内部无条件 `setRouterParams(undefined)` 设的空路由({params:undefined})必然被后续页面
|
|
191
|
+
// onLoad 的 setCurrentRouter 用真实参数覆盖,无害。但共享运行时把这次调用推迟进 queue,
|
|
192
|
+
// 与页面 mount 一起等异步核就位后 flush,且 onLaunch 排在 mount 前 → 变成"页面 onLoad 已
|
|
193
|
+
// 用真实参数设好 Current.router → onLaunch 重放用 undefined 覆盖回空 → 才 mount 渲染,
|
|
194
|
+
// useRouter() 读到 {params:undefined} → Object.keys(undefined) 崩"。
|
|
195
|
+
// 修复:仅 onLaunch 且本次确实无参(精确匹配该过场调用,不碰任何传参场景)时,重放前后
|
|
196
|
+
// 比对 Current.router——若重放把已存在的真实路由污染成 params===undefined,则还原。
|
|
197
|
+
if (name === 'onLaunch' && args.length === 0 && Current) {
|
|
198
|
+
var routerBefore = Current.router
|
|
199
|
+
real[name].apply(self, args)
|
|
200
|
+
var routerAfter = Current.router
|
|
201
|
+
if (routerBefore && routerBefore.params !== undefined &&
|
|
202
|
+
routerAfter && routerAfter.params === undefined) {
|
|
203
|
+
Current.router = routerBefore
|
|
204
|
+
}
|
|
205
|
+
return
|
|
206
|
+
}
|
|
207
|
+
real[name].apply(self, args)
|
|
208
|
+
})
|
|
209
|
+
}
|
|
210
|
+
})
|
|
211
|
+
placeholderApp.mount = function (c, id, cb) { whenReal(function (r) { r.mount(c, id, cb) }) }
|
|
212
|
+
placeholderApp.unmount = function (id, cb) { whenReal(function (r) { r.unmount(id, cb) }) }
|
|
213
|
+
placeholderApp.render = function (cb) { whenReal(function (r) { r.render && r.render(cb) }) }
|
|
214
|
+
|
|
215
|
+
Current.app = placeholderApp
|
|
216
|
+
shared.__TARO_placeholderApp = placeholderApp
|
|
217
|
+
|
|
218
|
+
// 占位 framework-runtime:mutate 填进 shared 同一对象(保引用,真身到达后原地覆盖)
|
|
219
|
+
var fwPlaceholder = shared['@tarojs/plugin-framework-react/dist/runtime']
|
|
220
|
+
if (!fwPlaceholder) { fwPlaceholder = {}; shared['@tarojs/plugin-framework-react/dist/runtime'] = fwPlaceholder }
|
|
221
|
+
fwPlaceholder.__isPlaceholder = true
|
|
222
|
+
fwPlaceholder.createReactApp = function (App, _react, _dom, config) {
|
|
223
|
+
// 业务传入的 _react/_dom 是占位,弃用;只捕获 App + config。
|
|
224
|
+
// 多业务包 last-writer 语义:后加载的业务包会覆盖 __appBootstrap 与最终 Current.app,
|
|
225
|
+
// 与 Taro 单份 runtime 内 framework `createReactApp` 无守卫赋值的原生行为一致
|
|
226
|
+
// (见 packages/taro-framework-react/src/runtime/connect.ts:434 `Current.app = appObj`)。
|
|
227
|
+
//
|
|
228
|
+
// F5 多包 App 隔离:同时记 pkgId,__activateReal 建 realApp 后按 pkgId 存进 __pkgApps 表,
|
|
229
|
+
// 供 page loader 每次 onLoad 前查回本包 App(即使 Current.app 被 last-writer 换走,
|
|
230
|
+
// 本包页面 mount 前仍能恢复到本包 App)。pkgId 由 app loader 顶部注入 shared.__currentPkgId。
|
|
231
|
+
shared.__appBootstrap = {
|
|
232
|
+
App: App,
|
|
233
|
+
config: config,
|
|
234
|
+
pkgId: shared.__currentPkgId,
|
|
235
|
+
}
|
|
236
|
+
return placeholderApp
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
// F6 native-components 占位:native-comp 产物顶层同步调 createNativeComponentConfig 建描述符传给
|
|
240
|
+
// Component()。同步核阶段无法建真描述符(reactDOM/framework 是占位),故返回占位描述符(形状完整、
|
|
241
|
+
// 生命周期延迟转发),并把 record 登记到 shared.__nativeCompConfigs;异步核到位后 replay 用真身重建。
|
|
242
|
+
shared.__nativeCompConfigs = shared.__nativeCompConfigs || []
|
|
243
|
+
fwPlaceholder.createNativeComponentConfig = function (Component, _react, _reactDom, componentConfig) {
|
|
244
|
+
var record = { Component: Component, config: componentConfig, realObj: null, pending: [] }
|
|
245
|
+
shared.__nativeCompConfigs.push(record)
|
|
246
|
+
return makePlaceholderNativeComp(record, componentConfig, Component)
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// 异步核 fill 真身后调用:用真身 framework.createNativeComponentConfig 为每个已注册的 native-comp
|
|
250
|
+
// 建真描述符,存入 record.realObj,并按调用顺序重放占位期缓存的生命周期调用(created→attached→…)。
|
|
251
|
+
// 真身 reactDOM 走 shared['react-dom'](已被 provider fill);react 走同步核的 shared.react。
|
|
252
|
+
shared.__replayNativeCompConfigs = function (realFramework) {
|
|
253
|
+
if (typeof realFramework.createNativeComponentConfig !== 'function') return
|
|
254
|
+
var records = shared.__nativeCompConfigs || []
|
|
255
|
+
records.forEach(function (record) {
|
|
256
|
+
if (record.realObj) return
|
|
257
|
+
record.realObj = realFramework.createNativeComponentConfig(
|
|
258
|
+
record.Component, shared.react, shared['react-dom'], record.config
|
|
259
|
+
)
|
|
260
|
+
var pending = record.pending; record.pending = []
|
|
261
|
+
pending.forEach(function (call) {
|
|
262
|
+
var fn = call.getReal(record.realObj)
|
|
263
|
+
if (typeof fn === 'function') fn.apply(call.self, call.args)
|
|
264
|
+
})
|
|
265
|
+
})
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
// 占位 @tarojs/taro:initPxTransform 存参;其余命令式 API 走 guardPlaceholder(未就位时告警+空操作)。
|
|
269
|
+
// 异步核激活时先置 shared.__rtActivated=true(realFlag 依据),再 fill 真身命令式 API:
|
|
270
|
+
// - 置位后 provider 自身对 taroObj 的读/写(含读 showToast 判断 initNativeApi)不会误触发保护;
|
|
271
|
+
// - 业务在异步核到位前(模块顶层/onLoad 早期)的调用此时 __rtActivated 仍为 false → 告警+空操作。
|
|
272
|
+
var taroBase = { initPxTransform: function (opts) { shared.__pxTransformOpts = opts } }
|
|
273
|
+
var taroReady = function () { return !!shared.__rtActivated }
|
|
274
|
+
shared['@tarojs/taro'] = guardPlaceholder(taroBase, 'Taro', TARO_PLACEHOLDER_WHITELIST, taroReady)
|
|
275
|
+
|
|
276
|
+
// 占位 react-dom(真身=@tarojs/react reconciler,随异步核到):同样 Proxy 守护。
|
|
277
|
+
// 正常 Taro 产物顶层不直接调 ReactDOM,仅传给 createReactApp(占位版弃用它);
|
|
278
|
+
// 守护是为兜住业务顶层直接 ReactDOM.render/createRoot 的边缘写法,给可读告警。
|
|
279
|
+
var reactDomBase = {}
|
|
280
|
+
var reactDomReady = function () { return !!shared.__rtActivated }
|
|
281
|
+
shared['react-dom'] = guardPlaceholder(reactDomBase, 'ReactDOM', null, reactDomReady)
|
|
282
|
+
|
|
283
|
+
// provider 就绪后调用:用真身 framework 重跑 createReactApp + flush 队列。
|
|
284
|
+
shared.__activateReal = function (realFramework) {
|
|
285
|
+
var boot = shared.__appBootstrap
|
|
286
|
+
if (!boot) return
|
|
287
|
+
var realAppObj = realFramework.createReactApp(
|
|
288
|
+
boot.App, shared.react, shared['react-dom'], boot.config
|
|
289
|
+
)
|
|
290
|
+
realApp = realAppObj // createReactApp 内部已 Current.app = realAppObj
|
|
291
|
+
shared.__TARO_placeholderApp = null
|
|
292
|
+
// F5 多包 App 隔离:按 pkgId 存表,供 page loader 每次 onLoad 前查回本包 App。
|
|
293
|
+
if (boot.pkgId) {
|
|
294
|
+
shared.__pkgApps = shared.__pkgApps || {}
|
|
295
|
+
shared.__pkgApps[boot.pkgId] = realAppObj
|
|
296
|
+
}
|
|
297
|
+
var q = queue; queue = []
|
|
298
|
+
q.forEach(function (fn) { fn(realApp) })
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
module.exports = { install: install }
|
|
303
|
+
// 导出纯函数供单测(不影响运行时使用;模板仍只调 install)
|
|
304
|
+
module.exports.makeChainableNoop = makeChainableNoop
|
|
305
|
+
module.exports.guardPlaceholder = guardPlaceholder
|
|
@@ -0,0 +1,144 @@
|
|
|
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
|
+
if (shared.__pxTransformOpts && typeof taro.initPxTransform === 'function') {
|
|
111
|
+
taro.initPxTransform(shared.__pxTransformOpts)
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// 建真 appObj + flush 生命周期/mount 队列。
|
|
115
|
+
// 用真身 framework 建 realAppObj,内部覆盖 Current.app = realAppObj。
|
|
116
|
+
if (typeof shared.__activateReal === 'function') {
|
|
117
|
+
shared.__activateReal(framework)
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// F6 native-components:同步核阶段 native-comp 产物顶层调的是占位 createNativeComponentConfig
|
|
121
|
+
// (app-shim 装的),返回占位描述符、生命周期(created/attached/ready…)全被缓存。此刻真身就位,
|
|
122
|
+
// 用真身 framework.createNativeComponentConfig 为每个已注册组件重建真描述符,并按序重放缓存的
|
|
123
|
+
// 生命周期调用(created 建 Entry → attached 挂载 → ready 触发)。这是 native-comp 能渲染的关键——
|
|
124
|
+
// 缺它则占位描述符只是空转发器,组件永不 mount。
|
|
125
|
+
if (typeof shared.__replayNativeCompConfigs === 'function') {
|
|
126
|
+
shared.__replayNativeCompConfigs(framework)
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// F6 兜底:flush 遗留的 native-comp mount 队列(占位+重放路径下 created 已同步建 Entry,
|
|
130
|
+
// attached 重放时 resolveApp 已能查回 App,此队列通常为空;保留作纵深防御,空队列时无副作用)。
|
|
131
|
+
if (typeof shared.__flushNativeCompQueue === 'function') {
|
|
132
|
+
shared.__flushNativeCompQueue()
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// 被同步核 require.async 加载时,把 activate 挂到全局供同步核回调。
|
|
137
|
+
// 顶层防御:即使全局未初始化(预热早于同步核)也能安全挂载。
|
|
138
|
+
(function () {
|
|
139
|
+
var GLOBAL_KEY = __TARO_SHARED_GLOBAL__
|
|
140
|
+
var g = __TARO_GLOBAL_OBJECT__[GLOBAL_KEY] || (__TARO_GLOBAL_OBJECT__[GLOBAL_KEY] = {})
|
|
141
|
+
g.__activateAsync = activate
|
|
142
|
+
})()
|
|
143
|
+
|
|
144
|
+
module.exports = { activate: activate }
|