@tarojs/plugin-framework-react 3.5.0-canary.1 → 3.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/runtime.js CHANGED
@@ -1,568 +1,669 @@
1
- import { Current, incrementId, container, SERVICE_IDENTIFIER, document, getPageInstance, injectPageInstance, safeExecute, eventHandler, addLeadingSlash } from '@tarojs/runtime';
2
- import { isFunction, isArray, EMPTY_OBJ, ensure } from '@tarojs/shared';
1
+ import { EMPTY_OBJ, isFunction, isArray, hooks, ensure } from '@tarojs/shared';
2
+ import { Current, getPageInstance, injectPageInstance, incrementId, document, safeExecute, eventHandler, addLeadingSlash } from '@tarojs/runtime';
3
3
 
4
- const HOOKS_APP_ID = 'taro-app';
5
- function isClassComponent(R, component) {
6
- const prototype = component.prototype;
7
- return (isFunction(component.render) ||
8
- !!(prototype === null || prototype === void 0 ? void 0 : prototype.isReactComponent) ||
9
- prototype instanceof R.Component // compat for some others react-like library
10
- );
11
- }
12
- function ensureIsArray(item) {
13
- if (isArray(item)) {
14
- return item;
15
- }
16
- else {
17
- return item ? [item] : [];
18
- }
19
- }
20
- /**
21
- * set writable, enumerable to true
22
- */
23
- function setDefaultDescriptor(obj) {
24
- obj.writable = true;
25
- obj.enumerable = true;
26
- return obj;
27
- }
28
- /**
29
- * 设置入口的路由参数
30
- * @param options 小程序传入的参数
31
- */
32
- function setRouterParams(options) {
33
- Current.router = Object.assign({ params: options === null || options === void 0 ? void 0 : options.query }, options);
34
- }
4
+ const reactMeta = {
5
+ PageContext: EMPTY_OBJ,
6
+ R: EMPTY_OBJ
7
+ };
35
8
 
