黑客与画家
黑客与画家
  • 发布:2022-02-07 18:43
  • 更新:2024-01-23 16:36
  • 阅读:9684

uniapp使用微信小程序分包异步化能力临时方案

分类:uni-app

背景

参考问题:uniapp开发微信小程序如何使用分包异步化特性,目前(2022/02/07)uniapp中的pages.json配置不支持分包异步化的特性(按照微信官方文档配置,构建后并不会在app.json文件生成对应的配置,猜测是因为分包异步化中的pages为空,构建代码过滤了,有空查看构建源码确认一下)。

这里应该由uniapp官方支持一下这个功能,目前项目需要,先用下面的临时方案

解决方案

思路:在uniapp构建完成后,添加自己的构建脚本,做以下的事情

  1. 读取pages.json
  2. 判断pages.json中是否有配置分包异步化
  3. 把分包异步化相关配置写入app.json
  4. 寻找用到分包组件的地方(小程序的页面 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,但测试过单个分包配置的场景,项目使用的时候请谨慎。

最后还是希望官方大佬支持一下分包异步化这个特性。

11 关注 分享
L***@163.com 2***@qq.com 1***@qq.com 1***@qq.com dashuai 1***@qq.com z***@163.com DDante 1***@qq.com 1***@qq.com HRK_01

要回复文章请先登录注册

我愿你知道

我愿你知道

回复 dashuai :
我根据我们公司的项目形式写了个小demo,能麻烦您看下吗?https://ask.dcloud.net.cn/question/152261
2022-08-30 09:11
dashuai

dashuai

回复 我愿你知道 :
如果js体积是大 的,只分包用,把js放组件里,组件分包,调用试试; 否则,放一般文件夹里
2022-08-30 00:22
我愿你知道

我愿你知道

回复 dashuai :
请问下,为什么我主包引用了分包中的js但还是报错,获取不到分包中js文件
2022-08-29 16:20
dashuai

dashuai

回复 黑客与画家 :
我经过几天的尝试(方法: 组件手动引入和注册,json文件中加占位组件),我把组件全都分离到单独的包了(但不完美,还有各种没有必须要的提醒),主包一下小了很多,心里舒服多了;js文件想分包出去,各种试,都没有成功,主要是uniapp不支持异步调用js,期待官方支持异步js,如果你解决了js异步包,请分享一下哈。220504
2022-05-04 23:32
黑客与画家

黑客与画家 (作者)

回复 dashuai :
要看你具体是怎么引用的。是直接import进来,还是require.async('../commonPackage/index.js')(参考微信官方文档)这种方法导入的?我这里只是实现了分包异步化中的组件使用。js的话可能要再试试。
2022-05-04 23:20
dashuai

dashuai

我试了一下分包内的js,只要主包引用了这个js,js就会被打包到主包里。这样还是不能减少分包的体积。
2022-04-28 23:19
1***@qq.com

1***@qq.com

大佬,有没有demo
2022-04-24 11:31
1***@qq.com

1***@qq.com

怎么进行配置呢
2022-04-24 11:22
1***@qq.com

1***@qq.com

大佬这个怎么配置运行呢
2022-04-18 23:34
2***@qq.com

2***@qq.com

看到新版微信开发者工具生成预览二维码时有个“代码质量”,发现“启用组件按需注入”这一项没有检测通过,希望uniapp官方能及时更新,支持微信的这个特性
2022-03-16 14:14