From 9cacd59ae29fb72ca1a34269fa002ea36ac67cba Mon Sep 17 00:00:00 2001 From: songyu Date: Mon, 13 Mar 2023 19:32:46 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=94=AF=E6=8C=81=E5=BE=AE=E4=BF=A1?= =?UTF-8?q?=E5=B0=8F=E7=A8=8B=E5=BA=8Frequire.async()=E8=AF=AD=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/uni-mp-weixin/lib/index.js | 13 ++++++ ...quireAsyncDependenciesBlockParserPlugin.js | 44 +++++++++++++++++++ .../RequireAsyncDependency.js | 23 ++++++++++ .../RequireAsyncPlugin.js | 29 ++++++++++++ packages/vue-cli-plugin-uni/lib/mp/index.js | 6 +-- .../vue-cli-plugin-uni/lib/split-chunks.js | 22 ++++++++++ 6 files changed, 134 insertions(+), 3 deletions(-) create mode 100644 packages/uni-mp-weixin/lib/index.js create mode 100644 packages/uni-mp-weixin/lib/support-require-async/RequireAsyncDependenciesBlockParserPlugin.js create mode 100644 packages/uni-mp-weixin/lib/support-require-async/RequireAsyncDependency.js create mode 100644 packages/uni-mp-weixin/lib/support-require-async/RequireAsyncPlugin.js diff --git a/packages/uni-mp-weixin/lib/index.js b/packages/uni-mp-weixin/lib/index.js new file mode 100644 index 0000000000..7c7204457f --- /dev/null +++ b/packages/uni-mp-weixin/lib/index.js @@ -0,0 +1,13 @@ + +const createWxMpIndependentPlugins = require('./createIndependentPlugin') +const RequireAsyncPlugin = require('./support-require-async/RequireAsyncPlugin') + +module.exports = function createWxMpPlugins () { + if (process.env.UNI_PLATFORM === 'mp-weixin') { + return [ + ...createWxMpIndependentPlugins(), + new RequireAsyncPlugin() + ] + } + return [] +} diff --git a/packages/uni-mp-weixin/lib/support-require-async/RequireAsyncDependenciesBlockParserPlugin.js b/packages/uni-mp-weixin/lib/support-require-async/RequireAsyncDependenciesBlockParserPlugin.js new file mode 100644 index 0000000000..a0c46340bb --- /dev/null +++ b/packages/uni-mp-weixin/lib/support-require-async/RequireAsyncDependenciesBlockParserPlugin.js @@ -0,0 +1,44 @@ +const AsyncDependenciesBlock = require('webpack/lib/AsyncDependenciesBlock') +const RequireAsyncDependency = require('./RequireAsyncDependency') + +class RequireAsyncDependenciesBlock extends AsyncDependenciesBlock { + constructor (request, range, groupOptions, module, loc, originModule) { + super(groupOptions, module, loc, request) + this.range = range + const dep = new RequireAsyncDependency(request, originModule, this) + dep.loc = loc + this.addDependency(dep) + } +} + +module.exports = class RequireAsyncDependenciesBlockParserPlugin { + constructor (options) { + this.options = options + } + + apply (parser) { + parser.hooks.call + .for('require.async').tap('RequireAsyncDependenciesBlockParserPlugin', expr => { + const param = parser.evaluateExpression(expr.arguments[0]) + + const { options: importOptions } = parser.parseCommentOptions(expr.range) + let chunkName = null + if (importOptions && importOptions.webpackChunkName !== undefined) { + chunkName = importOptions.webpackChunkName + } + const groupOptions = { name: chunkName } + + const depBlock = new RequireAsyncDependenciesBlock( + param.string, + expr.range, + groupOptions, + parser.state.module, + expr.loc, + parser.state.module + ) + + parser.state.current.addBlock(depBlock) + return true + }) + } +} diff --git a/packages/uni-mp-weixin/lib/support-require-async/RequireAsyncDependency.js b/packages/uni-mp-weixin/lib/support-require-async/RequireAsyncDependency.js new file mode 100644 index 0000000000..c083c6265b --- /dev/null +++ b/packages/uni-mp-weixin/lib/support-require-async/RequireAsyncDependency.js @@ -0,0 +1,23 @@ +const path = require('path') +const ImportDependency = require('webpack/lib/dependencies/ImportDependency') + +class RequireAsyncDependency extends ImportDependency { + +}; + +RequireAsyncDependency.Template = class ImportDependencyTemplate { + apply (dep, source, runtime) { + let content = runtime.moduleExports({ + module: dep.module, + request: dep.request + }) + + // 目前只支持相对路径引用 + const relativePath = path.relative(dep.originModule.context, dep.module.userRequest) + // 利用 require.async 加载分包中的资源,取代web环境下的 __webpack_require__.e(...) + content = `require.async("${relativePath}").then(function(){return ${content} })` + source.replace(dep.block.range[0], dep.block.range[1] - 1, content) + } +} + +module.exports = RequireAsyncDependency diff --git a/packages/uni-mp-weixin/lib/support-require-async/RequireAsyncPlugin.js b/packages/uni-mp-weixin/lib/support-require-async/RequireAsyncPlugin.js new file mode 100644 index 0000000000..0b358aad33 --- /dev/null +++ b/packages/uni-mp-weixin/lib/support-require-async/RequireAsyncPlugin.js @@ -0,0 +1,29 @@ + +const RequireAsyncDependenciesBlockParserPlugin = require('./RequireAsyncDependenciesBlockParserPlugin') +const RequireAsyncDependency = require('./RequireAsyncDependency') + +class RequireAsyncPlugin { + constructor(options) { + this.options = options + } + + apply(compiler) { + const options = this.options + compiler.hooks.compilation.tap('RequireAsyncPlugin', + + (compilation, { normalModuleFactory }) => { + compilation.dependencyFactories.set(RequireAsyncDependency, normalModuleFactory) + compilation.dependencyTemplates.set(RequireAsyncDependency, new RequireAsyncDependency.Template()) + + const handler = (parser, parserOptions) => { + new RequireAsyncDependenciesBlockParserPlugin(options).apply(parser) + } + + normalModuleFactory.hooks.parser.for('javascript/auto').tap('RequireAsyncDependenciesBlockParserPlugin', handler) + normalModuleFactory.hooks.parser.for('javascript/dynamic').tap('RequireAsyncDependenciesBlockParserPlugin', handler) + normalModuleFactory.hooks.parser.for('javascript/esm').tap('RequireAsyncDependenciesBlockParserPlugin', handler) + } + ) + } +} +module.exports = RequireAsyncPlugin diff --git a/packages/vue-cli-plugin-uni/lib/mp/index.js b/packages/vue-cli-plugin-uni/lib/mp/index.js index 2b1d5c4fb7..d3be8c68d4 100644 --- a/packages/vue-cli-plugin-uni/lib/mp/index.js +++ b/packages/vue-cli-plugin-uni/lib/mp/index.js @@ -27,7 +27,7 @@ function createUniMPPlugin () { return new WebpackUniMPPlugin() } -const createWxMpIndependentPlugins = require('@dcloudio/uni-mp-weixin/lib/createIndependentPlugin') +const createWxMpPlugins = require('@dcloudio/uni-mp-weixin/lib/index') const UniTips = require('./tips') @@ -192,7 +192,7 @@ module.exports = { new WebpackUniAppPlugin(), createUniMPPlugin(), new webpack.ProvidePlugin(getProvides()), - ...createWxMpIndependentPlugins() + ...createWxMpPlugins() ] if ((process.env.UNI_SUBPACKGE || process.env.UNI_MP_PLUGIN) && process.env.UNI_SUBPACKGE !== 'main') { @@ -361,4 +361,4 @@ ${globalEnv}.__webpack_require_UNI_MP_PLUGIN__ = __webpack_require__;` webpackConfig.plugins.delete('preload') webpackConfig.plugins.delete('prefetch') } -} +} diff --git a/packages/vue-cli-plugin-uni/lib/split-chunks.js b/packages/vue-cli-plugin-uni/lib/split-chunks.js index dbc7eee481..e670336198 100644 --- a/packages/vue-cli-plugin-uni/lib/split-chunks.js +++ b/packages/vue-cli-plugin-uni/lib/split-chunks.js @@ -10,6 +10,7 @@ const independentFilter = ({ independent }) => independent const map2Root = ({ root }) => root + '/' const normalSubPackageRoots = subPkgsInfo.filter(normalFilter).map(map2Root) const independentSubpackageRoots = subPkgsInfo.filter(independentFilter).map(map2Root) +const RequireAsyncDependency = require('@dcloudio/uni-mp-weixin/lib/support-require-async/RequireAsyncDependency') function createCacheGroups () { const cacheGroups = {} @@ -87,6 +88,13 @@ module.exports = function getSplitChunks () { if (module.type === 'css/mini-extract') { return false } + + // require.async()的模块不应该被分割 + const reason = (module && module.reasons && module.reasons[0]) || {} + if (reason.dependency instanceof RequireAsyncDependency) { + return false + } + if (module.resource && ( module.resource.indexOf('.vue') !== -1 || module.resource.indexOf('.nvue') !== -1 || @@ -139,6 +147,13 @@ module.exports = function getSplitChunks () { if (!baseTest(module)) { return false } + + // require.async()的模块不应该被分割 + const reason = (module && module.reasons && module.reasons[0]) || {} + if (reason.dependency instanceof RequireAsyncDependency) { + return false + } + chunks = getModuleChunks(module, chunks) const matchSubPackages = findSubPackages(chunks) const matchSubPackagesCount = matchSubPackages.size @@ -220,6 +235,13 @@ module.exports = function getSplitChunks () { if (!baseTest(module)) { return false } + + // require.async()的模块不应该被分割 + const reason = (module && module.reasons && module.reasons[0]) || {} + if (reason.dependency instanceof RequireAsyncDependency) { + return false + } + chunks = getModuleChunks(module, chunks) const matchSubPackages = findSubPackages(chunks) if (