@mpxjs/webpack-plugin 2.8.35 → 2.9.0-beta.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.
@@ -1,319 +1,362 @@
1
- import { isBrowser } from './env'
2
1
  import { hasOwn } from './utils'
2
+ import { isBrowser } from './env'
3
3
  import transRpxStyle from './transRpxStyle'
4
4
  import animation from './animation'
5
5
 
6
- export default function processOption (
7
- option,
8
- ctorType,
9
- firstPage,
10
- outputPath,
11
- pageConfig,
12
- pagesMap,
13
- componentsMap,
14
- tabBarMap,
15
- componentGenerics,
16
- genericsInfo,
17
- mixin,
18
- hasApp,
19
- Vue,
20
- VueRouter
21
- ) {
22
- if (ctorType === 'app') {
23
- // 对于app中的组件需要全局注册
24
- for (const componentName in componentsMap) {
25
- if (hasOwn(componentsMap, componentName)) {
26
- const component = componentsMap[componentName]
27
- Vue.component(componentName, component)
6
+ export default function processComponentOption ({ option, ctorType, outputPath, pageConfig, componentsMap, componentGenerics, genericsInfo, mixin, hasApp }) {
7
+ // 局部注册页面和组件中依赖的组件
8
+ for (const componentName in componentsMap) {
9
+ if (hasOwn(componentsMap, componentName)) {
10
+ const component = componentsMap[componentName]
11
+ if (!option.components) {
12
+ option.components = {}
28
13
  }
14
+ option.components[componentName] = component
29
15
  }
16
+ }
17
+
18
+ if (genericsInfo) {
19
+ const genericHash = genericsInfo.hash
20
+ global.__mpxGenericsMap[genericHash] = {}
21
+ Object.keys(genericsInfo.map).forEach((genericValue) => {
22
+ if (componentsMap[genericValue]) {
23
+ global.__mpxGenericsMap[genericHash][genericValue] = componentsMap[genericValue]
24
+ } else {
25
+ console.warn(`[Mpx runtime warn]: generic value "${genericValue}" must be
26
+ registered in parent context!`)
27
+ }
28
+ })
29
+ }
30
+
31
+ if (componentGenerics) {
32
+ option.props = option.props || {}
33
+ option.props.generichash = String
34
+ Object.keys(componentGenerics).forEach((genericName) => {
35
+ if (componentGenerics[genericName].default) {
36
+ option.props[`generic${genericName}`] = {
37
+ type: String,
38
+ default: `${genericName}default`
39
+ }
40
+ } else {
41
+ option.props[`generic${genericName}`] = String
42
+ }
43
+ })
44
+ }
30
45
 
31
- Vue.directive('animation', animation)
46
+ if (ctorType === 'page') {
47
+ option.__mpxPageConfig = Object.assign({}, global.__mpxPageConfig, pageConfig)
48
+ }
32
49
 
33
- Vue.filter('transRpxStyle', transRpxStyle)
50
+ if (!hasApp) {
51
+ option.directives = { animation }
52
+ option.filters = { transRpxStyle }
53
+ }
34
54
 
35
- const routes = []
55
+ if (option.mixins) {
56
+ option.mixins.push(mixin)
57
+ } else {
58
+ option.mixins = [mixin]
59
+ }
36
60
 
37
- for (const pagePath in pagesMap) {
38
- if (hasOwn(pagesMap, pagePath)) {
39
- const page = pagesMap[pagePath]
40
- routes.push({
41
- path: '/' + pagePath,
42
- component: page
43
- })
44
- }
61
+ if (outputPath) {
62
+ option.componentPath = '/' + outputPath
63
+ }
64
+
65
+ return option
66
+ }
67
+
68
+ export function getComponent (component, extendOptions) {
69
+ component = component.__esModule ? component.default : component
70
+ // eslint-disable-next-line
71
+ if (extendOptions) Object.assign(component, extendOptions)
72
+ return component
73
+ }
74
+
75
+ export function getWxsMixin (wxsModules) {
76
+ if (!wxsModules || !Object.keys(wxsModules).length) return {}
77
+ return {
78
+ created () {
79
+ Object.keys(wxsModules).forEach((key) => {
80
+ if (key in this) {
81
+ console.error(`[Mpx runtime error]: The wxs module key [${key}] exist in the component/page instance already, please check and rename it!`)
82
+ } else {
83
+ this[key] = wxsModules[key]
84
+ }
85
+ })
45
86
  }
87
+ }
88
+ }
46
89
 
47
- if (routes.length) {
48
- if (firstPage) {
49
- routes.push({
50
- path: '/',
51
- redirect: '/' + firstPage
52
- })
53
- }
54
- const webRouteConfig = global.__mpx.config.webRouteConfig
55
- global.__mpxRouter = option.router = new VueRouter({
56
- ...webRouteConfig,
57
- routes: routes
90
+ function createApp ({ componentsMap, Vue, pagesMap, firstPage, VueRouter, App, tabBarMap }) {
91
+ const option = {}
92
+ // 对于app中的组件需要全局注册
93
+ for (const componentName in componentsMap) {
94
+ if (hasOwn(componentsMap, componentName)) {
95
+ const component = componentsMap[componentName]
96
+ Vue.component(componentName, component)
97
+ }
98
+ }
99
+
100
+ Vue.directive('animation', animation)
101
+
102
+ Vue.filter('transRpxStyle', transRpxStyle)
103
+
104
+ const routes = []
105
+
106
+ for (const pagePath in pagesMap) {
107
+ if (hasOwn(pagesMap, pagePath)) {
108
+ const page = pagesMap[pagePath]
109
+ routes.push({
110
+ path: '/' + pagePath,
111
+ component: page
58
112
  })
59
- global.__mpxRouter.stack = []
60
- global.__mpxRouter.needCache = null
61
- global.__mpxRouter.needRemove = []
62
- // 处理reLaunch中传递的url并非首页时的replace逻辑
63
- global.__mpxRouter.beforeEach(function (to, from, next) {
64
- let action = global.__mpxRouter.__mpxAction
65
- const stack = global.__mpxRouter.stack
113
+ }
114
+ }
66
115
 
67
- // 处理人为操作
68
- if (!action) {
69
- if (stack.length > 1 && stack[stack.length - 2].path === to.path) {
70
- action = {
71
- type: 'back',
72
- delta: 1
73
- }
74
- } else {
75
- action = {
76
- type: 'to'
77
- }
116
+ if (routes.length) {
117
+ if (firstPage) {
118
+ routes.push({
119
+ path: '/',
120
+ redirect: '/' + firstPage
121
+ })
122
+ }
123
+ const webRouteConfig = global.__mpx.config.webRouteConfig
124
+ global.__mpxRouter = option.router = new VueRouter({
125
+ ...webRouteConfig,
126
+ routes: routes
127
+ })
128
+ global.__mpxRouter.stack = []
129
+ global.__mpxRouter.needCache = null
130
+ global.__mpxRouter.needRemove = []
131
+ // 处理reLaunch中传递的url并非首页时的replace逻辑
132
+ global.__mpxRouter.beforeEach(function (to, from, next) {
133
+ let action = global.__mpxRouter.__mpxAction
134
+ const stack = global.__mpxRouter.stack
135
+
136
+ // 处理人为操作
137
+ if (!action) {
138
+ if (stack.length > 1 && stack[stack.length - 2].path === to.path) {
139
+ action = {
140
+ type: 'back',
141
+ delta: 1
142
+ }
143
+ } else {
144
+ action = {
145
+ type: 'to'
78
146
  }
79
147
  }
148
+ }
80
149
 
81
- const pageInRoutes = routes.some(item => item.path === to.path)
82
- if (!pageInRoutes) {
83
- if (stack.length < 1) {
84
- if (global.__mpxRouter.app.$options.onPageNotFound) {
85
- // onPageNotFound,仅首次进入时生效
86
- global.__mpxRouter.app.$options.onPageNotFound({
87
- path: to.path,
88
- query: to.query,
89
- isEntryPage: true
90
- })
91
- return
92
- } else {
93
- console.warn(`[Mpx runtime warn]: the ${to.path} path does not exist in the application,will redirect to the home page path ${firstPage}`)
94
- return next({
95
- path: firstPage,
96
- replace: true
97
- })
98
- }
150
+ const pageInRoutes = routes.some(item => item.path === to.path)
151
+ if (!pageInRoutes) {
152
+ if (stack.length < 1) {
153
+ if (global.__mpxRouter.app.$options.onPageNotFound) {
154
+ // onPageNotFound,仅首次进入时生效
155
+ global.__mpxRouter.app.$options.onPageNotFound({
156
+ path: to.path,
157
+ query: to.query,
158
+ isEntryPage: true
159
+ })
160
+ return
99
161
  } else {
100
- let methods = ''
101
- switch (action.type) {
102
- case 'to':
103
- methods = 'navigateTo'
104
- break
105
- case 'redirect':
106
- methods = 'redirectTo'
107
- break
108
- case 'back':
109
- methods = 'navigateBack'
110
- break
111
- case 'reLaunch':
112
- methods = 'reLaunch'
113
- break
114
- default:
115
- methods = 'navigateTo'
116
- }
117
- throw new Error(`${methods}:fail page "${to.path}" is not found`)
162
+ console.warn(`[Mpx runtime warn]: the ${to.path} path does not exist in the application,will redirect to the home page path ${firstPage}`)
163
+ return next({
164
+ path: firstPage,
165
+ replace: true
166
+ })
118
167
  }
168
+ } else {
169
+ let methods = ''
170
+ switch (action.type) {
171
+ case 'to':
172
+ methods = 'navigateTo'
173
+ break
174
+ case 'redirect':
175
+ methods = 'redirectTo'
176
+ break
177
+ case 'back':
178
+ methods = 'navigateBack'
179
+ break
180
+ case 'reLaunch':
181
+ methods = 'reLaunch'
182
+ break
183
+ default:
184
+ methods = 'navigateTo'
185
+ }
186
+ throw new Error(`${methods}:fail page "${to.path}" is not found`)
119
187
  }
188
+ }
120
189
 
121
- const insertItem = {
122
- path: to.path
123
- }
124
- // 构建历史栈
125
- switch (action.type) {
126
- case 'to':
127
- stack.push(insertItem)
128
- global.__mpxRouter.needCache = insertItem
129
- break
130
- case 'back':
131
- global.__mpxRouter.needRemove = stack.splice(stack.length - action.delta, action.delta)
132
- break
133
- case 'redirect':
134
- global.__mpxRouter.needRemove = stack.splice(stack.length - 1, 1, insertItem)
135
- global.__mpxRouter.needCache = insertItem
136
- break
137
- case 'switch':
138
- if (!action.replaced) {
139
- action.replaced = true
140
- return next({
141
- path: action.path,
142
- replace: true
143
- })
144
- } else {
145
- // 将非tabBar页面remove
146
- let tabItem = null
147
- global.__mpxRouter.needRemove = stack.filter((item) => {
148
- if (tabBarMap[item.path.slice(1)]) {
149
- tabItem = item
150
- tabItem.path = to.path
151
- return false
152
- }
153
- return true
154
- })
155
- if (tabItem) {
156
- global.__mpxRouter.stack = [tabItem]
157
- } else {
158
- global.__mpxRouter.stack = [insertItem]
159
- global.__mpxRouter.needCache = insertItem
190
+ const insertItem = {
191
+ path: to.path
192
+ }
193
+ // 构建历史栈
194
+ switch (action.type) {
195
+ case 'to':
196
+ stack.push(insertItem)
197
+ global.__mpxRouter.needCache = insertItem
198
+ break
199
+ case 'back':
200
+ global.__mpxRouter.needRemove = stack.splice(stack.length - action.delta, action.delta)
201
+ break
202
+ case 'redirect':
203
+ global.__mpxRouter.needRemove = stack.splice(stack.length - 1, 1, insertItem)
204
+ global.__mpxRouter.needCache = insertItem
205
+ break
206
+ case 'switch':
207
+ if (!action.replaced) {
208
+ action.replaced = true
209
+ return next({
210
+ path: action.path,
211
+ replace: true
212
+ })
213
+ } else {
214
+ // 将非tabBar页面remove
215
+ let tabItem = null
216
+ global.__mpxRouter.needRemove = stack.filter((item) => {
217
+ if (tabBarMap[item.path.slice(1)]) {
218
+ tabItem = item
219
+ tabItem.path = to.path
220
+ return false
160
221
  }
161
- }
162
- break
163
- case 'reLaunch':
164
- if (!action.replaced) {
165
- action.replaced = true
166
- return next({
167
- path: action.path,
168
- query: {
169
- reLaunchCount: action.reLaunchCount
170
- },
171
- replace: true
172
- })
222
+ return true
223
+ })
224
+ if (tabItem) {
225
+ global.__mpxRouter.stack = [tabItem]
173
226
  } else {
174
- global.__mpxRouter.needRemove = stack
175
227
  global.__mpxRouter.stack = [insertItem]
176
228
  global.__mpxRouter.needCache = insertItem
177
229
  }
178
- }
179
- next()
180
- })
181
- // 处理visibilitychange时触发当前活跃页面组件的onshow/onhide
182
- if (isBrowser) {
183
- const errorHandler = function (args, fromVue) {
184
- if (global.__mpxAppCbs && global.__mpxAppCbs.error && global.__mpxAppCbs.error.length) {
185
- global.__mpxAppCbs.error.forEach((cb) => {
186
- cb.apply(null, args)
187
- })
188
- } else if (fromVue) {
189
- throw args[0]
190
230
  }
191
- }
192
- Vue.config.errorHandler = (...args) => {
193
- return errorHandler(args, true)
194
- }
195
- window.addEventListener('error', (event) => {
196
- return errorHandler([event.error, event])
197
- })
198
- window.addEventListener('unhandledrejection', (event) => {
199
- return errorHandler([event.reason, event])
200
- })
201
- document.addEventListener('visibilitychange', function () {
202
- const vnode = global.__mpxRouter && global.__mpxRouter.__mpxActiveVnode
203
- if (vnode && vnode.componentInstance) {
204
- const currentPage = vnode.tag.endsWith('mpx-tab-bar-container') ? vnode.componentInstance.$refs.tabBarPage : vnode.componentInstance
205
- if (document.hidden) {
206
- if (global.__mpxAppCbs && global.__mpxAppCbs.hide) {
207
- global.__mpxAppCbs.hide.forEach((cb) => {
208
- cb()
209
- })
210
- }
211
- if (currentPage) {
212
- currentPage.mpxPageStatus = 'hide'
213
- }
214
- } else {
215
- if (global.__mpxAppCbs && global.__mpxAppCbs.show) {
216
- global.__mpxAppCbs.show.forEach((cb) => {
217
- // todo 实现app.onShow参数
218
- /* eslint-disable node/no-callback-literal */
219
- cb({})
220
- })
221
- }
222
- if (currentPage) {
223
- currentPage.mpxPageStatus = 'show'
224
- }
225
- }
231
+ break
232
+ case 'reLaunch':
233
+ if (!action.replaced) {
234
+ action.replaced = true
235
+ return next({
236
+ path: action.path,
237
+ query: {
238
+ reLaunchCount: action.reLaunchCount
239
+ },
240
+ replace: true
241
+ })
242
+ } else {
243
+ global.__mpxRouter.needRemove = stack
244
+ global.__mpxRouter.stack = [insertItem]
245
+ global.__mpxRouter.needCache = insertItem
226
246
  }
227
- })
228
- // 初始化length
229
- global.__mpxRouter.__mpxHistoryLength = global.history.length
230
247
  }
231
- }
232
-
233
- // 注入pinia
234
- if (global.__mpxPinia) {
235
- option.pinia = global.__mpxPinia
236
- }
237
- } else {
238
- // 局部注册页面和组件中依赖的组件
239
- for (const componentName in componentsMap) {
240
- if (hasOwn(componentsMap, componentName)) {
241
- const component = componentsMap[componentName]
242
- if (!option.components) {
243
- option.components = {}
248
+ next()
249
+ })
250
+ // 处理visibilitychange时触发当前活跃页面组件的onshow/onhide
251
+ if (isBrowser) {
252
+ const errorHandler = function (args, fromVue) {
253
+ if (global.__mpxAppCbs && global.__mpxAppCbs.error && global.__mpxAppCbs.error.length) {
254
+ global.__mpxAppCbs.error.forEach((cb) => {
255
+ cb.apply(null, args)
256
+ })
257
+ } else if (fromVue) {
258
+ throw args[0]
244
259
  }
245
- option.components[componentName] = component
246
260
  }
247
- }
248
-
249
- if (genericsInfo) {
250
- const genericHash = genericsInfo.hash
251
- global.__mpxGenericsMap[genericHash] = {}
252
- Object.keys(genericsInfo.map).forEach((genericValue) => {
253
- if (componentsMap[genericValue]) {
254
- global.__mpxGenericsMap[genericHash][genericValue] = componentsMap[genericValue]
255
- } else {
256
- console.log(option)
257
- console.warn(`[Mpx runtime warn]: generic value "${genericValue}" must be
258
- registered in parent context!`)
259
- }
261
+ Vue.config.errorHandler = (...args) => {
262
+ return errorHandler(args, true)
263
+ }
264
+ window.addEventListener('error', (event) => {
265
+ return errorHandler([event.error, event])
260
266
  })
261
- }
262
-
263
- if (componentGenerics) {
264
- option.props = option.props || {}
265
- option.props.generichash = String
266
- Object.keys(componentGenerics).forEach((genericName) => {
267
- if (componentGenerics[genericName].default) {
268
- option.props[`generic${genericName}`] = {
269
- type: String,
270
- default: `${genericName}default`
267
+ window.addEventListener('unhandledrejection', (event) => {
268
+ return errorHandler([event.reason, event])
269
+ })
270
+ document.addEventListener('visibilitychange', function () {
271
+ const vnode = global.__mpxRouter && global.__mpxRouter.__mpxActiveVnode
272
+ if (vnode && vnode.componentInstance) {
273
+ const currentPage = vnode.tag.endsWith('mpx-tab-bar-container') ? vnode.componentInstance.$refs.tabBarPage : vnode.componentInstance
274
+ if (document.hidden) {
275
+ if (global.__mpxAppCbs && global.__mpxAppCbs.hide) {
276
+ global.__mpxAppCbs.hide.forEach((cb) => {
277
+ cb()
278
+ })
279
+ }
280
+ if (currentPage) {
281
+ currentPage.mpxPageStatus = 'hide'
282
+ }
283
+ } else {
284
+ if (global.__mpxAppCbs && global.__mpxAppCbs.show) {
285
+ global.__mpxAppCbs.show.forEach((cb) => {
286
+ // todo 实现app.onShow参数
287
+ /* eslint-disable node/no-callback-literal */
288
+ cb({})
289
+ })
290
+ }
291
+ if (currentPage) {
292
+ currentPage.mpxPageStatus = 'show'
293
+ }
271
294
  }
272
- } else {
273
- option.props[`generic${genericName}`] = String
274
295
  }
275
296
  })
276
- }
277
-
278
- if (ctorType === 'page') {
279
- option.__mpxPageConfig = Object.assign({}, global.__mpxPageConfig, pageConfig)
280
- }
281
- if (!hasApp) {
282
- option.directives = { animation }
283
- option.filters = { transRpxStyle }
297
+ // 初始化length
298
+ global.__mpxRouter.__mpxHistoryLength = global.history.length
284
299
  }
285
300
  }
286
301
 
287
- if (option.mixins) {
288
- option.mixins.push(mixin)
289
- } else {
290
- option.mixins = [mixin]
302
+ if (App.onAppInit) {
303
+ Object.assign(option, App.onAppInit() || {})
291
304
  }
292
305
 
293
- if (outputPath) {
294
- option.componentPath = '/' + outputPath
306
+ if (isBrowser && global.__mpxPinia) {
307
+ // 注入pinia
308
+ option.pinia = global.__mpxPinia
295
309
  }
296
- return option
297
- }
298
310
 
299
- export function getComponent (component, extendOptions) {
300
- component = component.__esModule ? component.default : component
301
- // eslint-disable-next-line
302
- if (extendOptions) Object.assign(component, extendOptions)
303
- return component
311
+ const app = new Vue({
312
+ ...option,
313
+ render: (h) => h(App)
314
+ })
315
+ return {
316
+ app,
317
+ ...option
318
+ }
304
319
  }
305
320
 
306
- export function getWxsMixin (wxsModules) {
307
- if (!wxsModules) return {}
308
- return {
309
- created () {
310
- Object.keys(wxsModules).forEach((key) => {
311
- if (key in this) {
312
- console.error(`[Mpx runtime error]: The wxs module key [${key}] exist in the component/page instance already, please check and rename it!`)
313
- } else {
314
- this[key] = wxsModules[key]
315
- }
321
+ export function processAppOption ({ firstPage, pagesMap, componentsMap, App, Vue, VueRouter, tabBarMap, webConfig }) {
322
+ if (!isBrowser) {
323
+ return context => {
324
+ const { app, router, pinia = {} } = createApp({
325
+ App,
326
+ componentsMap,
327
+ Vue,
328
+ pagesMap,
329
+ firstPage,
330
+ VueRouter,
331
+ tabBarMap
316
332
  })
333
+ if (App.onSSRAppCreated) {
334
+ return App.onSSRAppCreated({ pinia, router, app, context })
335
+ } else {
336
+ return new Promise((resolve, reject) => {
337
+ router.push(context.url)
338
+ router.onReady(() => {
339
+ context.rendered = () => {
340
+ context.state = JSON.stringify((pinia.state && pinia.state.value) || {})
341
+ }
342
+ resolve(app)
343
+ }, reject)
344
+ })
345
+ }
346
+ }
347
+ } else {
348
+ const { app, pinia } = createApp({
349
+ App,
350
+ componentsMap,
351
+ Vue,
352
+ pagesMap,
353
+ firstPage,
354
+ VueRouter,
355
+ tabBarMap
356
+ })
357
+ if (window.__INITIAL_STATE__) {
358
+ pinia.state.value = JSON.parse(window.__INITIAL_STATE__)
317
359
  }
360
+ app.$mount(webConfig.el || '#app')
318
361
  }
319
362
  }