@mpxjs/webpack-plugin 2.6.113 → 2.6.114-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 (39) hide show
  1. package/lib/config.js +14 -0
  2. package/lib/dependency/AddEntryDependency.js +24 -0
  3. package/lib/dependency/ResolveDependency.js +4 -0
  4. package/lib/index.js +44 -3
  5. package/lib/json-compiler/index.js +3 -0
  6. package/lib/loader.js +43 -2
  7. package/lib/path-loader.js +4 -1
  8. package/lib/platform/template/wx/component-config/button.js +14 -2
  9. package/lib/platform/template/wx/component-config/image.js +4 -0
  10. package/lib/platform/template/wx/component-config/input.js +4 -0
  11. package/lib/platform/template/wx/component-config/rich-text.js +4 -0
  12. package/lib/platform/template/wx/component-config/scroll-view.js +4 -0
  13. package/lib/platform/template/wx/component-config/switch.js +4 -0
  14. package/lib/platform/template/wx/component-config/text.js +4 -0
  15. package/lib/platform/template/wx/component-config/textarea.js +5 -0
  16. package/lib/platform/template/wx/component-config/view.js +4 -0
  17. package/lib/platform/template/wx/index.js +114 -1
  18. package/lib/runtime/components/tenon/filterTag.js +402 -0
  19. package/lib/runtime/components/tenon/getInnerListeners.js +292 -0
  20. package/lib/runtime/components/tenon/tenon-button.vue +305 -0
  21. package/lib/runtime/components/tenon/tenon-image.vue +61 -0
  22. package/lib/runtime/components/tenon/tenon-input.vue +95 -0
  23. package/lib/runtime/components/tenon/tenon-rich-text.vue +30 -0
  24. package/lib/runtime/components/tenon/tenon-scroll-view.vue +118 -0
  25. package/lib/runtime/components/tenon/tenon-switch.vue +91 -0
  26. package/lib/runtime/components/tenon/tenon-text-area.vue +64 -0
  27. package/lib/runtime/components/tenon/tenon-text.vue +64 -0
  28. package/lib/runtime/components/tenon/tenon-view.vue +89 -0
  29. package/lib/runtime/components/tenon/util.js +44 -0
  30. package/lib/runtime/optionProcessor.tenon.js +386 -0
  31. package/lib/template-compiler/compiler.js +11 -2
  32. package/lib/template-compiler/trans-dynamic-class-expr.js +1 -1
  33. package/lib/tenon/index.js +108 -0
  34. package/lib/tenon/processJSON.js +361 -0
  35. package/lib/tenon/processScript.js +260 -0
  36. package/lib/tenon/processStyles.js +21 -0
  37. package/lib/tenon/processTemplate.js +133 -0
  38. package/lib/utils/get-relative-path.js +24 -0
  39. package/package.json +7 -3
