const path = require('path') const webpack = require('webpack') const { parseEntry, normalizePath } = require('@dcloudio/uni-cli-shared') const { pagesJsonJsFileName } = require('@dcloudio/uni-cli-shared/lib/pages') const { createSource, getModuleId } = require('../shared') const generateApp = require('./generate-app') const generateJson = require('./generate-json') const generateComponent = require('./generate-component') const clearStyleFile = require('./clear-style-file') const mockGenericComponent = require('./mock-generic-component') const addEmptyComponent = require('./add-empty-component') const addPluginWrapper = require('./add-plugin-wrapper') function emitFile (filePath, source, compilation) { compilation.emitAsset(filePath, createSource(source)) } function addSubPackagesRequire (compilation) { if (!process.env.UNI_OPT_SUBPACKAGES) { return } const assetsKeys = Object.keys(compilation.assets) Object.keys(process.UNI_SUBPACKAGES).forEach(root => { const subPackageVendorPath = normalizePath(path.join(root, 'common/vendor.js')) if (assetsKeys.indexOf(subPackageVendorPath) !== -1) { // TODO 理论上仅需在分包第一个 js 中添加 require common vendor,但目前不同平台可能顺序不一致, // 故 每个分包里的 js 里均添加一次 require assetsKeys.forEach(name => { if ( path.extname(name) === '.js' && name.indexOf(root + '/') === 0 && name !== subPackageVendorPath ) { let relativePath = normalizePath(path.relative(path.dirname(name), subPackageVendorPath)) if (!relativePath.startsWith('.')) { relativePath = './' + relativePath } const source = `require('${relativePath}');` + compilation.getAsset(name).source.source() compilation.updateAsset(name, createSource(source)) } }) } }) } function addMPPluginRequire (compilation) { // 编译到小程序插件 特殊处理入口文件 const assetsKeys = Object.keys(compilation.assets) const UNI_MP_PLUGIN_MAIN = process.env.UNI_MP_PLUGIN_MAIN const UNI_MP_PLUGIN_EXPORT = JSON.parse(process.env.UNI_MP_PLUGIN_EXPORT) assetsKeys.forEach(name => { const needProcess = process.env.UNI_MP_PLUGIN ? name === UNI_MP_PLUGIN_MAIN : UNI_MP_PLUGIN_EXPORT.includes(name) if (needProcess) { const modules = Array.from(compilation.modules) const orignalSource = compilation.getAsset(name).source.source() const globalEnv = process.env.UNI_PLATFORM === 'mp-alipay' ? 'my' : 'wx' const filePath = normalizePath(path.resolve(process.env.UNI_INPUT_DIR, name)) let uniModule = modules.find(module => module.resource && normalizePath(module.resource) === filePath) if (!uniModule && webpack.version[0] > 4) { uniModule = modules.find(module => module.rootModule && module.rootModule.resource && normalizePath(module.rootModule.resource) === filePath ) } const uniModuleId = getModuleId(compilation, uniModule) const source = orignalSource + `\nmodule.exports = ${globalEnv}.__webpack_require_UNI_MP_PLUGIN__('${uniModuleId}');\n` compilation.updateAsset(name, createSource(source)) } }) } function processAssets (compiler, compilation) { addSubPackagesRequire(compilation) addMPPluginRequire(compilation) generateJson(compilation) // app.js,app.wxss generateApp(compilation) .forEach(({ file, source }) => emitFile(file, source, compilation)) generateComponent(compilation, compiler.options.output[webpack.version[0] > 4 ? 'chunkLoadingGlobal' : 'jsonpFunction']) clearStyleFile(compilation) mockGenericComponent(compilation) addEmptyComponent(compilation) addPluginWrapper(compilation) } class WebpackUniMPPlugin { apply (compiler) { if (!process.env.UNI_USING_NATIVE && !process.env.UNI_USING_V3_NATIVE) { if (webpack.version[0] > 4) { compiler.hooks.compilation.tap('WebpackUniMPPlugin', compilation => { compilation.hooks.processAssets.tap({ name: 'WebpackUniMPPlugin', stage: webpack.Compilation.PROCESS_ASSETS_STAGE_ADDITIONAL }, (_) => { processAssets(compiler, compilation) }) }) } else { compiler.hooks.emit.tap('webpack-uni-mp-emit', (compilation) => processAssets(compiler, compilation)) } } compiler.hooks.invalid.tap('webpack-uni-mp-invalid', (fileName, changeTime) => { if ( fileName && typeof fileName === 'string' ) { // 重新解析 entry const basename = path.basename(fileName) const deps = process.UNI_PAGES_DEPS || new Set() if ( basename === 'pages.json' || basename === pagesJsonJsFileName || deps.has(normalizePath(fileName)) ) { try { parseEntry() } catch (e) { console.error(e) } } } }) } } module.exports = WebpackUniMPPlugin