36
- // 初始值设置为 any 主要是为了过 TS 的校验
37
- let PageContext = EMPTY_OBJ;
38
- let R$1 = EMPTY_OBJ;
39
- let h$1;
40
- let ReactDOM$1;
41
- const pageKeyId = incrementId();
42
- const hooks$1 = container.get(SERVICE_IDENTIFIER.Hooks);
43
- function setReconciler() {
44
- var _a;
45
- hooks$1.getLifecycle = function (instance, lifecycle) {
46
- lifecycle = lifecycle.replace(/^on(Show|Hide)$/, 'componentDid$1');
47
- return instance[lifecycle];
48
- };
49
- (_a = hooks$1.modifyMpEventImpls) === null || _a === void 0 ? void 0 : _a.push(function (event) {
50
- event.type = event.type.replace(/-/g, '');
51
- });
52
- hooks$1.batchedEventUpdates = function (cb) {
53
- ReactDOM$1.unstable_batchedUpdates(cb);
54
- };
55
- hooks$1.mergePageInstance = function (prev, next) {
56
- if (!prev || !next)
57
- return;
58
- // 子组件使用 lifecycle hooks 注册了生命周期后,会存在 prev,里面是注册的生命周期回调。
59
- // prev 使用 Object.create(null) 创建,H5 的 fast-refresh 可能也会导致存在 prev,要排除这些意外产生的 prev
60
- if ('constructor' in prev)
61
- return;
62
- Object.keys(prev).forEach(item => {
63
- const prevList = prev[item];
64
- const nextList = ensureIsArray(next[item]);
65
- next[item] = nextList.concat(prevList);
66
- });
67
- };
68
- if (process.env.TARO_ENV === 'h5') {
69
- hooks$1.createPullDownComponent = (el, _, R, customWrapper) => {
70
- const isReactComponent = isClassComponent(R, el);
71
- return R.forwardRef((props, ref) => {
72
- const newProps = Object.assign({}, props);
73
- const refs = isReactComponent ? { ref: ref } : {
74
- forwardedRef: ref,
75
- // 兼容 react-redux 7.20.1+
76
- reactReduxForwardedRef: ref
77
- };
78
- return h$1(customWrapper || 'taro-pull-to-refresh', null, h$1(el, Object.assign(Object.assign({}, newProps), refs)));
79
- });
80
- };
81
- hooks$1.getDOMNode = inst => {
82
- return ReactDOM$1.findDOMNode(inst);
83
- };
84
- }
85
- }
86
- function connectReactPage(R, id) {
87
- return (Page) => {
88
- // eslint-disable-next-line dot-notation
89
- const isReactComponent = isClassComponent(R, Page);
90
- const inject = (node) => node && injectPageInstance(node, id);
91
- const refs = isReactComponent ? { ref: inject } : {
92
- forwardedRef: inject,
93
- // 兼容 react-redux 7.20.1+
94
- reactReduxForwardedRef: inject
95
- };
96
- if (PageContext === EMPTY_OBJ) {
97
- PageContext = R.createContext('');
98
- }
99
- return class PageWrapper extends R.Component {
100
- constructor() {
101
- super(...arguments);
102
- this.state = {
103
- hasError: false
104
- };
105
- }
106
- static getDerivedStateFromError(error) {
107
- process.env.NODE_ENV !== 'production' && console.warn(error);
108
- return { hasError: true };
109
- }
110
- // React 16 uncaught error 会导致整个应用 crash,
111
- // 目前把错误缩小到页面
112
- componentDidCatch(error, info) {
113
- if (process.env.NODE_ENV !== 'production') {
114
- console.warn(error);
115
- console.error(info.componentStack);
116
- }
117
- }
118
- render() {
119
- const children = this.state.hasError
120
- ? []
121
- : h$1(PageContext.Provider, { value: id }, h$1(Page, Object.assign(Object.assign({}, this.props), refs)));
122
- if (process.env.TARO_ENV === 'h5') {
123
- return h$1('div', { id, className: 'taro_page' }, children);
124
- }
125
- else {
126
- return h$1('root', { id }, children);
127
- }
128
- }
129
- };
130
- };
131
- }
132
- /**
133
- * 桥接小程序 App 构造器和 React 渲染流程
134
- * @param App 用户编写的入口组件
135
- * @param react 框架
136
- * @param dom 框架渲染器
137
- * @param config 入口组件配置 app.config.js 的内容
138
- * @returns 传递给 App 构造器的对象 obj :App(obj)
139
- */
140
- function createReactApp(App, react, dom, config) {
141
- var _a;
142
- if (process.env.NODE_ENV !== 'production') {
143
- ensure(!!dom, '构建 React/Nerv 项目请把 process.env.FRAMEWORK 设置为 \'react\'/\'nerv\' ');
144
- }
145
- R$1 = react;
146
- h$1 = react.createElement;
147
- ReactDOM$1 = dom;
148
- const appInstanceRef = react.createRef();
149
- const isReactComponent = isClassComponent(R$1, App);
150
- let appWrapper;
151
- setReconciler();
152
- function getAppInstance() {
153
- return appInstanceRef.current;
154
- }
155
- class AppWrapper extends R$1.Component {
156
- constructor() {
157
- super(...arguments);
158
- // run createElement() inside the render function to make sure that owner is right
159
- this.pages = [];
160
- this.elements = [];
161
- }
162
- mount(pageComponent, id, cb) {
163
- const pageWrapper = connectReactPage(R$1, id)(pageComponent);
164
- const key = id + pageKeyId();
165
- const page = () => h$1(pageWrapper, { key, tid: id });
166
- this.pages.push(page);
167
- this.forceUpdate(cb);
168
- }
169
- unmount(id, cb) {
170
- const elements = this.elements;
171
- const idx = elements.findIndex(item => item.props.tid === id);
172
- elements.splice(idx, 1);
173
- this.forceUpdate(cb);
174
- }
175
- render() {
176
- const { pages, elements } = this;
177
- while (pages.length > 0) {
178
- const page = pages.pop();
179
- elements.push(page());
180
- }
181
- let props = null;
182
- if (isReactComponent) {
183
- props = { ref: appInstanceRef };
184
- }
185
- return h$1(App, props, process.env.TARO_ENV === 'h5' ? h$1('div', null, elements.slice()) : elements.slice());
186
- }
187
- }
188
- if (process.env.TARO_ENV !== 'h5') {
189
- appWrapper = (_a = ReactDOM$1.render) === null || _a === void 0 ? void 0 : _a.call(ReactDOM$1, h$1(AppWrapper), document.getElementById('app'));
190
- }
191
- const [ONLAUNCH, ONSHOW, ONHIDE] = hooks$1.getMiniLifecycleImpl().app;
192
- const appObj = Object.create({
193
- render(cb) {
194
- appWrapper.forceUpdate(cb);
195
- },
196
- mount(component, id, cb) {
197
- appWrapper.mount(component, id, cb);
198
- },
199
- unmount(id, cb) {
200
- appWrapper.unmount(id, cb);
201
- }
202
- }, {
203
- config: setDefaultDescriptor({
204
- configurable: true,
205
- value: config
206
- }),
207
- [ONLAUNCH]: setDefaultDescriptor({
208
- value(options) {
209
- var _a, _b;
210
- setRouterParams(options);
211
- if (process.env.TARO_ENV === 'h5') {
212
- // 由于 H5 路由初始化的时候会清除 app 下的 dom 元素,所以需要在路由初始化后执行 render
213
- appWrapper = (_a = ReactDOM$1.render) === null || _a === void 0 ? void 0 : _a.call(ReactDOM$1, h$1(AppWrapper), document.getElementById((config === null || config === void 0 ? void 0 : config.appId) || 'app'));
214
- }
215
- // 用户编写的入口组件实例
216
- const app = getAppInstance();
217
- this.$app = app;
218
- if (app) {
219
- // 把 App Class 上挂载的额外属性同步到全局 app 对象中
220
- if (app.taroGlobalData) {
221
- const globalData = app.taroGlobalData;
222
- const keys = Object.keys(globalData);
223
- const descriptors = Object.getOwnPropertyDescriptors(globalData);
224
- keys.forEach(key => {
225
- Object.defineProperty(this, key, {
226
- configurable: true,
227
- enumerable: true,
228
- get() {
229
- return globalData[key];
230
- },
231
- set(value) {
232
- globalData[key] = value;
233
- }
234
- });
235
- });
236
- Object.defineProperties(this, descriptors);
237
- }
238
- (_b = app.onLaunch) === null || _b === void 0 ? void 0 : _b.call(app, options);
239
- }
240
- }
241
- }),
242
- [ONSHOW]: setDefaultDescriptor({
243
- value(options) {
244
- var _a;
245
- setRouterParams(options);
246
- /**
247
- * trigger lifecycle
248
- */
249
- const app = getAppInstance();
250
- // class component, componentDidShow
251
- (_a = app === null || app === void 0 ? void 0 : app.componentDidShow) === null || _a === void 0 ? void 0 : _a.call(app, options);
252
- // functional component, useDidShow
253
- triggerAppHook('onShow', options);
254
- }
255
- }),
256
- [ONHIDE]: setDefaultDescriptor({
257
- value() {
258
- var _a;
259
- /**
260
- * trigger lifecycle
261
- */
262
- const app = getAppInstance();
263
- // class component, componentDidHide
264
- (_a = app === null || app === void 0 ? void 0 : app.componentDidHide) === null || _a === void 0 ? void 0 : _a.call(app);
265
- // functional component, useDidHide
266
- triggerAppHook('onHide');
267
- }
268
- }),
269
- onPageNotFound: setDefaultDescriptor({
270
- value(res) {
271
- var _a;
272
- const app = getAppInstance();
273
- (_a = app === null || app === void 0 ? void 0 : app.onPageNotFound) === null || _a === void 0 ? void 0 : _a.call(app, res);
274
- }
275
- })
276
- });
277
- function triggerAppHook(lifecycle, ...option) {
278
- const instance = getPageInstance(HOOKS_APP_ID);
279
- if (instance) {
280
- const app = getAppInstance();
281
- const func = hooks$1.getLifecycle(instance, lifecycle);
282
- if (Array.isArray(func)) {
283
- func.forEach(cb => cb.apply(app, option));
284
- }
285
- }
286
- }
287
- Current.app = appObj;
288
- return appObj;
9
+ const HOOKS_APP_ID = 'taro-app';
10
+ function isClassComponent(R, component) {
11
+ var _a;
12
+ const prototype = component.prototype;
13
+ // For React Redux
14
+ if ((_a = component.displayName) === null || _a === void 0 ? void 0 : _a.includes('Connect'))
15
+ return false;
16
+ return (isFunction(component.render) ||
17
+ !!(prototype === null || prototype === void 0 ? void 0 : prototype.isReactComponent) ||
18
+ prototype instanceof R.Component // compat for some others react-like library
19
+ );
20
+ }
21
+ function ensureIsArray(item) {
22
+ if (isArray(item)) {
23
+ return item;
24
+ }
25
+ else {
26
+ return item ? [item] : [];
27
+ }
28
+ }
29
+ /**
30
+ * set writable, enumerable to true
31
+ */
32
+ function setDefaultDescriptor(obj) {
33
+ obj.writable = true;
34
+ obj.enumerable = true;
35
+ return obj;
36
+ }
37
+ /**
38
+ * 设置入口的路由参数
39
+ * @param options 小程序传入的参数
40
+ */
41
+ function setRouterParams(options) {
42
+ Current.router = Object.assign({ params: options === null || options === void 0 ? void 0 : options.query }, options);
289
43
  }
290
44
 
291
- const taroHooks = (lifecycle) => {
292
- return (fn) => {
293
- const id = R$1.useContext(PageContext) || HOOKS_APP_ID;
294
- // hold fn ref and keep up to date
295
- const fnRef = R$1.useRef(fn);
296
- if (fnRef.current !== fn)
297
- fnRef.current = fn;
298
- R$1.useLayoutEffect(() => {
299
- let inst = getPageInstance(id);
300
- let first = false;
301
- if (inst == null) {
302
- first = true;
303
- inst = Object.create(null);
304
- }
305
- inst = inst;
306
- // callback is immutable but inner function is up to date
307
- const callback = (...args) => fnRef.current(...args);
308
- if (isFunction(inst[lifecycle])) {
309
- inst[lifecycle] = [inst[lifecycle], callback];
310
- }
311
- else {
312
- inst[lifecycle] = [
313
- ...(inst[lifecycle] || []),
314
- callback
315
- ];
316
- }
317
- if (first) {
318
- injectPageInstance(inst, id);
319
- }
320
- return () => {
321
- const inst = getPageInstance(id);
322
- const list = inst[lifecycle];
323
- if (list === callback) {
324
- inst[lifecycle] = undefined;
325
- }
326
- else if (isArray(list)) {
327
- inst[lifecycle] = list.filter(item => item !== callback);
328
- }
329
- };
330
- }, []);
331
- };
332
- };
333
- const useDidShow = taroHooks('componentDidShow');
334
- const useDidHide = taroHooks('componentDidHide');
335
- const usePullDownRefresh = taroHooks('onPullDownRefresh');
336
- const useReachBottom = taroHooks('onReachBottom');
337
- const usePageScroll = taroHooks('onPageScroll');
338
- const useResize = taroHooks('onResize');
339
- const useShareAppMessage = taroHooks('onShareAppMessage');
340
- const useTabItemTap = taroHooks('onTabItemTap');
341
- const useTitleClick = taroHooks('onTitleClick');
342
- const useOptionMenuClick = taroHooks('onOptionMenuClick');
343
- const usePullIntercept = taroHooks('onPullIntercept');
344
- const useShareTimeline = taroHooks('onShareTimeline');
345
- const useAddToFavorites = taroHooks('onAddToFavorites');
346
- const useReady = taroHooks('onReady');
347
- const useRouter = (dynamic = false) => {
348
- return dynamic ? Current.router : R$1.useMemo(() => Current.router, []);
349
- };
45
+ const createTaroHook = (lifecycle) => {
46
+ return (fn) => {
47
+ const { R: React, PageContext } = reactMeta;
48
+ const id = React.useContext(PageContext) || HOOKS_APP_ID;
49
+ // hold fn ref and keep up to date
50
+ const fnRef = React.useRef(fn);
51
+ if (fnRef.current !== fn)
52
+ fnRef.current = fn;
53
+ React.useLayoutEffect(() => {
54
+ let inst = getPageInstance(id);
55
+ let first = false;
56
+ if (inst == null) {
57
+ first = true;
58
+ inst = Object.create(null);
59
+ }
60
+ inst = inst;
61
+ // callback is immutable but inner function is up to date
62
+ const callback = (...args) => fnRef.current(...args);
63
+ if (isFunction(inst[lifecycle])) {
64
+ inst[lifecycle] = [inst[lifecycle], callback];
65
+ }
66
+ else {
67
+ inst[lifecycle] = [
68
+ ...(inst[lifecycle] || []),
69
+ callback
70
+ ];
71
+ }
72
+ if (first) {
73
+ injectPageInstance(inst, id);
74
+ }
75
+ return () => {
76
+ const inst = getPageInstance(id);
77
+ const list = inst[lifecycle];
78
+ if (list === callback) {
79
+ inst[lifecycle] = undefined;
80
+ }
81
+ else if (isArray(list)) {
82
+ inst[lifecycle] = list.filter(item => item !== callback);
83
+ }
84
+ };
85
+ }, []);
86
+ };
87
+ };
88
+ /** LifeCycle */
89
+ const useDidHide = createTaroHook('componentDidHide');
90
+ const useDidShow = createTaroHook('componentDidShow');
91
+ /** App */
92
+ const useError = createTaroHook('onError');
93
+ const useLaunch = createTaroHook('onLaunch');
94
+ const usePageNotFound = createTaroHook('onPageNotFound');
95
+ /** Page */
96
+ const useLoad = createTaroHook('onLoad');
97
+ const usePageScroll = createTaroHook('onPageScroll');
98
+ const usePullDownRefresh = createTaroHook('onPullDownRefresh');
99
+ const usePullIntercept = createTaroHook('onPullIntercept');
100
+ const useReachBottom = createTaroHook('onReachBottom');
101
+ const useResize = createTaroHook('onResize');
102
+ const useUnload = createTaroHook('onUnload');
103
+ /** Mini-Program */
104
+ const useAddToFavorites = createTaroHook('onAddToFavorites');
105
+ const useOptionMenuClick = createTaroHook('onOptionMenuClick');
106
+ const useSaveExitState = createTaroHook('onSaveExitState');
107
+ const useShareAppMessage = createTaroHook('onShareAppMessage');
108
+ const useShareTimeline = createTaroHook('onShareTimeline');
109
+ const useTitleClick = createTaroHook('onTitleClick');
110
+ /** Router */
111
+ const useReady = createTaroHook('onReady');
112
+ const useRouter = (dynamic = false) => {
113
+ const React = reactMeta.R;
114
+ return dynamic ? Current.router : React.useMemo(() => Current.router, []);
115
+ };
116
+ const useTabItemTap = createTaroHook('onTabItemTap');
350
117
  const useScope = () => undefined;
351
118
 
352
- var taroHooks$1 = /*#__PURE__*/Object.freeze({
119
+ var taroHooks = /*#__PURE__*/Object.freeze({
353
120
  __proto__: null,
354
- useDidShow: useDidShow,
355
121
  useDidHide: useDidHide,
122
+ useDidShow: useDidShow,
123
+ useError: useError,
124
+ useLaunch: useLaunch,
125
+ usePageNotFound: usePageNotFound,
126
+ useLoad: useLoad,
127
+ usePageScroll: usePageScroll,
356
128
  usePullDownRefresh: usePullDownRefresh,
129
+ usePullIntercept: usePullIntercept,
357
130
  useReachBottom: useReachBottom,
358
- usePageScroll: usePageScroll,
359
131
  useResize: useResize,
360
- useShareAppMessage: useShareAppMessage,
361
- useTabItemTap: useTabItemTap,
362
- useTitleClick: useTitleClick,
132
+ useUnload: useUnload,
133
+ useAddToFavorites: useAddToFavorites,
363
134
  useOptionMenuClick: useOptionMenuClick,
364
- usePullIntercept: usePullIntercept,
135
+ useSaveExitState: useSaveExitState,
136
+ useShareAppMessage: useShareAppMessage,
365
137
  useShareTimeline: useShareTimeline,
366
- useAddToFavorites: useAddToFavorites,
138
+ useTitleClick: useTitleClick,
367
139
  useReady: useReady,
368
140
  useRouter: useRouter,
141
+ useTabItemTap: useTabItemTap,
369
142
  useScope: useScope
370
143
  });
371
144
 
372
- const getNativeCompId = incrementId();
373
- let R;
374
- let h;
375
- let ReactDOM;
376
- function initNativeComponentEntry(R, ReactDOM) {
377
- class NativeComponentWrapper extends R.Component {
378
- constructor() {
379
- super(...arguments);
380
- this.root = R.createRef();
381
- this.ctx = this.props.getCtx();
382
- }
383
- componentDidMount() {
384
- this.ctx.component = this;
385
- const rootElement = this.root.current;
386
- rootElement.ctx = this.ctx;
387
- rootElement.performUpdate(true);
388
- }
389
- render() {
390
- return (h('root', {
391
- ref: this.root
392
- }, this.props.renderComponent(this.ctx)));
393
- }
394
- }
395
- class Entry extends R.Component {
396
- constructor() {
397
- super(...arguments);
398
- this.state = {
399
- components: []
400
- };
401
- }
402
- componentDidMount() {
403
- Current.app = this;
404
- }
405
- mount(Component, compId, getCtx) {
406
- const isReactComponent = isClassComponent(R, Component);
407
- const inject = (node) => node && injectPageInstance(node, compId);
408
- const refs = isReactComponent ? { ref: inject } : {
409
- forwardedRef: inject,
410
- reactReduxForwardedRef: inject
411
- };
412
- const item = {
413
- compId,
414
- element: h(NativeComponentWrapper, {
415
- key: compId,
416
- getCtx,
417
- renderComponent(ctx) {
418
- return h(Component, Object.assign(Object.assign({}, (ctx.data || (ctx.data = {})).props), refs));
419
- }
420
- })
421
- };
422
- this.setState({
423
- components: [...this.state.components, item]
424
- });
425
- }
426
- unmount(compId) {
427
- const components = this.state.components;
428
- const index = components.findIndex(item => item.compId === compId);
429
- const next = [...components.slice(0, index), ...components.slice(index + 1)];
430
- this.setState({
431
- components: next
432
- });
433
- }
434
- render() {
435
- const components = this.state.components;
436
- return (components.map(({ element }) => element));
437
- }
438
- }
439
- setReconciler();
440
- const app = document.getElementById('app');
441
- ReactDOM.render(h(Entry, {}), app);
442
- }
443
- function createNativeComponentConfig(Component, react, reactdom, componentConfig) {
444
- R = react;
445
- h = react.createElement;
446
- ReactDOM = reactdom;
447
- setReconciler();
448
- const componentObj = {
449
- options: componentConfig,
450
- properties: {
451
- props: {
452
- type: null,
453
- value: null,
454
- observer(_newVal, oldVal) {
455
- oldVal && this.component.forceUpdate();
456
- }
457
- }
458
- },
459
- created() {
460
- if (!Current.app) {
461
- initNativeComponentEntry(R, ReactDOM);
462
- }
463
- },
464
- attached() {
465
- setCurrent();
466
- this.compId = getNativeCompId();
467
- this.config = componentConfig;
468
- Current.app.mount(Component, this.compId, () => this);
469
- },
470
- ready() {
471
- safeExecute(this.compId, 'onReady');
472
- },
473
- detached() {
474
- Current.app.unmount(this.compId);
475
- },
476
- pageLifetimes: {
477
- show(options) {
478
- safeExecute(this.compId, 'onShow', options);
479
- },
480
- hide() {
481
- safeExecute(this.compId, 'onHide');
482
- }
483
- },
484
- methods: {
485
- eh: eventHandler
486
- }
487
- };
488
- function setCurrent() {
489
- const pages = getCurrentPages();
490
- const currentPage = pages[pages.length - 1];
491
- if (Current.page === currentPage)
492
- return;
493
- Current.page = currentPage;
494
- const route = currentPage.route || currentPage.__route__;
495
- const router = {
496
- params: currentPage.options || {},
497
- path: addLeadingSlash(route),
498
- onReady: '',
499
- onHide: '',
500
- onShow: ''
501
- };
502
- Current.router = router;
503
- if (!currentPage.options) {
504
- // 例如在微信小程序中,页面 options 的设置时机比组件 attached 慢
505
- Object.defineProperty(currentPage, 'options', {
506
- enumerable: true,
507
- configurable: true,
508
- get() {
509
- return this._optionsValue;
510
- },
511
- set(value) {
512
- router.params = value;
513
- this._optionsValue = value;
514
- }
515
- });
516
- }
517
- }
518
- return componentObj;
145
+ let h$1;
146
+ let ReactDOM$1;
147
+ let Fragment;
148
+ const pageKeyId = incrementId();
149
+ function setReconciler(ReactDOM) {
150
+ hooks.tap('getLifecycle', function (instance, lifecycle) {
151
+ lifecycle = lifecycle.replace(/^on(Show|Hide)$/, 'componentDid$1');
152
+ return instance[lifecycle];
153
+ });
154
+ hooks.tap('modifyMpEvent', function (event) {
155
+ event.type = event.type.replace(/-/g, '');
156
+ });
157
+ hooks.tap('batchedEventUpdates', function (cb) {
158
+ ReactDOM.unstable_batchedUpdates(cb);
159
+ });
160
+ hooks.tap('mergePageInstance', function (prev, next) {
161
+ if (!prev || !next)
162
+ return;
163
+ // 子组件使用 lifecycle hooks 注册了生命周期后,会存在 prev,里面是注册的生命周期回调。
164
+ // prev 使用 Object.create(null) 创建,H5 的 fast-refresh 可能也会导致存在 prev,要排除这些意外产生的 prev
165
+ if ('constructor' in prev)
166
+ return;
167
+ Object.keys(prev).forEach(item => {
168
+ const prevList = prev[item];
169
+ const nextList = ensureIsArray(next[item]);
170
+ next[item] = nextList.concat(prevList);
171
+ });
172
+ });
173
+ if (process.env.TARO_ENV === 'h5') {
174
+ hooks.tap('createPullDownComponent', (el, _, R, customWrapper) => {
175
+ const isReactComponent = isClassComponent(R, el);
176
+ return R.forwardRef((props, ref) => {
177
+ const newProps = Object.assign({}, props);
178
+ const refs = isReactComponent ? { ref: ref } : {
179
+ forwardedRef: ref,
180
+ // 兼容 react-redux 7.20.1+
181
+ reactReduxForwardedRef: ref
182
+ };
183
+ return h$1(customWrapper || 'taro-pull-to-refresh', null, h$1(el, Object.assign(Object.assign({}, newProps), refs)));
184
+ });
185
+ });
186
+ hooks.tap('getDOMNode', inst => {
187
+ return ReactDOM.findDOMNode(inst);
188
+ });
189
+ }
190
+ }
191
+ function connectReactPage(R, id) {
192
+ return (Page) => {
193
+ // eslint-disable-next-line dot-notation
194
+ const isReactComponent = isClassComponent(R, Page);
195
+ const inject = (node) => node && injectPageInstance(node, id);
196
+ const refs = isReactComponent ? { ref: inject } : {
197
+ forwardedRef: inject,
198
+ // 兼容 react-redux 7.20.1+
199
+ reactReduxForwardedRef: inject
200
+ };
201
+ if (reactMeta.PageContext === EMPTY_OBJ) {
202
+ reactMeta.PageContext = R.createContext('');
203
+ }
204
+ return class PageWrapper extends R.Component {
205
+ constructor() {
206
+ super(...arguments);
207
+ this.state = {
208
+ hasError: false
209
+ };
210
+ }
211
+ static getDerivedStateFromError(error) {
212
+ var _a, _b;
213
+ (_b = (_a = Current.app) === null || _a === void 0 ? void 0 : _a.onError) === null || _b === void 0 ? void 0 : _b.call(_a, error.message + error.stack);
214
+ return { hasError: true };
215
+ }
216
+ // React 16 uncaught error 会导致整个应用 crash,
217
+ // 目前把错误缩小到页面
218
+ componentDidCatch(error, info) {
219
+ if (process.env.NODE_ENV !== 'production') {
220
+ console.warn(error);
221
+ console.error(info.componentStack);
222
+ }
223
+ }
224
+ render() {
225
+ const children = this.state.hasError
226
+ ? []
227
+ : h$1(reactMeta.PageContext.Provider, { value: id }, h$1(Page, Object.assign(Object.assign({}, this.props), refs)));
228
+ if (process.env.TARO_ENV === 'h5') {
229
+ return h$1('div', { id, className: 'taro_page' }, children);
230
+ }
231
+ else {
232
+ return h$1('root', { id }, children);
233
+ }
234
+ }
235
+ };
236
+ };
237
+ }
238
+ /**
239
+ * 桥接小程序 App 构造器和 React 渲染流程
240
+ * @param App 用户编写的入口组件
241
+ * @param react 框架
242
+ * @param dom 框架渲染器
243
+ * @param config 入口组件配置 app.config.js 的内容
244
+ * @returns 传递给 App 构造器的对象 obj :App(obj)
245
+ */
246
+ function createReactApp(App, react, dom, config) {
247
+ if (process.env.NODE_ENV !== 'production') {
248
+ ensure(!!dom, '构建 React/Nerv 项目请把 process.env.FRAMEWORK 设置为 \'react\'/\'nerv\' ');
249
+ }
250
+ reactMeta.R = react;
251
+ h$1 = react.createElement;
252
+ ReactDOM$1 = dom;
253
+ Fragment = react.Fragment;
254
+ const appInstanceRef = react.createRef();
255
+ const isReactComponent = isClassComponent(react, App);
256
+ let appWrapper;
257
+ setReconciler(ReactDOM$1);
258
+ function getAppInstance() {
259
+ return appInstanceRef.current;
260
+ }
261
+ function renderReactRoot() {
262
+ var _a, _b;
263
+ let appId = 'app';
264
+ if (process.env.TARO_ENV === 'h5') {
265
+ appId = (config === null || config === void 0 ? void 0 : config.appId) || appId;
266
+ }
267
+ const container = document.getElementById(appId);
268
+ if ((react.version || '').startsWith('18')) {
269
+ const root = ReactDOM$1.createRoot(container);
270
+ (_a = root.render) === null || _a === void 0 ? void 0 : _a.call(root, h$1(AppWrapper));
271
+ }
272
+ else {
273
+ (_b = ReactDOM$1.render) === null || _b === void 0 ? void 0 : _b.call(ReactDOM$1, h$1(AppWrapper), container);
274
+ }
275
+ }
276
+ class AppWrapper extends react.Component {
277
+ constructor(props) {
278
+ super(props);
279
+ // run createElement() inside the render function to make sure that owner is right
280
+ this.pages = [];
281
+ this.elements = [];
282
+ appWrapper = this;
283
+ }
284
+ mount(pageComponent, id, cb) {
285
+ const pageWrapper = connectReactPage(react, id)(pageComponent);
286
+ const key = id + pageKeyId();
287
+ const page = () => h$1(pageWrapper, { key, tid: id });
288
+ this.pages.push(page);
289
+ this.forceUpdate(cb);
290
+ }
291
+ unmount(id, cb) {
292
+ const elements = this.elements;
293
+ const idx = elements.findIndex(item => item.props.tid === id);
294
+ elements.splice(idx, 1);
295
+ this.forceUpdate(cb);
296
+ }
297
+ render() {
298
+ const { pages, elements } = this;
299
+ while (pages.length > 0) {
300
+ const page = pages.pop();
301
+ elements.push(page());
302
+ }
303
+ let props = null;
304
+ if (isReactComponent) {
305
+ props = { ref: appInstanceRef };
306
+ }
307
+ return h$1(App, props, process.env.TARO_ENV === 'h5' ? h$1(Fragment !== null && Fragment !== void 0 ? Fragment : 'div', null, elements.slice()) : elements.slice());
308
+ }
309
+ }
310
+ if (process.env.TARO_ENV !== 'h5') {
311
+ renderReactRoot();
312
+ }
313
+ const [ONLAUNCH, ONSHOW, ONHIDE] = hooks.call('getMiniLifecycleImpl').app;
314
+ const appObj = Object.create({
315
+ render(cb) {
316
+ appWrapper.forceUpdate(cb);
317
+ },
318
+ mount(component, id, cb) {
319
+ appWrapper.mount(component, id, cb);
320
+ },
321
+ unmount(id, cb) {
322
+ appWrapper.unmount(id, cb);
323
+ }
324
+ }, {
325
+ config: setDefaultDescriptor({
326
+ configurable: true,
327
+ value: config
328
+ }),
329
+ [ONLAUNCH]: setDefaultDescriptor({
330
+ value(options) {
331
+ var _a;
332
+ setRouterParams(options);
333
+ if (process.env.TARO_ENV === 'h5') {
334
+ // 由于 H5 路由初始化的时候会清除 app 下的 dom 元素,所以需要在路由初始化后执行 render
335
+ renderReactRoot();
336
+ }
337
+ // 用户编写的入口组件实例
338
+ const app = getAppInstance();
339
+ this.$app = app;
340
+ if (app) {
341
+ // 把 App Class 上挂载的额外属性同步到全局 app 对象中
342
+ if (app.taroGlobalData) {
343
+ const globalData = app.taroGlobalData;
344
+ const keys = Object.keys(globalData);
345
+ const descriptors = Object.getOwnPropertyDescriptors(globalData);
346
+ keys.forEach(key => {
347
+ Object.defineProperty(this, key, {
348
+ configurable: true,
349
+ enumerable: true,
350
+ get() {
351
+ return globalData[key];
352
+ },
353
+ set(value) {
354
+ globalData[key] = value;
355
+ }
356
+ });
357
+ });
358
+ Object.defineProperties(this, descriptors);
359
+ }
360
+ (_a = app.onLaunch) === null || _a === void 0 ? void 0 : _a.call(app, options);
361
+ }
362
+ triggerAppHook('onLaunch', options);
363
+ }
364
+ }),
365
+ [ONSHOW]: setDefaultDescriptor({
366
+ value(options) {
367
+ var _a;
368
+ setRouterParams(options);
369
+ /**
370
+ * trigger lifecycle
371
+ */
372
+ const app = getAppInstance();
373
+ // class component, componentDidShow
374
+ (_a = app === null || app === void 0 ? void 0 : app.componentDidShow) === null || _a === void 0 ? void 0 : _a.call(app, options);
375
+ // functional component, useDidShow
376
+ triggerAppHook('onShow', options);
377
+ }
378
+ }),
379
+ [ONHIDE]: setDefaultDescriptor({
380
+ value() {
381
+ var _a;
382
+ /**
383
+ * trigger lifecycle
384
+ */
385
+ const app = getAppInstance();
386
+ // class component, componentDidHide
387
+ (_a = app === null || app === void 0 ? void 0 : app.componentDidHide) === null || _a === void 0 ? void 0 : _a.call(app);
388
+ // functional component, useDidHide
389
+ triggerAppHook('onHide');
390
+ }
391
+ }),
392
+ onError: setDefaultDescriptor({
393
+ value(error) {
394
+ var _a;
395
+ const app = getAppInstance();
396
+ (_a = app === null || app === void 0 ? void 0 : app.onError) === null || _a === void 0 ? void 0 : _a.call(app, error);
397
+ triggerAppHook('onError', error);
398
+ if (process.env.NODE_ENV !== 'production' && (error === null || error === void 0 ? void 0 : error.includes('Minified React error'))) {
399
+ console.warn('React 出现报错,请打开编译配置 mini.debugReact 查看报错详情:https://docs.taro.zone/docs/config-detail#minidebugreact');
400
+ }
401
+ }
402
+ }),
403
+ onPageNotFound: setDefaultDescriptor({
404
+ value(res) {
405
+ var _a;
406
+ const app = getAppInstance();
407
+ (_a = app === null || app === void 0 ? void 0 : app.onPageNotFound) === null || _a === void 0 ? void 0 : _a.call(app, res);
408
+ triggerAppHook('onPageNotFound', res);
409
+ }
410
+ })
411
+ });
412
+ function triggerAppHook(lifecycle, ...option) {
413
+ const instance = getPageInstance(HOOKS_APP_ID);
414
+ if (instance) {
415
+ const app = getAppInstance();
416
+ const func = hooks.call('getLifecycle', instance, lifecycle);
417
+ if (Array.isArray(func)) {
418
+ func.forEach(cb => cb.apply(app, option));
419
+ }
420
+ }
421
+ }
422
+ Current.app = appObj;
423
+ return appObj;
424
+ }
425
+
426
+ const getNativeCompId = incrementId();
427
+ let h;
428
+ let ReactDOM;
429
+ function initNativeComponentEntry(R, ReactDOM) {
430
+ class NativeComponentWrapper extends R.Component {
431
+ constructor() {
432
+ super(...arguments);
433
+ this.root = R.createRef();
434
+ this.ctx = this.props.getCtx();
435
+ }
436
+ componentDidMount() {
437
+ this.ctx.component = this;
438
+ const rootElement = this.root.current;
439
+ rootElement.ctx = this.ctx;
440
+ rootElement.performUpdate(true);
441
+ }
442
+ render() {
443
+ return (h('root', {
444
+ ref: this.root
445
+ }, this.props.renderComponent(this.ctx)));
446
+ }
447
+ }
448
+ class Entry extends R.Component {
449
+ constructor() {
450
+ super(...arguments);
451
+ this.state = {
452
+ components: []
453
+ };
454
+ }
455
+ componentDidMount() {
456
+ Current.app = this;
457
+ }
458
+ mount(Component, compId, getCtx) {
459
+ const isReactComponent = isClassComponent(R, Component);
460
+ const inject = (node) => node && injectPageInstance(node, compId);
461
+ const refs = isReactComponent ? { ref: inject } : {
462
+ forwardedRef: inject,
463
+ reactReduxForwardedRef: inject
464
+ };
465
+ if (reactMeta.PageContext === EMPTY_OBJ) {
466
+ reactMeta.PageContext = R.createContext('');
467
+ }
468
+ const item = {
469
+ compId,
470
+ element: h(NativeComponentWrapper, {
471
+ key: compId,
472
+ getCtx,
473
+ renderComponent(ctx) {
474
+ return h(reactMeta.PageContext.Provider, { value: compId }, h(Component, Object.assign(Object.assign(Object.assign({}, (ctx.data || (ctx.data = {})).props), refs), { $scope: ctx })));
475
+ }
476
+ })
477
+ };
478
+ this.setState({
479
+ components: [...this.state.components, item]
480
+ });
481
+ }
482
+ unmount(compId) {
483
+ const components = this.state.components;
484
+ const index = components.findIndex(item => item.compId === compId);
485
+ const next = [...components.slice(0, index), ...components.slice(index + 1)];
486
+ this.setState({
487
+ components: next
488
+ });
489
+ }
490
+ render() {
491
+ const components = this.state.components;
492
+ return (components.map(({ element }) => element));
493
+ }
494
+ }
495
+ setReconciler(ReactDOM);
496
+ const app = document.getElementById('app');
497
+ ReactDOM.render(h(Entry, {}), app);
498
+ }
499
+ function createNativeComponentConfig(Component, react, reactdom, componentConfig) {
500
+ var _a, _b;
501
+ reactMeta.R = react;
502
+ h = react.createElement;
503
+ ReactDOM = reactdom;
504
+ setReconciler(ReactDOM);
505
+ const componentObj = {
506
+ options: componentConfig,
507
+ properties: {
508
+ props: {
509
+ type: null,
510
+ value: null,
511
+ observer(_newVal, oldVal) {
512
+ oldVal && this.component.forceUpdate();
513
+ }
514
+ }
515
+ },
516
+ created() {
517
+ if (!Current.app) {
518
+ initNativeComponentEntry(react, ReactDOM);
519
+ }
520
+ },
521
+ attached() {
522
+ const compId = this.compId = getNativeCompId();
523
+ setCurrent(compId);
524
+ this.config = componentConfig;
525
+ Current.app.mount(Component, compId, () => this);
526
+ },
527
+ ready() {
528
+ safeExecute(this.compId, 'onReady');
529
+ },
530
+ detached() {
531
+ Current.app.unmount(this.compId);
532
+ },
533
+ pageLifetimes: {
534
+ show(options) {
535
+ safeExecute(this.compId, 'onShow', options);
536
+ },
537
+ hide() {
538
+ safeExecute(this.compId, 'onHide');
539
+ }
540
+ },
541
+ methods: {
542
+ eh: eventHandler
543
+ }
544
+ };
545
+ function setCurrent(compId) {
546
+ const pages = getCurrentPages();
547
+ const currentPage = pages[pages.length - 1];
548
+ if (Current.page === currentPage)
549
+ return;
550
+ Current.page = currentPage;
551
+ const route = currentPage.route || currentPage.__route__;
552
+ const router = {
553
+ params: currentPage.options || {},
554
+ path: addLeadingSlash(route),
555
+ $taroPath: compId,
556
+ onReady: '',
557
+ onHide: '',
558
+ onShow: ''
559
+ };
560
+ Current.router = router;
561
+ if (!currentPage.options) {
562
+ // 例如在微信小程序中,页面 options 的设置时机比组件 attached 慢
563
+ Object.defineProperty(currentPage, 'options', {
564
+ enumerable: true,
565
+ configurable: true,
566
+ get() {
567
+ return this._optionsValue;
568
+ },
569
+ set(value) {
570
+ router.params = value;
571
+ this._optionsValue = value;
572
+ }
573
+ });
574
+ }
575
+ }
576
+ // onShareAppMessage 和 onShareTimeline 一样,会影响小程序右上方按钮的选项,因此不能默认注册。
577
+ if (Component.onShareAppMessage ||
578
+ ((_a = Component.prototype) === null || _a === void 0 ? void 0 : _a.onShareAppMessage) ||
579
+ Component.enableShareAppMessage) {
580
+ componentObj.methods.onShareAppMessage = function (options) {
581
+ const target = options === null || options === void 0 ? void 0 : options.target;
582
+ if (target) {
583
+ const id = target.id;
584
+ const element = document.getElementById(id);
585
+ if (element) {
586
+ target.dataset = element.dataset;
587
+ }
588
+ }
589
+ return safeExecute(this.compId, 'onShareAppMessage', options);
590
+ };
591
+ }
592
+ if (Component.onShareTimeline ||
593
+ ((_b = Component.prototype) === null || _b === void 0 ? void 0 : _b.onShareTimeline) ||
594
+ Component.enableShareTimeline) {
595
+ componentObj.methods.onShareTimeline = function () {
596
+ return safeExecute(this.compId, 'onShareTimeline');
597
+ };
598
+ }
599
+ return componentObj;
519
600
  }
520
601
 
521
- var _a;
522
- const hooks = container.get(SERVICE_IDENTIFIER.Hooks);
523
- hooks.initNativeApiImpls || (hooks.initNativeApiImpls = []);
524
- hooks.initNativeApiImpls.push(function (taro) {
525
- for (const hook in taroHooks$1) {
526
- taro[hook] = taroHooks$1[hook];
527
- }
528
- });
529
- if (__TARO_FRAMEWORK__ === 'preact') {
530
- const options = require('preact').options;
531
- const oldVNodeHook = options.vnode;
532
- options.vnode = vnode => {
533
- const { type, props } = vnode;
534
- let normalizedProps = props;
535
- // only normalize props on Element nodes
536
- if (typeof type === 'string') {
537
- normalizedProps = {};
538
- for (let i in props) {
539
- const value = props[i];
540
- if (/^on/.test(i)) {
541
- i = i.toLowerCase();
542
- }
543
- normalizedProps[i] = value;
544
- }
545
- vnode.props = normalizedProps;
546
- }
547
- if (oldVNodeHook)
548
- oldVNodeHook(vnode);
549
- };
550
- (_a = hooks.modifyMpEventImpls) === null || _a === void 0 ? void 0 : _a.push(e => {
551
- const type = e.type;
552
- if (type === 'tap') {
553
- e.type = 'click';
554
- }
555
- else if (type === 'focus') {
556
- // 兼容 preact/compat/src/render.js options.vnode 的处理逻辑
557
- e.type = 'focusin';
558
- }
559
- else if (type === 'blur') {
560
- e.type = 'focusout';
561
- }
562
- });
563
- // hooks.modifyDispatchEventImpls?.push(e => {
564
- // })
602
+ hooks.tap('initNativeApi', function (taro) {
603
+ for (const hook in taroHooks) {
604
+ taro[hook] = taroHooks[hook];
605
+ }
606
+ });
607
+ if (__TARO_FRAMEWORK__ === 'preact') {
608
+ const options = require('preact').options;
609
+ const oldVNodeHook = options.vnode;
610
+ const oldDiffedHook = options.diffed;
611
+ options.vnode = vnode => {
612
+ const { type, props } = vnode;
613
+ let normalizedProps = props;
614
+ // only normalize props on Element nodes
615
+ if (typeof type === 'string') {
616
+ normalizedProps = {};
617
+ for (let i in props) {
618
+ const value = props[i];
619
+ if (/^on/.test(i)) {
620
+ i = i.toLowerCase();
621
+ }
622
+ if (type === 'map' && i === 'onregionchange') {
623
+ // map 组件的 regionchange 事件非常特殊,详情:https://github.com/NervJS/taro/issues/5766
624
+ normalizedProps.onbegin = value;
625
+ normalizedProps.onend = value;
626
+ continue;
627
+ }
628
+ normalizedProps[i] = value;
629
+ }
630
+ vnode.props = normalizedProps;
631
+ }
632
+ if (oldVNodeHook)
633
+ oldVNodeHook(vnode);
634
+ };
635
+ options.diffed = function (newVNode) {
636
+ const dom = newVNode._dom;
637
+ const newVNodeProps = newVNode.props;
638
+ if (dom) { /** ElementNode */
639
+ for (const propName in newVNodeProps) {
640
+ const propValue = newVNodeProps[propName];
641
+ if (propValue === false && dom.props[propName] === undefined) {
642
+ // 值为 false 的属性在 Preact 的 diff 中被 removeAttribute 了,这里手动 setAttribute
643
+ // fix https://github.com/NervJS/taro/issues/11197
644
+ dom.setAttribute(propName, propValue);
645
+ }
646
+ }
647
+ }
648
+ if (oldDiffedHook)
649
+ oldDiffedHook(newVNode);
650
+ };
651
+ hooks.tap('modifyMpEvent', e => {
652
+ const type = e.type;
653
+ if (type === 'tap') {
654
+ e.type = 'click';
655
+ }
656
+ else if (type === 'focus') {
657
+ // 兼容 preact/compat/src/render.js options.vnode 的处理逻辑
658
+ e.type = 'focusin';
659
+ }
660
+ else if (type === 'blur') {
661
+ e.type = 'focusout';
662
+ }
663
+ });
664
+ // hooks.modifyDispatchEventImpls?.push(e => {
665
+ // })
565
666
  }
566
667
 
567
- export { PageContext, R$1 as R, connectReactPage, createNativeComponentConfig, createReactApp, setReconciler, useAddToFavorites, useDidHide, useDidShow, useOptionMenuClick, usePageScroll, usePullDownRefresh, usePullIntercept, useReachBottom, useReady, useResize, useRouter, useScope, useShareAppMessage, useShareTimeline, useTabItemTap, useTitleClick };
668
+ export { connectReactPage, createNativeComponentConfig, createReactApp, setReconciler, useAddToFavorites, useDidHide, useDidShow, useError, useLaunch, useLoad, useOptionMenuClick, usePageNotFound, usePageScroll, usePullDownRefresh, usePullIntercept, useReachBottom, useReady, useResize, useRouter, useSaveExitState, useScope, useShareAppMessage, useShareTimeline, useTabItemTap, useTitleClick, useUnload };
568
669
  //# sourceMappingURL=runtime.js.map