uniapp如何解决微信小程序跨分包引入组件的问题?

3,921 阅读1分钟

一个分包使用其他分包的自定义组件时,由于其他分包还未下载或注入,其他分包的组件处于不可用的状态。通过为其他分包的自定义组件设置 占位组件,我们可以先渲染占位组件作为替代,在分包下载完成后再进行替换 假如我们有两个分包A和B,如果A分包中页面需要引入B包中的组定义组件,我们可以在页面对应的配置文件pages.json文件中添加componentPlaceholder属性,但是对于A分包中的组件需要引入B包中的自定义组件,由于uniapp没有针对自定义组件创建配置文件,我们需要自定义webpack插件对编译完成的资源进行处理,注入componentPlaceholder属性,我们创建一个webpack插件,placeholder-plugin.js,代码如下:

const fs = require('fs')
const chalk = require('chalk')
const process = require('process')
const pluginId = 'component-placeholder-plugin'
const validateOptions = require('schema-utils')
const schemaPlaceholderPluginOption = require('./schemaPlaceholderPluginOption.json')
const schemaPlaceholderOptionChild = require('./schemaPlaceholderOptionChild.json')
class ComponentPlaceholder {
	constructor(option) {
		validateOptions(schemaPlaceholderPluginOption, option, '插件名称:' + pluginId)
		this.option = option
	}
	apply(compiler) {
		compiler.hooks.afterEmit.tapAsync(pluginId, (compiler, cb) => {
			this.option.fileList.forEach((item) => {
				try {
					validateOptions(schemaPlaceholderOptionChild, item, '插件名称:' + pluginId)
				} catch (e) {
					console.error(chalk.red('插件名称:' + pluginId + '中的fileList字段中的子项校验失败,请检查'))
					process.exit()
				}

				let exist = fs.existsSync(item.filePath)
				if (exist) {
					let data = this.getFileContent(item)
					this.setFileContent(item.filePath, data)
				}
			})
			cb()
		})
	}
	getFileContent(item) {
		let str = fs.readFileSync(item.filePath)
		let data = JSON.parse(str)
		if (data.componentPlaceholder) {
			data.componentPlaceholder = { ...data.componentPlaceholder, ...item.componentPlaceholder }
		} else {
			data.componentPlaceholder = item.componentPlaceholder
		}
		return JSON.stringify(data)
	}
	setFileContent(filePath, data) {
		try {
			fs.writeFileSync(filePath, data)
		} catch (e) {
			console.log('目标文件:' + filePath + '更改失败')
		}
	}
}
module.exports = ComponentPlaceholder

vue.config.js中我们引入placeholder-plugin.js

const placeholderConfig = require('./loaders/placeholderConfig.js')
// 
registerComponentPlaceholderPlugin(config, 'dist/dev/')
function registerComponentPlaceholderPlugin(config, targetDir) {
// 注意这里config是chainWebpack的返回的config, targetDir: 开发环境的目录,生产环境改成dist/build
	const params = placeholderConfig('../' + targetDir)
	config.plugin('component-placeholder-plugin').use(new ComponentPlaceholderPlugin({
		fileList: [{
                    filePath: path.resolve(__dirname, targetDir + '/pages/list/index.json'),
                    componentPlaceholder: {
                        'area-com': 'view'
                    }
		}]
          })
    )
}