@mpxjs/webpack-plugin 2.7.0-beta.8 → 2.7.1-beta.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.
@@ -16,6 +16,8 @@ class AppEntryDependency extends NullDependency {
16
16
  const mpx = compilation.__mpx__
17
17
  const moduleGraph = compilation.moduleGraph
18
18
 
19
+ mpx.getEntryNode(module, 'app')
20
+
19
21
  if (mpx.appInfo.name) {
20
22
  const issuer = moduleGraph.getIssuer(module)
21
23
  const err = new Error(issuer
@@ -1,8 +1,9 @@
1
1
  const ModuleDependency = require('webpack/lib/dependencies/ModuleDependency')
2
2
  const makeSerializable = require('webpack/lib/util/makeSerializable')
3
+ const InitFragment = require('webpack/lib//InitFragment')
3
4
 
4
5
  class CommonJsVariableDependency extends ModuleDependency {
5
- constructor (request, name) {
6
+ constructor (request, name = '') {
6
7
  super(request)
7
8
  this.name = name
8
9
  }
@@ -44,10 +45,10 @@ CommonJsVariableDependency.Template = class CommonJsVariableDependencyTemplate e
44
45
  runtimeTemplate,
45
46
  moduleGraph,
46
47
  chunkGraph,
47
- runtimeRequirements
48
+ runtimeRequirements,
49
+ initFragments
48
50
  }
49
51
  ) {
50
- if (!dep.name) return
51
52
  const importedModule = moduleGraph.getModule(dep)
52
53
  let requireExpr = runtimeTemplate.moduleExports({
53
54
  module: importedModule,
@@ -57,7 +58,18 @@ CommonJsVariableDependency.Template = class CommonJsVariableDependencyTemplate e
57
58
  runtimeRequirements
58
59
  })
59
60
 
60
- source.insert(0, `/* mpx cjs variable */ var ${dep.name} = ${requireExpr};\n`)
61
+ let expr = '/* mpx cjs variable */ '
62
+ if (dep.name) expr += 'var ' + dep.name + ' = '
63
+ expr += requireExpr + ';\n'
64
+
65
+ initFragments.push(
66
+ new InitFragment(
67
+ expr,
68
+ InitFragment.STAGE_CONSTANTS,
69
+ 1,
70
+ dep.request
71
+ )
72
+ )
61
73
  }
62
74
  }
63
75
 
@@ -21,13 +21,13 @@ class DynamicEntryDependency extends NullDependency {
21
21
 
22
22
  get key () {
23
23
  const { resource, entryType, outputPath, packageRoot, relativePath, range } = this
24
- return [resource, entryType, outputPath, packageRoot, relativePath, ...range].join('|')
24
+ return toPosix([resource, entryType, outputPath, packageRoot, relativePath, ...range].join('|'))
25
25
  }
26
26
 
27
27
  addEntry (compilation, callback) {
28
28
  const mpx = compilation.__mpx__
29
29
  const publicPath = compilation.outputOptions.publicPath || ''
30
- let { resource, entryType, outputPath, relativePath } = this
30
+ let { resource, entryType, outputPath, relativePath, originEntryNode } = this
31
31
 
32
32
  const { packageRoot, outputPath: filename, alreadyOutputed } = mpx.getPackageInfo({
33
33
  resource,
@@ -59,7 +59,7 @@ class DynamicEntryDependency extends NullDependency {
59
59
  if (entryType === 'export') {
60
60
  mpx.exportModules.add(entryModule)
61
61
  }
62
- // todo entry的父子关系可以在这里建立
62
+ originEntryNode.addChild(mpx.getEntryNode(entryModule, entryType))
63
63
  return callback(null, {
64
64
  resultPath,
65
65
  entryModule
@@ -70,6 +70,7 @@ class DynamicEntryDependency extends NullDependency {
70
70
  mpxAction (module, compilation, callback) {
71
71
  const mpx = compilation.__mpx__
72
72
  const { packageRoot } = this
73
+ this.originEntryNode = mpx.getEntryNode(module)
73
74
  // 分包构建在需要在主包构建完成后在finishMake中处理,返回的资源路径先用key来占位,在合成extractedAssets时再进行最终替换
74
75
  if (packageRoot && mpx.currentPackageRoot !== packageRoot) {
75
76
  mpx.subpackagesEntriesMap[packageRoot] = mpx.subpackagesEntriesMap[packageRoot] || []
@@ -9,6 +9,7 @@ class FlagPluginDependency extends NullDependency {
9
9
  mpxAction (module, compilation, callback) {
10
10
  const mpx = compilation.__mpx__
11
11
  mpx.isPluginMode = true
12
+ mpx.getEntryNode(module, 'plugin')
12
13
  return callback()
13
14
  }
14
15
  }
@@ -0,0 +1,44 @@
1
+ const NullDependency = require('webpack/lib/dependencies/NullDependency')
2
+ const makeSerializable = require('webpack/lib/util/makeSerializable')
3
+
4
+ class RecordIndependentDependency extends NullDependency {
5
+ constructor (root, request) {
6
+ super()
7
+ this.root = root
8
+ this.request = request
9
+ }
10
+
11
+ get type () {
12
+ return 'mpx record independent'
13
+ }
14
+
15
+ mpxAction (module, compilation, callback) {
16
+ const mpx = compilation.__mpx__
17
+ const { root, request } = this
18
+ mpx.independentSubpackagesMap[root] = request
19
+ return callback()
20
+ }
21
+
22
+ serialize (context) {
23
+ const { write } = context
24
+ write(this.root)
25
+ write(this.request)
26
+ super.serialize(context)
27
+ }
28
+
29
+ deserialize (context) {
30
+ const { read } = context
31
+ this.root = read()
32
+ this.request = read()
33
+ super.deserialize(context)
34
+ }
35
+ }
36
+
37
+ RecordIndependentDependency.Template = class RecordIndependentDependencyTemplate {
38
+ apply () {
39
+ }
40
+ }
41
+
42
+ makeSerializable(RecordIndependentDependency, '@mpxjs/webpack-plugin/lib/dependencies/RecordIndependentDependency')
43
+
44
+ module.exports = RecordIndependentDependency
package/lib/extractor.js CHANGED
@@ -4,8 +4,8 @@ const parseRequest = require('./utils/parse-request')
4
4
  const toPosix = require('./utils/to-posix')
5
5
  const fixRelative = require('./utils/fix-relative')
6
6
  const addQuery = require('./utils/add-query')
7
+ const normalize = require('./utils/normalize')
7
8
  const { MPX_DISABLE_EXTRACTOR_CACHE, DEFAULT_RESULT_SOURCE } = require('./utils/const')
8
- const RecordResourceMapDependency = require('./dependencies/RecordResourceMapDependency')
9
9
 
10
10
  module.exports = content => content
11
11
 
@@ -37,10 +37,10 @@ module.exports.pitch = async function (remainingRequest) {
37
37
  })
38
38
 
39
39
  let request = remainingRequest
40
- // static的情况下需要记录相关静态资源的输出路径
40
+ // static的情况下需要用record-loader记录相关静态资源的输出路径,不能直接在这里记录,需要确保在子依赖开始构建前完成记录,因为子依赖构建时可能就需要访问当前资源的输出路径
41
41
  if (isStatic) {
42
- const packageRoot = queryObj.packageRoot || ''
43
- this._module.addPresentationalDependency(new RecordResourceMapDependency(resourcePath, 'staticResource', file, packageRoot))
42
+ const recordLoader = normalize.lib('record-loader')
43
+ request = `${recordLoader}!${remainingRequest}`
44
44
  }
45
45
 
46
46
  let content = await this.importModule(`!!${request}`)
@@ -51,6 +51,10 @@ module.exports.pitch = async function (remainingRequest) {
51
51
  }).join('\n')
52
52
  }
53
53
 
54
+ let resultSource = DEFAULT_RESULT_SOURCE
55
+
56
+ if (typeof content !== 'string') return resultSource
57
+
54
58
  const extractedInfo = {
55
59
  content,
56
60
  index
@@ -61,8 +65,6 @@ module.exports.pitch = async function (remainingRequest) {
61
65
  extractedInfo
62
66
  })
63
67
 
64
- let resultSource = DEFAULT_RESULT_SOURCE
65
-
66
68
  const { buildInfo } = this._module
67
69
 
68
70
  // 如果importModule子模块中包含动态特性,比如动态添加入口和静态资源输出路径,则当前extractor模块不可缓存
package/lib/helpers.js CHANGED
@@ -4,14 +4,6 @@ const selectorPath = normalize.lib('selector')
4
4
  const addQuery = require('./utils/add-query')
5
5
  const parseRequest = require('./utils/parse-request')
6
6
 
7
- function getRawRequest ({ resource, loaderIndex, loaders }, excludedPreLoaders = /eslint-loader/) {
8
- return loaderUtils.getRemainingRequest({
9
- resource: resource,
10
- loaderIndex: loaderIndex,
11
- loaders: loaders.filter(loader => !excludedPreLoaders.test(loader.path))
12
- })
13
- }
14
-
15
7
  const defaultLang = {
16
8
  template: 'wxml',
17
9
  styles: 'wxss',
@@ -21,7 +13,7 @@ const defaultLang = {
21
13
  }
22
14
 
23
15
  module.exports = function createHelpers (loaderContext) {
24
- const rawRequest = getRawRequest(loaderContext)
16
+ const rawRequest = loaderUtils.getRemainingRequest(loaderContext)
25
17
 
26
18
  function getRequire (type, part, extraOptions, index) {
27
19
  return 'require(' + getRequestString(type, part, extraOptions, index) + ')'
@@ -0,0 +1,59 @@
1
+ const parseComponent = require('./parser')
2
+ const createHelpers = require('./helpers')
3
+ const CommonJsVariableDependency = require('./dependencies/CommonJsVariableDependency')
4
+ const path = require('path')
5
+ const normalize = require('./utils/normalize')
6
+
7
+ module.exports = function (content) {
8
+ this.cacheable()
9
+ const mpx = this.getMpx()
10
+ if (!mpx) {
11
+ return content
12
+ }
13
+
14
+ const mode = mpx.mode
15
+ const env = mpx.env
16
+ const i18n = mpx.i18n
17
+ const filePath = this.resourcePath
18
+ const extname = path.extname(filePath)
19
+ if (extname === '.mpx') {
20
+ const parts = parseComponent(content, {
21
+ filePath,
22
+ needMap: this.sourceMap,
23
+ mode,
24
+ env
25
+ })
26
+ const {
27
+ getRequire
28
+ } = createHelpers(this)
29
+
30
+ if (parts.script) {
31
+ content = getRequire('script', parts.script)
32
+ } else {
33
+ content = ''
34
+ }
35
+ }
36
+
37
+ let output = 'global.isIndependent = true\n'
38
+ // 注入i18n
39
+ if (i18n) {
40
+ const i18nWxsPath = normalize.lib('runtime/i18n.wxs')
41
+ const i18nWxsLoaderPath = normalize.lib('wxs/i18n-loader.js')
42
+ const i18nWxsRequest = i18nWxsLoaderPath + '!' + i18nWxsPath
43
+ const i18nMethodsVar = 'i18nMethods'
44
+ this._module.addDependency(new CommonJsVariableDependency(i18nWxsRequest, i18nMethodsVar))
45
+
46
+ output += `if (!global.i18n) {
47
+ global.i18n = ${JSON.stringify({
48
+ locale: i18n.locale,
49
+ version: 0
50
+ })}
51
+ global.i18nMethods = ${i18nMethodsVar}
52
+ }\n`
53
+ }
54
+ output += content
55
+ output += '\n'
56
+ output += 'delete global.isIndependent\n'
57
+
58
+ return output
59
+ }
package/lib/index.js CHANGED
@@ -26,6 +26,7 @@ const PackageEntryPlugin = require('./resolver/PackageEntryPlugin')
26
26
  const AppEntryDependency = require('./dependencies/AppEntryDependency')
27
27
  const RecordResourceMapDependency = require('./dependencies/RecordResourceMapDependency')
28
28
  const RecordGlobalComponentsDependency = require('./dependencies/RecordGlobalComponentsDependency')
29
+ const RecordIndependentDependency = require('./dependencies/RecordIndependentDependency')
29
30
  const DynamicEntryDependency = require('./dependencies/DynamicEntryDependency')
30
31
  const FlagPluginDependency = require('./dependencies/FlagPluginDependency')
31
32
  const RemoveEntryDependency = require('./dependencies/RemoveEntryDependency')
@@ -77,30 +78,6 @@ const isChunkInPackage = (chunkName, packageName) => {
77
78
  return (new RegExp(`^${packageName}\\/`)).test(chunkName)
78
79
  }
79
80
 
80
- const getPackageCacheGroup = packageName => {
81
- if (packageName === 'main') {
82
- return {
83
- name: 'bundle',
84
- minChunks: 2,
85
- chunks: 'all'
86
- }
87
- } else {
88
- return {
89
- test: (module, { chunkGraph }) => {
90
- const chunks = chunkGraph.getModuleChunksIterable(module)
91
- return chunks.size && every(chunks, (chunk) => {
92
- return isChunkInPackage(chunk.name, packageName)
93
- })
94
- },
95
- name: `${packageName}/bundle`,
96
- minChunks: 2,
97
- minSize: 1000,
98
- priority: 100,
99
- chunks: 'all'
100
- }
101
- }
102
- }
103
-
104
81
  const externalsMap = {
105
82
  weui: /^weui-miniprogram/
106
83
  }
@@ -108,20 +85,19 @@ const externalsMap = {
108
85
  const warnings = []
109
86
  const errors = []
110
87
 
111
- // class EntryNode {
112
- // constructor (options) {
113
- // this.request = options.request
114
- // this.type = options.type
115
- // this.module = null
116
- // this.parents = new Set()
117
- // this.children = new Set()
118
- // }
119
- //
120
- // addChild (node) {
121
- // this.children.add(node)
122
- // node.parents.add(this)
123
- // }
124
- // }
88
+ class EntryNode {
89
+ constructor (module, type) {
90
+ this.module = module
91
+ this.type = type
92
+ this.parents = new Set()
93
+ this.children = new Set()
94
+ }
95
+
96
+ addChild (node) {
97
+ this.children.add(node)
98
+ node.parents.add(this)
99
+ }
100
+ }
125
101
 
126
102
  class MpxWebpackPlugin {
127
103
  constructor (options = {}) {
@@ -163,9 +139,6 @@ class MpxWebpackPlugin {
163
139
  options.transRpxRules = options.transRpxRules || null
164
140
  options.auditResource = options.auditResource || false
165
141
  options.decodeHTMLText = options.decodeHTMLText || false
166
- options.nativeOptions = Object.assign({
167
- cssLangs: ['css', 'less', 'stylus', 'scss', 'sass']
168
- }, options.nativeOptions)
169
142
  options.i18n = options.i18n || null
170
143
  options.checkUsingComponents = options.checkUsingComponents || false
171
144
  options.reportSize = options.reportSize || null
@@ -180,6 +153,10 @@ class MpxWebpackPlugin {
180
153
  include: () => true
181
154
  }
182
155
  options.customOutputPath = options.customOutputPath || null
156
+ options.nativeConfig = Object.assign({
157
+ cssLangs: ['css', 'less', 'stylus', 'scss', 'sass']
158
+ }, options.nativeConfig)
159
+ options.webConfig = options.webConfig || {}
183
160
  this.options = options
184
161
  }
185
162
 
@@ -339,6 +316,7 @@ class MpxWebpackPlugin {
339
316
  originalWriteFile(filePath, content, callback)
340
317
  }
341
318
  }
319
+
342
320
  const defs = this.options.defs
343
321
 
344
322
  const typeExtMap = config[this.options.mode].typeExtMap
@@ -360,6 +338,42 @@ class MpxWebpackPlugin {
360
338
 
361
339
  let mpx
362
340
 
341
+ const getPackageCacheGroup = packageName => {
342
+ if (packageName === 'main') {
343
+ return {
344
+ // 对于独立分包模块不应用该cacheGroup
345
+ test: (module) => {
346
+ let isIndependent = false
347
+ if (module.resource) {
348
+ const { queryObj } = parseRequest(module.resource)
349
+ isIndependent = !!queryObj.independent
350
+ } else {
351
+ const identifier = module.identifier()
352
+ isIndependent = /\|independent=/.test(identifier)
353
+ }
354
+ return !isIndependent
355
+ },
356
+ name: 'bundle',
357
+ minChunks: 2,
358
+ chunks: 'all'
359
+ }
360
+ } else {
361
+ return {
362
+ test: (module, { chunkGraph }) => {
363
+ const chunks = chunkGraph.getModuleChunksIterable(module)
364
+ return chunks.size && every(chunks, (chunk) => {
365
+ return isChunkInPackage(chunk.name, packageName)
366
+ })
367
+ },
368
+ name: `${packageName}/bundle`,
369
+ minChunks: 2,
370
+ minSize: 1000,
371
+ priority: 100,
372
+ chunks: 'all'
373
+ }
374
+ }
375
+ }
376
+
363
377
  const processSubpackagesEntriesMap = (compilation, callback) => {
364
378
  const mpx = compilation.__mpx__
365
379
  if (mpx && !isEmptyObject(mpx.subpackagesEntriesMap)) {
@@ -434,6 +448,9 @@ class MpxWebpackPlugin {
434
448
  compilation.dependencyFactories.set(RecordGlobalComponentsDependency, new NullFactory())
435
449
  compilation.dependencyTemplates.set(RecordGlobalComponentsDependency, new RecordGlobalComponentsDependency.Template())
436
450
 
451
+ compilation.dependencyFactories.set(RecordIndependentDependency, new NullFactory())
452
+ compilation.dependencyTemplates.set(RecordIndependentDependency, new RecordIndependentDependency.Template())
453
+
437
454
  compilation.dependencyFactories.set(CommonJsVariableDependency, normalModuleFactory)
438
455
  compilation.dependencyTemplates.set(CommonJsVariableDependency, new CommonJsVariableDependency.Template())
439
456
  })
@@ -468,10 +485,8 @@ class MpxWebpackPlugin {
468
485
  subpackagesEntriesMap: {},
469
486
  replacePathMap: {},
470
487
  exportModules: new Set(),
471
- // 记录entry依赖关系,用于体积分析
472
- entryNodesMap: {},
473
488
  // 记录entryModule与entryNode的对应关系,用于体积分析
474
- entryModulesMap: new Map(),
489
+ entryNodeModulesMap: new Map(),
475
490
  extractedMap: {},
476
491
  usingComponents: {},
477
492
  // todo es6 map读写性能高于object,之后会逐步替换
@@ -491,8 +506,10 @@ class MpxWebpackPlugin {
491
506
  transRpxRules: this.options.transRpxRules,
492
507
  postcssInlineConfig: this.options.postcssInlineConfig,
493
508
  decodeHTMLText: this.options.decodeHTMLText,
494
- // native文件专用相关配置
495
- nativeOptions: this.options.nativeOptions,
509
+ // native文件专用配置
510
+ nativeConfig: this.options.nativeConfig,
511
+ // 输出web专用配置
512
+ webConfig: this.options.webConfig,
496
513
  tabBarMap: {},
497
514
  defs: preProcessDefs(this.options.defs),
498
515
  i18n: this.options.i18n,
@@ -515,6 +532,15 @@ class MpxWebpackPlugin {
515
532
  compilation.addEntry(compiler.context, dep, { name }, callback)
516
533
  return dep
517
534
  },
535
+ getEntryNode: (module, type) => {
536
+ const entryNodeModulesMap = mpx.entryNodeModulesMap
537
+ let entryNode = entryNodeModulesMap.get(module)
538
+ if (!entryNode) {
539
+ entryNode = new EntryNode(module, type)
540
+ entryNodeModulesMap.set(module, entryNode)
541
+ }
542
+ return entryNode
543
+ },
518
544
  getOutputPath: (resourcePath, type, { ext = '', conflictPath = '' } = {}) => {
519
545
  const name = path.parse(resourcePath).name
520
546
  const hash = mpx.pathHash(resourcePath)
@@ -564,7 +590,7 @@ class MpxWebpackPlugin {
564
590
  const { resourcePath } = parseRequest(resource)
565
591
  const currentPackageRoot = mpx.currentPackageRoot
566
592
  const currentPackageName = currentPackageRoot || 'main'
567
- const isIndependent = mpx.independentSubpackagesMap[currentPackageRoot]
593
+ const isIndependent = !!mpx.independentSubpackagesMap[currentPackageRoot]
568
594
  const resourceMap = mpx[`${resourceType}sMap`] || mpx.otherResourcesMap
569
595
 
570
596
  if (!resourceMap.main) {
@@ -667,12 +693,14 @@ class MpxWebpackPlugin {
667
693
  const rawAddModule = compilation.addModule
668
694
  compilation.addModule = (module, callback) => {
669
695
  const issuerResource = module.issuerResource
670
- // 避免context module报错
671
- if (module.request && module.resource) {
696
+ const currentPackageRoot = mpx.currentPackageRoot
697
+ const independent = mpx.independentSubpackagesMap[currentPackageRoot]
698
+
699
+ if (module.resource) {
700
+ // NormalModule
672
701
  const isStatic = isStaticModule(module)
673
- const isIndependent = mpx.independentSubpackagesMap[mpx.currentPackageRoot]
674
702
 
675
- let needPackageQuery = isStatic || isIndependent
703
+ let needPackageQuery = isStatic || independent
676
704
 
677
705
  if (!needPackageQuery) {
678
706
  const { resourcePath } = parseRequest(module.resource)
@@ -692,12 +720,23 @@ class MpxWebpackPlugin {
692
720
  }
693
721
  })
694
722
  if (packageRoot) {
695
- module.request = addQuery(module.request, { packageRoot })
696
- module.resource = addQuery(module.resource, { packageRoot })
723
+ const queryObj = {
724
+ packageRoot
725
+ }
726
+ if (independent) queryObj.independent = independent
727
+ module.request = addQuery(module.request, queryObj)
728
+ module.resource = addQuery(module.resource, queryObj)
697
729
  }
698
730
  }
731
+ } else if (independent) {
732
+ // ContextModule和RawModule只在独立分包的情况下添加分包标记,其余默认不添加
733
+ const postfix = `|independent=${independent}|${currentPackageRoot}`
734
+ if (module._identifier) {
735
+ module._identifier += postfix
736
+ } else if (module.identifierStr) {
737
+ module.identifierStr += postfix
738
+ }
699
739
  }
700
-
701
740
  return rawAddModule.call(compilation, module, callback)
702
741
  }
703
742
 
@@ -1238,7 +1277,7 @@ try {
1238
1277
  })
1239
1278
  })
1240
1279
 
1241
- compiler.hooks.emit.tapAsync('MpxWebpackPlugin', (compilation, callback) => {
1280
+ compiler.hooks.emit.tap('MpxWebpackPlugin', (compilation) => {
1242
1281
  if (this.options.generateBuildMap) {
1243
1282
  const pagesMap = compilation.__mpx__.pagesMap
1244
1283
  const componentsPackageMap = compilation.__mpx__.componentsMap
@@ -1255,7 +1294,31 @@ try {
1255
1294
  }
1256
1295
  }
1257
1296
  }
1258
- callback()
1297
+ })
1298
+
1299
+ const clearFileCache = () => {
1300
+ const fs = compiler.intermediateFileSystem
1301
+ const cacheLocation = compiler.options.cache.cacheLocation
1302
+ return new Promise((resolve, reject) => {
1303
+ fs.rm(cacheLocation, {
1304
+ recursive: true,
1305
+ force: true
1306
+ }, (err) => {
1307
+ if (err) return reject(err)
1308
+ resolve()
1309
+ })
1310
+ })
1311
+ }
1312
+
1313
+ compiler.hooks.done.tapPromise('MpxWebpackPlugin', async () => {
1314
+ const cache = compiler.getCache('MpxWebpackPlugin')
1315
+ const cacheIsValid = await cache.getPromise('cacheIsValid', null)
1316
+ if (!cacheIsValid) {
1317
+ await Promise.all([
1318
+ clearFileCache(),
1319
+ cache.storePromise('cacheIsValid', null, true)
1320
+ ])
1321
+ }
1259
1322
  })
1260
1323
  }
1261
1324
  }
@@ -12,6 +12,7 @@ const getJSONContent = require('../utils/get-json-content')
12
12
  const createHelpers = require('../helpers')
13
13
  const createJSONHelper = require('./helper')
14
14
  const RecordGlobalComponentsDependency = require('../dependencies/RecordGlobalComponentsDependency')
15
+ const RecordIndependentDependency = require('../dependencies/RecordIndependentDependency')
15
16
  const { MPX_DISABLE_EXTRACTOR_CACHE, RESOLVE_IGNORED_ERR, JSON_JS_EXT } = require('../utils/const')
16
17
  const resolve = require('../utils/resolve')
17
18
 
@@ -263,13 +264,17 @@ module.exports = function (content) {
263
264
  },
264
265
  (result, content, callback) => {
265
266
  const extName = path.extname(result)
266
- if (extName === '.mpx' || extName === '.vue') {
267
+ if (extName === '.mpx') {
267
268
  const parts = parseComponent(content, {
268
269
  filePath: result,
269
270
  needMap: this.sourceMap,
270
271
  mode,
271
272
  env
272
273
  })
274
+ // 对于通过.mpx文件声明的独立分包,默认将其自身的script block视为init module
275
+ if (parts.script && queryObj.independent === true) {
276
+ queryObj.independent = result
277
+ }
273
278
  getJSONContent(parts.json || {}, this, (err, content) => {
274
279
  callback(err, result, content)
275
280
  })
@@ -346,6 +351,31 @@ module.exports = function (content) {
346
351
  return result
347
352
  }
348
353
 
354
+ const recordIndependent = (root, request) => {
355
+ this._module.addPresentationalDependency(new RecordIndependentDependency(root, request))
356
+ }
357
+
358
+ const processIndependent = (otherConfig, context, tarRoot, callback) => {
359
+ // 支付宝不支持独立分包,无需处理
360
+ const independent = otherConfig.independent
361
+ if (!independent || mode === 'ali') {
362
+ delete otherConfig.independent
363
+ return callback()
364
+ }
365
+ // independent配置为字符串时视为init module
366
+ if (typeof independent === 'string') {
367
+ otherConfig.independent = true
368
+ resolve(context, independent, this, (err, result) => {
369
+ if (err) return callback(err)
370
+ recordIndependent(tarRoot, result)
371
+ callback()
372
+ })
373
+ } else {
374
+ recordIndependent(tarRoot, true)
375
+ callback()
376
+ }
377
+ }
378
+
349
379
  // 为了获取资源的所属子包,该函数需串行执行
350
380
  const processSubPackage = (subPackage, context, callback) => {
351
381
  if (subPackage) {
@@ -357,26 +387,27 @@ module.exports = function (content) {
357
387
  let srcRoot = subPackage.srcRoot || subPackage.root || ''
358
388
  if (!tarRoot || subPackagesCfg[tarRoot]) return callback()
359
389
 
390
+ context = path.join(context, srcRoot)
360
391
  const otherConfig = getOtherConfig(subPackage)
361
- // 支付宝不支持独立分包,无需处理
362
- if (otherConfig.independent && mode !== 'ali') {
363
- mpx.independentSubpackagesMap[tarRoot] = true
364
- }
365
-
366
392
  subPackagesCfg[tarRoot] = {
367
393
  root: tarRoot,
368
- pages: [],
369
- ...otherConfig
394
+ pages: []
370
395
  }
371
- context = path.join(context, srcRoot)
372
396
  async.parallel([
397
+ (callback) => {
398
+ processIndependent(otherConfig, context, tarRoot, callback)
399
+ },
373
400
  (callback) => {
374
401
  processPages(subPackage.pages, context, tarRoot, callback)
375
402
  },
376
403
  (callback) => {
377
404
  processPlugins(subPackage.plugins, context, tarRoot, callback)
378
405
  }
379
- ], callback)
406
+ ], (err) => {
407
+ if (err) return callback(err)
408
+ Object.assign(subPackagesCfg[tarRoot], otherConfig)
409
+ callback()
410
+ })
380
411
  } else {
381
412
  callback()
382
413
  }
package/lib/loader.js CHANGED
@@ -15,6 +15,8 @@ const getJSONContent = require('./utils/get-json-content')
15
15
  const normalize = require('./utils/normalize')
16
16
  const getEntryName = require('./utils/get-entry-name')
17
17
  const AppEntryDependency = require('./dependencies/AppEntryDependency')
18
+ const RecordResourceMapDependency = require('./dependencies/RecordResourceMapDependency')
19
+ const CommonJsVariableDependency = require('./dependencies/CommonJsVariableDependency')
18
20
  const { MPX_APP_MODULE_ID } = require('./utils/const')
19
21
 
20
22
  module.exports = function (content) {
@@ -25,7 +27,9 @@ module.exports = function (content) {
25
27
  return content
26
28
  }
27
29
  const { resourcePath, queryObj } = parseRequest(this.resource)
28
- const packageName = queryObj.packageRoot || mpx.currentPackageRoot || 'main'
30
+ const packageRoot = queryObj.packageRoot || mpx.currentPackageRoot
31
+ const packageName = packageRoot || 'main'
32
+ const independent = queryObj.independent
29
33
  const pagesMap = mpx.pagesMap
30
34
  const componentsMap = mpx.componentsMap[packageName]
31
35
  const mode = mpx.mode
@@ -37,16 +41,6 @@ module.exports = function (content) {
37
41
  const vueContentCache = mpx.vueContentCache
38
42
  const autoScope = matchCondition(resourcePath, mpx.autoScopeRules)
39
43
 
40
- // 支持资源query传入isPage或isComponent支持页面/组件单独编译
41
- if ((queryObj.isComponent && !componentsMap[resourcePath]) || (queryObj.isPage && !pagesMap[resourcePath])) {
42
- const entryName = getEntryName(this)
43
- if (queryObj.isComponent) {
44
- componentsMap[resourcePath] = entryName || 'noEntryComponent'
45
- } else {
46
- pagesMap[resourcePath] = entryName || 'noEntryPage'
47
- }
48
- }
49
-
50
44
  let ctorType = 'app'
51
45
  if (pagesMap[resourcePath]) {
52
46
  // page
@@ -56,10 +50,17 @@ module.exports = function (content) {
56
50
  ctorType = 'component'
57
51
  }
58
52
 
53
+ // 支持资源query传入isPage或isComponent支持页面/组件单独编译
54
+ if (queryObj.isComponent || queryObj.isPage) {
55
+ const entryName = getEntryName(this) || (queryObj.isComponent ? 'noEntryComponent' : 'noEntryPage')
56
+ ctorType = queryObj.isComponent ? 'component' : 'page'
57
+ this._module.addPresentationalDependency(new RecordResourceMapDependency(resourcePath, ctorType, entryName, packageRoot))
58
+ }
59
+
59
60
  const loaderContext = this
60
61
  const stringifyRequest = r => loaderUtils.stringifyRequest(loaderContext, r)
61
62
  const isProduction = this.minimize || process.env.NODE_ENV === 'production'
62
- const filePath = resourcePath
63
+ const filePath = this.resourcePath
63
64
  const moduleId = ctorType === 'app' ? MPX_APP_MODULE_ID : 'm' + mpx.pathHash(filePath)
64
65
 
65
66
  const parts = parseComponent(content, {
@@ -69,6 +70,10 @@ module.exports = function (content) {
69
70
  env
70
71
  })
71
72
 
73
+ const {
74
+ getRequire
75
+ } = createHelpers(loaderContext)
76
+
72
77
  let output = ''
73
78
  const callback = this.async()
74
79
 
@@ -208,24 +213,36 @@ module.exports = function (content) {
208
213
  this._module.addPresentationalDependency(new AppEntryDependency(resourcePath, appName))
209
214
  }
210
215
 
211
- const {
212
- getRequire
213
- } = createHelpers(loaderContext)
214
-
215
216
  // 注入模块id及资源路径
216
217
  output += `global.currentModuleId = ${JSON.stringify(moduleId)}\n`
217
218
  if (!isProduction) {
218
219
  output += `global.currentResource = ${JSON.stringify(filePath)}\n`
219
220
  }
220
- if (ctorType === 'app' && i18n) {
221
- output += `global.i18n = ${JSON.stringify({ locale: i18n.locale, version: 0 })}\n`
222
221
 
222
+ // 为app注入i18n
223
+ if (i18n && ctorType === 'app') {
223
224
  const i18nWxsPath = normalize.lib('runtime/i18n.wxs')
224
225
  const i18nWxsLoaderPath = normalize.lib('wxs/i18n-loader.js')
225
226
  const i18nWxsRequest = i18nWxsLoaderPath + '!' + i18nWxsPath
227
+ const i18nMethodsVar = 'i18nMethods'
228
+ this._module.addDependency(new CommonJsVariableDependency(i18nWxsRequest, i18nMethodsVar))
229
+
230
+ output += `if (!global.i18n) {
231
+ global.i18n = ${JSON.stringify({
232
+ locale: i18n.locale,
233
+ version: 0
234
+ })}
235
+ global.i18nMethods = ${i18nMethodsVar}
236
+ }\n`
237
+ }
226
238
 
227
- output += `global.i18nMethods = require(${loaderUtils.stringifyRequest(loaderContext, i18nWxsRequest)})\n`
239
+ // 为独立分包注入init module
240
+ if (independent && typeof independent === 'string') {
241
+ const independentLoader = normalize.lib('independent-loader.js')
242
+ const independentInitRequest = `!!${independentLoader}!${independent}`
243
+ this._module.addDependency(new CommonJsVariableDependency(independentInitRequest))
228
244
  }
245
+
229
246
  // 注入构造函数
230
247
  let ctor = 'App'
231
248
  if (ctorType === 'page') {
@@ -295,28 +312,17 @@ module.exports = function (content) {
295
312
  // script
296
313
  output += '/* script */\n'
297
314
  let scriptSrcMode = srcMode
298
- const script = parts.script
315
+ // 给予script默认值, 确保生成js request以自动补全js
316
+ const script = parts.script || {}
299
317
  if (script) {
300
318
  scriptSrcMode = script.mode || scriptSrcMode
301
319
  if (scriptSrcMode) output += `global.currentSrcMode = ${JSON.stringify(scriptSrcMode)}\n`
302
- const extraOptions = {}
320
+ // 传递ctorType以补全js内容
321
+ const extraOptions = {
322
+ ctorType
323
+ }
303
324
  if (script.src) extraOptions.resourcePath = resourcePath
304
325
  output += getRequire('script', script, extraOptions) + '\n'
305
- } else {
306
- switch (ctorType) {
307
- case 'app':
308
- output += 'import {createApp} from "@mpxjs/core"\n' +
309
- 'createApp({})\n'
310
- break
311
- case 'page':
312
- output += 'import {createPage} from "@mpxjs/core"\n' +
313
- 'createPage({})\n'
314
- break
315
- case 'component':
316
- output += 'import {createComponent} from "@mpxjs/core"\n' +
317
- 'createComponent({})\n'
318
- }
319
- output += '\n'
320
326
  }
321
327
  callback(null, output)
322
328
  }
@@ -55,7 +55,7 @@ module.exports = function (content) {
55
55
  }
56
56
 
57
57
  function checkCSSLangFiles (callback) {
58
- const langs = mpx.nativeOptions.cssLangs || ['less', 'stylus', 'scss', 'sass']
58
+ const langs = mpx.nativeConfig.cssLangs || ['less', 'stylus', 'scss', 'sass']
59
59
  const results = []
60
60
  async.eachOf(langs, function (lang, i, callback) {
61
61
  if (!CSS_LANG_EXT_MAP[lang]) {
@@ -0,0 +1,11 @@
1
+ const parseRequest = require('./utils/parse-request')
2
+ const RecordResourceMapDependency = require('./dependencies/RecordResourceMapDependency')
3
+
4
+ module.exports = function (source) {
5
+ const mpx = this.getMpx()
6
+ const { resourcePath, queryObj } = parseRequest(this.resource)
7
+ const file = mpx.getExtractedFile(this.resource)
8
+ const packageRoot = queryObj.packageRoot || ''
9
+ this._module.addPresentationalDependency(new RecordResourceMapDependency(resourcePath, 'staticResource', file, packageRoot))
10
+ return source
11
+ }
@@ -36,7 +36,8 @@
36
36
  easingFunction: {
37
37
  type: String,
38
38
  default: 'default'
39
- }
39
+ },
40
+ scrollOptions: Object
40
41
  },
41
42
  data () {
42
43
  return {
@@ -90,11 +91,21 @@
90
91
  this.goto(val)
91
92
  }
92
93
  },
94
+ activated () {
95
+ if (this.bs && this.autoplay) {
96
+ this.bs.startPlay()
97
+ }
98
+ },
99
+ deactivated () {
100
+ if (this.bs && this.autoplay) {
101
+ this.bs.pausePlay()
102
+ }
103
+ },
93
104
  beforeCreate () {
94
105
  this.itemIds = []
95
106
  },
96
107
  mounted () {
97
- this.bs = new BScroll(this.$refs.wrapper, {
108
+ const originBsOptions = {
98
109
  scrollX: !this.vertical,
99
110
  scrollY: this.vertical,
100
111
  slide: {
@@ -103,14 +114,17 @@
103
114
  speed: this.duration,
104
115
  easing: this.easing,
105
116
  interval: this.interval,
106
- autoplay: this.autoplay
117
+ autoplay: this.autoplay,
118
+ startPageXIndex: this.vertical ? 0 : this.current,
119
+ startPageYIndex: this.vertical? this.current : 0
107
120
  },
108
121
  momentum: false,
109
122
  bounce: false,
110
123
  probeType: 3,
111
124
  stopPropagation: true
112
- })
113
-
125
+ }
126
+ const bsOptions = Object.assign({}, originBsOptions, this.scrollOptions)
127
+ this.bs = new BScroll(this.$refs.wrapper, bsOptions)
114
128
  this.bs.on('slideWillChange', (page) => {
115
129
  this.currentIndex = this.vertical ? page.pageY : page.pageX
116
130
  this.$emit('change', getCustomEvent('change', {
@@ -86,7 +86,7 @@
86
86
  }
87
87
 
88
88
  if (this.maxlength !== -1) {
89
- domProps.maxlength = this.maxlength
89
+ domProps.maxLength = this.maxlength
90
90
  }
91
91
 
92
92
  const data = {
package/lib/selector.js CHANGED
@@ -9,6 +9,7 @@ module.exports = function (content) {
9
9
  return content
10
10
  }
11
11
  const { queryObj } = parseRequest(this.resource)
12
+ const ctorType = queryObj.ctorType
12
13
  const type = queryObj.type
13
14
  const index = queryObj.index || 0
14
15
  const mode = mpx.mode
@@ -24,6 +25,26 @@ module.exports = function (content) {
24
25
  if (Array.isArray(part)) {
25
26
  part = part[index]
26
27
  }
28
+ if (!part) {
29
+ let content = ''
30
+ // 补全js内容
31
+ if (type === 'script') {
32
+ switch (ctorType) {
33
+ case 'app':
34
+ content += 'import {createApp} from "@mpxjs/core"\n' +
35
+ 'createApp({})\n'
36
+ break
37
+ case 'page':
38
+ content += 'import {createPage} from "@mpxjs/core"\n' +
39
+ 'createPage({})\n'
40
+ break
41
+ case 'component':
42
+ content += 'import {createComponent} from "@mpxjs/core"\n' +
43
+ 'createComponent({})\n'
44
+ }
45
+ }
46
+ part = { content }
47
+ }
27
48
  part = part || { content: '' }
28
49
  this.callback(null, part.content, part.map)
29
50
  }
@@ -23,6 +23,7 @@ module.exports = function (css, map) {
23
23
  const transRpxRulesRaw = mpx.transRpxRules
24
24
  const transRpxRules = transRpxRulesRaw ? (Array.isArray(transRpxRulesRaw) ? transRpxRulesRaw : [transRpxRulesRaw]) : []
25
25
 
26
+ const transRpxFn = mpx.webConfig.transRpxFn
26
27
  const testResolveRange = (include = () => true, exclude) => {
27
28
  return matchCondition(this.resourcePath, { include, exclude })
28
29
  }
@@ -38,15 +39,14 @@ module.exports = function (css, map) {
38
39
  },
39
40
  config.options
40
41
  )
41
- // ali环境处理host选择器
42
+ // ali平台下处理scoped和host选择器
42
43
  if (mode === 'ali') {
44
+ if (queryObj.scoped) {
45
+ plugins.push(scopeId({ id }))
46
+ }
43
47
  plugins.push(transSpecial({ id }))
44
48
  }
45
49
 
46
- if (queryObj.scoped) {
47
- plugins.push(scopeId({ id }))
48
- }
49
-
50
50
  plugins.push(pluginCondStrip({
51
51
  defs
52
52
  }))
@@ -68,7 +68,7 @@ module.exports = function (css, map) {
68
68
  }
69
69
 
70
70
  if (mpx.mode === 'web') {
71
- plugins.push(vw)
71
+ plugins.push(vw({ transRpxFn }))
72
72
  }
73
73
  // source map
74
74
  if (this.sourceMap && !options.map) {
@@ -5,12 +5,13 @@ const rpxRegExpG = /\b(\d+(\.\d+)?)rpx\b/g
5
5
  module.exports = postcss.plugin('vw', (options = {}) => root => {
6
6
  const rpx2vwRatio = +(100 / 750).toFixed(8)
7
7
 
8
+ const transRpxFn = options.transRpxFn && typeof options.transRpxFn === 'function' ? options.transRpxFn : function (match, $1) {
9
+ if ($1 === '0') return $1
10
+ return `${$1 * rpx2vwRatio}vw`
11
+ }
8
12
  function transVw (declaration) {
9
13
  if (rpxRegExp.test(declaration.value)) {
10
- declaration.value = declaration.value.replace(rpxRegExpG, function (match, $1) {
11
- if ($1 === '0') return $1
12
- return `${$1 * rpx2vwRatio}vw`
13
- })
14
+ declaration.value = declaration.value.replace(rpxRegExpG, transRpxFn)
14
15
  }
15
16
  }
16
17
 
@@ -2039,7 +2039,10 @@ function processElement (el, root, options, meta) {
2039
2039
 
2040
2040
  const pass = isNative || processTemplate(el) || processingTemplate
2041
2041
 
2042
- processScoped(el, options)
2042
+ // 仅ali平台需要scoped模拟样式隔离
2043
+ if (mode === 'ali') {
2044
+ processScoped(el, options)
2045
+ }
2043
2046
 
2044
2047
  if (transAli) {
2045
2048
  processAliExternalClassesHack(el, options)
@@ -132,7 +132,7 @@ module.exports = function (json, {
132
132
  },
133
133
  (result, content, callback) => {
134
134
  const extName = path.extname(result)
135
- if (extName === '.mpx' || extName === '.vue') {
135
+ if (extName === '.mpx') {
136
136
  const parts = parseComponent(content, {
137
137
  filePath: result,
138
138
  needMap: loaderContext.sourceMap,
@@ -113,12 +113,6 @@ module.exports = function (script, {
113
113
  import Vue from 'vue'
114
114
  import VueRouter from 'vue-router'
115
115
  Vue.use(VueRouter)
116
- import BScroll from '@better-scroll/core'
117
- import PullDown from '@better-scroll/pull-down'
118
- import ObserveDOM from '@better-scroll/observe-dom'
119
- BScroll.use(ObserveDOM)
120
- BScroll.use(PullDown)
121
- global.BScroll = BScroll
122
116
  global.getApp = function(){}
123
117
  global.getCurrentPages = function(){
124
118
  if(!global.__mpxRouter) return []
@@ -216,11 +210,11 @@ module.exports = function (script, {
216
210
  content += ` global.currentResource = ${JSON.stringify(loaderContext.resourcePath)}\n`
217
211
  }
218
212
  // 为了正确获取currentSrcMode便于运行时进行转换,对于src引入的组件script采用require方式引入(由于webpack会将import的执行顺序上升至最顶),这意味着对于src引入脚本中的named export将不会生效,不过鉴于mpx和小程序中本身也没有在组件script中声明export的用法,所以应该没有影响
219
- content += '\n\n\n/** ====== Source start ====== **/\n'
213
+ content += '\n\n\n/** Source start **/\n'
220
214
  content += script.src
221
215
  ? `require(${stringifyRequest(script.src)})\n`
222
216
  : script.content
223
- content += '\n/** ====== Source end ====== **/\n\n\n'
217
+ content += '\n/** Source end **/\n\n\n'
224
218
  // createApp/Page/Component执行完成后立刻获取当前的option并暂存
225
219
  content += ` const currentOption = global.currentOption\n`
226
220
  // 获取pageConfig
@@ -39,11 +39,16 @@ module.exports = function (content) {
39
39
  let results = targetPath.unshiftContainer('body', insertNodes) || []
40
40
  targetPath.inserted = true
41
41
  results.forEach((item) => {
42
- item.stop()
42
+ item.shouldStopTraverse = true
43
43
  })
44
44
  }
45
45
  }
46
46
  },
47
+ ForStatement (path) {
48
+ if (path.shouldStopTraverse) {
49
+ path.stop()
50
+ }
51
+ },
47
52
  // 处理vant-aliapp中export var bem = bem;这种不被acorn支持的2b语法
48
53
  ExportNamedDeclaration (path) {
49
54
  if (
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mpxjs/webpack-plugin",
3
- "version": "2.7.0-beta.8",
3
+ "version": "2.7.1-beta.1",
4
4
  "description": "mpx compile core",
5
5
  "keywords": [
6
6
  "mpx"
@@ -77,5 +77,8 @@
77
77
  "@types/babel-traverse": "^6.25.4",
78
78
  "@types/babel-types": "^7.0.4"
79
79
  },
80
- "gitHead": "73247d266ae7380b88295208d645f85b9dd72398"
80
+ "engines": {
81
+ "node": ">=14.14.0"
82
+ },
83
+ "gitHead": "0ea8bcfff2ccfc433cb2ce43275b7e2af2bc8a61"
81
84
  }