背景
参考问题:uniapp开发微信小程序如何使用分包异步化特性,目前(2022/02/07)uniapp中的pages.json配置不支持分包异步化的特性(按照微信官方文档配置,构建后并不会在app.json文件生成对应的配置,猜测是因为分包异步化中的pages为空,构建代码过滤了,有空查看构建源码确认一下)。
这里应该由uniapp官方支持一下这个功能,目前项目需要,先用下面的临时方案
解决方案
思路:在uniapp构建完成后,添加自己的构建脚本,做以下的事情
- 读取pages.json
- 判断pages.json中是否有配置分包异步化
- 把分包异步化相关配置写入app.json
- 寻找用到分包组件的地方(小程序的页面 or 组件json配置文件),注入组件占位(不注入的话小程序会报错导致分包内组件无法使用)
构建脚本源码
/* eslint-disable @typescript-eslint/no-require-imports */
const fs = require('fs');
const path = require('path');
console.log('开始处理异步化分包...');
// 读取pages.json
const pagesConfig = (() => {
const configPath = path.resolve(__dirname, '../../../pages.json'); // @NOTE 这里要根据脚本执行的路径改一下
const pages = fs.readFileSync(configPath, 'utf8');
// @NOTE 移除注释
let pagesJson = pages.replace(/\/\*.*\*\//g, '');
pagesJson = pagesJson.replace(/\/\/.*/g, '');
return JSON.parse(pagesJson);
})();
// 读取page.json中的异步分包(没有配置pages)
const asyncPackages = (pagesConfig.subPackages || []).filter(package => !package.pages || package.pages.length === 0);
// console.log(pagesConfig, asyncPackages);
// 写入app.json
const distPath = path.resolve(__dirname, '../../../../dist/build/mp-weixin'); // @NOTE 这里要根据脚本执行的路径改一下
const appJsonPath = path.resolve(distPath, 'app.json');
const appJson = JSON.parse(fs.readFileSync(appJsonPath, 'utf8'));
if (!appJson.subPackages) {
appJson.subPackages = [];
}
asyncPackages.forEach((package) => {
const hasInject = appJson.subPackages.find(pack => pack.root === package.root);
if (hasInject) {
return;
}
appJson.subPackages.push({
root: package.root,
pages: [],
});
});
fs.writeFileSync(appJsonPath, JSON.stringify(appJson));
// 寻找用到分包组件的地方,注入组件占位(不注入的话小程序会报错导致分包内组件无法使用)
const ignorePaths = [];
ignorePaths.push(appJsonPath); // 过滤app.json
asyncPackages.forEach((package) => {
ignorePaths.push(path.join(distPath, package.root)); // 过滤分包的内容
});
const injectPlaceholder = (filepath) => {
// 判断是否用到了分包的组件
const jsonConfig = require(filepath);
if (!jsonConfig.usingComponents) {
return;
}
const subPackageComponents = [];
// @TODO 可以考虑使用map来加快查找速度
Object.keys(jsonConfig.usingComponents).forEach((componentName) => {
const componentPath = jsonConfig.usingComponents[componentName];
const targetSubPackage = asyncPackages.find(package => componentPath.startsWith(`/${package.root}`));
if (targetSubPackage) {
// 防止重复添加
// eslint-disable-next-line @typescript-eslint/prefer-optional-chain
if (jsonConfig.componentPlaceholder && jsonConfig.componentPlaceholder[componentName]) {
return;
}
subPackageComponents.push(componentName);
}
});
if (subPackageComponents.length === 0) {
return;
}
console.log('开始处理: ', filepath);
if (!jsonConfig.componentPlaceholder) {
jsonConfig.componentPlaceholder = {};
}
subPackageComponents.forEach((name) => {
jsonConfig.componentPlaceholder[name] = 'view'; // 占位符全用view组件
});
fs.writeFileSync(filepath, JSON.stringify(jsonConfig));
console.log('处理完成: ', filepath);
};
findJSON(distPath, ignorePaths, injectPlaceholder);
console.log('异步化分包处理完成');
function findJSON(folder, ignorePaths, cb) {
fs.readdirSync(folder).forEach((filename) => {
const filepath = path.join(folder, filename);
const isIgnore = ignorePaths.some(ignorePath => filepath.startsWith(ignorePath));
if (isIgnore) {
return;
}
const stat = fs.statSync(filepath);
if (filename.endsWith('.json')) {
cb(filepath);
return;
}
if (stat.isDirectory()) {
findJSON(filepath, ignorePaths, cb);
}
});
}
最后
目前用这个方式解决了分包异步化中使用分包内的组件问题,至于分包内的js使用,大家可以验证一下,我暂时没有这个场景,所以没有验证。
上面的代码编写没有review,但测试过单个分包配置的场景,项目使用的时候请谨慎。
最后还是希望官方大佬支持一下分包异步化这个特性。
21 个评论
要回复文章请先登录或注册
1***@qq.com
1***@qq.com
j***@163.com
1***@qq.com
1***@qq.com
DDante
3***@qq.com
3***@qq.com
3***@qq.com
DDante