@@ -0,0 +1,260 @@
1
+ const genComponentTag = require('../utils/gen-component-tag')
2
+ const loaderUtils = require('loader-utils')
3
+ const addQuery = require('../utils/add-query')
4
+ const normalize = require('../utils/normalize')
5
+ const SingleEntryPlugin = require('webpack/lib/SingleEntryPlugin')
6
+ const AddEntryDependency = require('../dependency/AddEntryDependency')
7
+ const builtInLoaderPath = normalize.lib('built-in-loader')
8
+ const optionProcessorPath = normalize.lib('runtime/optionProcessor')
9
+
10
+ function shallowStringify (obj) {
11
+ let arr = []
12
+ for (let key in obj) {
13
+ if (obj.hasOwnProperty(key)) {
14
+ let value = obj[key]
15
+ if (Array.isArray(value)) {
16
+ value = `[${value.join(',')}]`
17
+ }
18
+ arr.push(`'${key}':${value}`)
19
+ }
20
+ }
21
+ return `{${arr.join(',')}}`
22
+ }
23
+
24
+ let entryDeps = new Set()
25
+
26
+ let callbacked = false
27
+ let cacheCallback
28
+
29
+ module.exports = function (script, options, callback) {
30
+ const ctorType = options.ctorType
31
+ const builtInComponentsMap = options.builtInComponentsMap
32
+ const localComponentsMap = options.localComponentsMap
33
+ const localPagesMap = options.localPagesMap
34
+ const srcMode = options.srcMode
35
+ const loaderContext = options.loaderContext
36
+ const isProduction = options.isProduction
37
+ const componentId = options.componentId
38
+ const getRequireForSrc = options.getRequireForSrc
39
+ // const i18n = options.i18n
40
+ const jsonConfig = options.jsonConfig
41
+ // const tabBar = jsonConfig.tabBar
42
+ const tabBarMap = options.tabBarMap
43
+ // const tabBarStr = options.tabBarStr
44
+ const genericsInfo = options.genericsInfo
45
+ const componentGenerics = options.componentGenerics
46
+ const forceDisableBuiltInLoader = options.forceDisableBuiltInLoader
47
+
48
+ // add entry
49
+ const checkEntryDeps = (callback) => {
50
+ callback = callback || cacheCallback
51
+ if (callback && entryDeps.size === 0) {
52
+ callback()
53
+ } else {
54
+ cacheCallback = callback
55
+ }
56
+ }
57
+
58
+ const addEntryDep = (context, resource, name) => {
59
+ // 如果loader已经回调,就不再添加entry
60
+ if (callbacked) return
61
+ const dep = SingleEntryPlugin.createDependency(resource, name)
62
+ entryDeps.add(dep)
63
+ const virtualModule = new AddEntryDependency({
64
+ context: context._compiler.context,
65
+ dep,
66
+ name
67
+ })
68
+ /* eslint-disable camelcase */
69
+ context._module.__has_tenon_entry = true
70
+ context._module.addDependency(virtualModule)
71
+ entryDeps.delete(dep)
72
+ checkEntryDeps()
73
+ }
74
+
75
+ // const emitWarning = (msg) => {
76
+ // loaderContext.emitWarning(
77
+ // new Error('[script processor][' + loaderContext.resource + ']: ' + msg)
78
+ // )
79
+ // }
80
+
81
+ const stringifyRequest = r => loaderUtils.stringifyRequest(loaderContext, r)
82
+ // let tabBarPagesMap = {}
83
+ // if (tabBar && tabBarMap) {
84
+ // // 挂载tabBar组件
85
+ // const tabBarRequest = stringifyRequest(addQuery(tabBar.custom ? './custom-tab-bar/index' : tabBarPath, { component: true }))
86
+ // tabBarPagesMap['mpx-tab-bar'] = `getComponent(require(${tabBarRequest}))`
87
+ // // 挂载tabBar页面
88
+ // Object.keys(tabBarMap).forEach((pagePath) => {
89
+ // const pageCfg = localPagesMap[pagePath]
90
+ // if (pageCfg) {
91
+ // const pageRequest = stringifyRequest(pageCfg.resource)
92
+ // if (pageCfg.async) {
93
+ // tabBarPagesMap[pagePath] = `()=>import(${pageRequest}).then(res => getComponent(res, { __mpxPageRoute: ${JSON.stringify(pagePath)} }))`
94
+ // } else {
95
+ // tabBarPagesMap[pagePath] = `getComponent(require(${pageRequest}), { __mpxPageRoute: ${JSON.stringify(pagePath)} })`
96
+ // }
97
+ // } else {
98
+ // emitWarning(`TabBar page path ${pagePath} is not exist in local page map, please check!`)
99
+ // }
100
+ // })
101
+ // }
102
+
103
+ let output = '/* script */\n'
104
+
105
+ let scriptSrcMode = srcMode
106
+ if (script) {
107
+ scriptSrcMode = script.mode || scriptSrcMode
108
+ } else {
109
+ script = {
110
+ tag: 'script',
111
+ content: ''
112
+ }
113
+ switch (ctorType) {
114
+ case 'app':
115
+ script.content = 'import {createApp} from "@mpxjs/core"\n' +
116
+ 'createApp({})\n'
117
+ break
118
+ case 'page':
119
+ script.content = 'import {createPage} from "@mpxjs/core"\n' +
120
+ 'createPage({})\n'
121
+ break
122
+ case 'component':
123
+ script.content = 'import {createComponent} from "@mpxjs/core"\n' +
124
+ 'createComponent({})\n'
125
+ }
126
+ }
127
+ output += genComponentTag(script, {
128
+ attrs (script) {
129
+ const attrs = Object.assign({}, script.attrs)
130
+ // src改为内联require,删除
131
+ delete attrs.src
132
+ return attrs
133
+ },
134
+ content (script) {
135
+ let content = `\n import processOption, { getComponent, getWxsMixin } from ${stringifyRequest(optionProcessorPath)}\n`
136
+ // add import
137
+ if (ctorType === 'app') {
138
+ content += ` import '@mpxjs/webpack-plugin/lib/runtime/base.styl'
139
+ import Vue from 'vue'
140
+ const VueRouter = {}
141
+ global.getApp = function(){}
142
+ global.__networkTimeout = ${JSON.stringify(jsonConfig.networkTimeout)}
143
+ global.__style = ${JSON.stringify(jsonConfig.style || 'v1')}
144
+ global.__mpxPageConfig = ${JSON.stringify(jsonConfig.window)}\n
145
+ global.currentPagePath = ""\n`
146
+ }
147
+ // 注入wxs模块
148
+ // content += ' const wxsModules = {}\n'
149
+ // if (options.wxsModuleMap) {
150
+ // Object.keys(options.wxsModuleMap).forEach((module) => {
151
+ // const src = loaderUtils.urlToRequest(options.wxsModuleMap[module], options.projectRoot)
152
+ // const expression = `require(${stringifyRequest(src)})`
153
+ // content += ` wxsModules.${module} = ${expression}\n`
154
+ // })
155
+ // }
156
+ let firstPage = ''
157
+ const pagesMap = {}
158
+ const componentsMap = {}
159
+ Object.keys(localPagesMap).forEach((pagePath) => {
160
+ const pageCfg = localPagesMap[pagePath]
161
+ // const pageRequest = stringifyRequest(pageCfg.resource)
162
+ addEntryDep(loaderContext, addQuery(pageCfg.resource, { tenon: true }), pagePath)
163
+ // addEntrySafely(loaderContext, addQuery(pageCfg.resource, { tenon: true }), pagePath)
164
+ // loaderContext.resolve(loaderContext._compiler.context, addQuery(pageCfg.resource, { tenon: true }), (err, resource) => {
165
+ // if(err) return callback(err)
166
+
167
+ // })
168
+ // if (pageCfg.async) {
169
+ // pagesMap[pagePath] = `()=>import(${pageRequest}).then(res => getComponent(res, { __mpxPageRoute: ${JSON.stringify(pagePath)} }))`
170
+ // } else {
171
+ // // 为了保持小程序中app->page->component的js执行顺序,所有的page和component都改为require引入
172
+ // pagesMap[pagePath] = `getComponent(require(${pageRequest}), { __mpxPageRoute: ${JSON.stringify(pagePath)} })`
173
+ // }
174
+
175
+ // if (pageCfg.isFirst) {
176
+ // firstPage = pagePath
177
+ // }
178
+ })
179
+
180
+ Object.keys(localComponentsMap).forEach((componentName) => {
181
+ const componentCfg = localComponentsMap[componentName]
182
+ const componentRequest = stringifyRequest(componentCfg.resource)
183
+ if (componentCfg.async) {
184
+ componentsMap[componentName] = `()=>import(${componentRequest}).then(res => getComponent(res))`
185
+ } else {
186
+ componentsMap[componentName] = `getComponent(require(${componentRequest}))`
187
+ }
188
+ })
189
+
190
+ Object.keys(builtInComponentsMap).forEach((componentName) => {
191
+ const componentCfg = builtInComponentsMap[componentName]
192
+ const componentRequest = forceDisableBuiltInLoader ? stringifyRequest(componentCfg.resource) : stringifyRequest('builtInComponent.vue!=!' + builtInLoaderPath + '!' + componentCfg.resource)
193
+ componentsMap[componentName] = `getComponent(require(${componentRequest}), { __mpxBuiltIn: true })`
194
+ })
195
+
196
+ content += ` global.currentSrcMode = ${JSON.stringify(scriptSrcMode)}\n`
197
+ if (!isProduction) {
198
+ content += ` global.currentResource = ${JSON.stringify(loaderContext.resourcePath)}\n`
199
+ }
200
+ // 为了正确获取currentSrcMode便于运行时进行转换,对于src引入的组件script采用require方式引入(由于webpack会将import的执行顺序上升至最顶),这意味着对于src引入脚本中的named export将不会生效,不过鉴于mpx和小程序中本身也没有在组件script中声明export的用法,所以应该没有影响
201
+ content += script.src
202
+ ? (getRequireForSrc('script', script) + '\n')
203
+ : (script.content + '\n') + '\n'
204
+ // createApp/Page/Component执行完成后立刻获取当前的option并暂存
205
+ content += ` const currentOption = global.currentOption\n`
206
+ // 获取pageConfig
207
+ const pageConfig = {}
208
+ if (ctorType === 'page') {
209
+ // 存储当前page路径
210
+ content += ` global.currentPagePath = ${JSON.stringify(loaderContext._compilation.__mpx__.pagesMap[loaderContext.resourcePath])}\n`
211
+ const uselessOptions = new Set([
212
+ 'usingComponents',
213
+ 'style',
214
+ 'singlePage'
215
+ ])
216
+ Object.keys(jsonConfig)
217
+ .filter(key => !uselessOptions.has(key))
218
+ .forEach(key => {
219
+ pageConfig[key] = jsonConfig[key]
220
+ })
221
+ }
222
+
223
+ // 配置平台转换通过createFactory在core中convertor中定义和进行
224
+ // 通过processOption进行组件注册和路由注入
225
+ content += ` export default processOption(
226
+ currentOption,
227
+ ${JSON.stringify(ctorType)},
228
+ ${JSON.stringify(firstPage)},
229
+ ${JSON.stringify(componentId)},
230
+ ${JSON.stringify(pageConfig)},
231
+ // @ts-ignore
232
+ ${shallowStringify(pagesMap)},
233
+ // @ts-ignore
234
+ ${shallowStringify(componentsMap)},
235
+ ${JSON.stringify(tabBarMap)},
236
+ ${JSON.stringify(componentGenerics)},
237
+ ${JSON.stringify(genericsInfo)},
238
+ undefined`
239
+
240
+ // if (ctorType === 'app') {
241
+ // content += `,
242
+ // Vue,
243
+ // VueRouter`
244
+ // if (i18n) {
245
+ // content += `,
246
+ // i18n`
247
+ // }
248
+ // }
249
+ content += `\n )\n`
250
+ return content
251
+ }
252
+ })
253
+ output += '\n'
254
+ checkEntryDeps(() => {
255
+ callbacked = true
256
+ callback(null, {
257
+ output
258
+ })
259
+ })
260
+ }
@@ -0,0 +1,21 @@
1
+ const genComponentTag = require('../utils/gen-component-tag')
2
+
3
+ module.exports = function (styles, options, callback) {
4
+ let output = '/* styles */\n'
5
+ if (styles.length) {
6
+ styles.forEach((style) => {
7
+ output += genComponentTag(style, {
8
+ attrs (style) {
9
+ const attrs = Object.assign({}, style.attrs)
10
+ if (options.autoScope) attrs.scoped = true
11
+ return attrs
12
+ }
13
+ })
14
+ output += '\n'
15
+ })
16
+ output += '\n'
17
+ }
18
+ callback(null, {
19
+ output
20
+ })
21
+ }
@@ -0,0 +1,133 @@
1
+ const templateCompiler = require('../template-compiler/compiler')
2
+ const genComponentTag = require('../utils/gen-component-tag')
3
+ const addQuery = require('../utils/add-query')
4
+ const path = require('path')
5
+ const parseRequest = require('../utils/parse-request')
6
+ // const getMainCompilation = require('../utils/get-main-compilation')
7
+
8
+ // function calculateRootEleChild (arr) {
9
+ // if (!arr) {
10
+ // return 0
11
+ // }
12
+ // return arr.reduce((total, item) => {
13
+ // if (item.type === 1) {
14
+ // if (item.tag === 'template') {
15
+ // total += calculateRootEleChild(item.children)
16
+ // } else {
17
+ // total += 1
18
+ // }
19
+ // }
20
+ // return total
21
+ // }, 0)
22
+ // }
23
+
24
+ module.exports = function (template, options, callback) {
25
+ const mode = options.mode
26
+ const srcMode = options.srcMode
27
+ const defs = options.defs
28
+ const moduleId = options.moduleId
29
+ const loaderContext = options.loaderContext
30
+ const ctorType = options.ctorType
31
+ const resourcePath = parseRequest(loaderContext.resource).resourcePath
32
+ const builtInComponentsMap = {}
33
+ // const compilation = loaderContext._compilation
34
+ // const mainCompilation = getMainCompilation(compilation)
35
+ // const mpx = mainCompilation.__mpx__
36
+ // const wxsContentMap = mpx.wxsContentMap
37
+ let wxsModuleMap, genericsInfo
38
+ let output = '/* template */\n'
39
+
40
+ if (ctorType === 'app') {
41
+ template = {
42
+ tag: 'template',
43
+ content: '<div class="app">this is app</div>'
44
+ }
45
+ // builtInComponentsMap['mpx-keep-alive'] = {
46
+ // resource: addQuery('@mpxjs/webpack-plugin/lib/runtime/components/web/mpx-keep-alive.vue', { component: true })
47
+ // }
48
+ }
49
+
50
+ if (template) {
51
+ // 由于远端src template资源引用的相对路径可能发生变化,暂时不支持。
52
+ if (template.src) {
53
+ return callback(new Error('[mpx loader][' + loaderContext.resource + ']: ' + 'template content must be inline in .mpx files!'))
54
+ }
55
+ if (template.lang) {
56
+ return callback(new Error('[mpx loader][' + loaderContext.resource + ']: ' + 'template lang is not supported in trans web mode temporarily, we will support it in the future!'))
57
+ }
58
+
59
+ output += genComponentTag(template, (template) => {
60
+ if (ctorType === 'app') {
61
+ return template.content
62
+ }
63
+ if (template.content) {
64
+ const templateSrcMode = template.mode || srcMode
65
+ const parsed = templateCompiler.parse(template.content, {
66
+ warn: (msg) => {
67
+ loaderContext.emitWarning(
68
+ new Error('[template compiler][' + loaderContext.resource + ']: ' + msg)
69
+ )
70
+ },
71
+ error: (msg) => {
72
+ loaderContext.emitError(
73
+ new Error('[template compiler][' + loaderContext.resource + ']: ' + msg)
74
+ )
75
+ },
76
+ usingComponents: options.usingComponents,
77
+ hasComment: options.hasComment,
78
+ isNative: options.isNative,
79
+ basename: path.basename(resourcePath),
80
+ isComponent: ctorType === 'component',
81
+ mode,
82
+ srcMode: templateSrcMode,
83
+ defs,
84
+ decodeHTMLText: options.decodeHTMLText,
85
+ // externalClasses: options.externalClasses,
86
+ hasScoped: false,
87
+ moduleId,
88
+ filePath: loaderContext.resourcePath,
89
+ i18n: null,
90
+ checkUsingComponents: options.checkUsingComponents,
91
+ // web模式下全局组件不会被合入usingComponents中,故globalComponents可以传空
92
+ globalComponents: [],
93
+ // web模式下实现抽象组件
94
+ componentGenerics: options.componentGenerics
95
+ })
96
+ // if (parsed.meta.wxsModuleMap) {
97
+ // wxsModuleMap = parsed.meta.wxsModuleMap
98
+ // }
99
+ // if (parsed.meta.wxsContentMap) {
100
+ // for (let module in parsed.meta.wxsContentMap) {
101
+ // wxsContentMap[`${resourcePath}~${module}`] = parsed.meta.wxsContentMap[module]
102
+ // }
103
+ // }
104
+ if (parsed.meta.builtInComponentsMap) {
105
+ Object.keys(parsed.meta.builtInComponentsMap).forEach((name) => {
106
+ builtInComponentsMap[name] = {
107
+ resource: addQuery(parsed.meta.builtInComponentsMap[name], { component: true })
108
+ }
109
+ })
110
+ }
111
+ // if (parsed.meta.genericsInfo) {
112
+ // genericsInfo = parsed.meta.genericsInfo
113
+ // }
114
+ // 输出H5有多个root element时, 使用div标签包裹
115
+ // if (parsed.root.tag === 'temp-node') {
116
+ // const childLen = calculateRootEleChild(parsed.root.children)
117
+ // if (childLen >= 2) {
118
+ // parsed.root.tag = 'div'
119
+ // }
120
+ // }
121
+ return templateCompiler.serialize(parsed.root)
122
+ }
123
+ })
124
+ output += '\n\n'
125
+ }
126
+
127
+ callback(null, {
128
+ output,
129
+ builtInComponentsMap,
130
+ genericsInfo,
131
+ wxsModuleMap
132
+ })
133
+ }
@@ -0,0 +1,24 @@
1
+ function getRelativePath (source, target) {
2
+ source = source && source.replace(/\/[^/]*$/, ''); // get dirname
3
+ // make sure source and target are absolute path
4
+ /^\//.test(source) || (source = '/' + source);
5
+ /^\//.test(target) || (target = '/' + target)
6
+ // check if source or target is root path
7
+ let sourceArr = source.split('/').filter((item, index) => index !== 0 && !!item)
8
+ let targetArr = target.split('/').filter((item, index) => index !== 0 && !!item)
9
+ let i = 0
10
+ while (sourceArr[i] === targetArr[i] && i < sourceArr.length && i < targetArr.length) {
11
+ i++
12
+ }
13
+ let relativePath = ''
14
+ for (let j = 0; j < sourceArr.length - i; j++) {
15
+ relativePath += '../'
16
+ }
17
+ relativePath += targetArr.slice(i).join('/')
18
+ if (relativePath[0] !== '.') relativePath = './' + relativePath
19
+ return relativePath
20
+ }
21
+
22
+ module.exports = {
23
+ getRelativePath
24
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mpxjs/webpack-plugin",
3
- "version": "2.6.113",
3
+ "version": "2.6.114-alpha.0",
4
4
  "description": "mpx compile core",
5
5
  "keywords": [
6
6
  "mpx"
@@ -27,6 +27,9 @@
27
27
  "@better-scroll/slide": "^2.2.1",
28
28
  "@better-scroll/wheel": "^2.2.1",
29
29
  "@better-scroll/zoom": "^2.2.1",
30
+ "@hummer/tenon-dev-server-webpack-plugin": "0.0.2",
31
+ "@hummer/tenon-loader": "^1.1.0",
32
+ "@hummer/tenon-style-loader": "^0.2.0",
30
33
  "acorn-walk": "^7.2.0",
31
34
  "async": "^2.6.0",
32
35
  "consolidate": "^0.15.1",
@@ -79,7 +82,8 @@
79
82
  },
80
83
  "devDependencies": {
81
84
  "@types/babel-traverse": "^6.25.4",
82
- "@types/babel-types": "^7.0.4"
85
+ "@types/babel-types": "^7.0.4",
86
+ "webpack": "^4.46.0"
83
87
  },
84
- "gitHead": "05ebd038f9f72d8a12dbae6c6f7685dbfa19f1b8"
88
+ "gitHead": "7f944d9d7fe0dd3bd0a798c6268c6d08f90d62c0"
85
89
  }