多单页应用的构建优化-按entry拆分构建

一、目的

多单页应用的仓库体积相对较大,而往往开发分支涉及的改动仅会影响其中的少数页面,因此无论是开发时还是生产时,都有必要去做选择性的前端代码构建。

二、原理

以webpack为例,在构建过程中,会根据entry配置,在指定目录下寻找main文件作为入口文件进行依赖树构建以及打包。当应用中存在多个单页也就是多个main文件时,排除其中不想打包的main文件,或者指定想打包的main文件,即可实现开发时按enrty拆分构建。

三、实现方案

使用IgnorePlugin,排除非指定main入口

module.exports = {
  plugins: [
    new webpack.IgnorePlugin({
      checkResource(resource, context) {
        // 获取绝对路径
        const absolutePath = path.resolve(context, resource);

        // 排除所有/pages下非目标页面的main文件
        return (
          absolutePath.includes('/pages/') &&
          absolutePath.includes('main') &&
          !absolutePath.includes(targetPage)
        );
      },
    }),
  ],
};

直接修改entry,构建指定main入口

module.exports = {
  entry: [
    {
      files: entryFiles,
    },
  ],
}

四、应用场景

开发时构建

开发时,确定开发影响的单页,以命令行参数的形式传给webpack.config.js即可

实例代码:

# 命令行去指定 entry
yarn dev --entry=./src/anotherEntry.js
const path = require('path');

// 消费 entry
const argv = process.argv.slice(2);
const entryIndex = argv.findIndex(arg => arg.startsWith('--entry='));
const entry = entryIndex !== -1 ? argv[entryIndex].split('=')[1] : './src/index.js';

module.exports = {
  mode: 'development',
  entry: path.resolve(__dirname, entry)
};

运行时构建

运行时构建,可以通过获取变更文件,匹配引用到变更文件的main入口来实现。引用分析,可以通过babel的ast能力去识别import语句去做递归处理,构建引用树,作为变更文件溯源main的依据。

主要步骤如下:

  1. 获取当前分支改动所影响的main入口
  2. 获取当前分支改动文件(git rev-parse & git log)
  3. 构建main文件依赖树(babel的ast去做import语句匹配)
  4. 根据改动文件进行溯源,获取有影响的main
  5. 对有影响的main进行打包(用entry收窄或者ignorePlugin过滤均可实现)
  6. 将打包资源与线上资源进行增量替换(上传cdn,并且修改资源映射表)

实例代码:

# 获取当前分支
git rev-parse --abbrev-ref HEAD

# 获取相对master有变更的文件
git log --name-only --pretty=format: master..currentBranch

# 获取文件存档
git archive --remote=git@gitlab.qima-inc.com:fe/scrm-b-pc-dist.git master -- packages/pc-node/dist/config/${fileName} | tar -xO
/*
 * 分析文件的引用关系,从main入口开始递归分析
 */
const handleFileReferenceAnalyse = (targetFile, referenceFile, mainFilePath) => {
  const relativeFilePath = getRelativeFilePath(targetFile);
  let fileEntity = allFileEntityMap.get(relativeFilePath);
  if (allFileEntityMap.get(relativeFilePath)) {
    fileEntity.setExportPath(referenceFile);
    fileEntity.addToRelativeMainFile(mainFilePath);
    return;
  }
  fileEntity = new FileEntity(relativeFilePath, allFileEntityMap);
  if (referenceFile) {
    fileEntity.setExportPath(referenceFile);
  }
  fileEntity.addToRelativeMainFile(mainFilePath);
  if (fileEntity.isEscapeAst) {
    return;
  }
  const parseAst = getAstBody(targetFile);
  const importPaths = parseNodeImportPath(parseAst, targetFile, relativeFilePath);
  fileEntity.setImportPath(importPaths);
  allFileEntityMap.set(relativeFilePath, fileEntity);
  importPaths.forEach((importPath) => {
    handleFileReferenceAnalyse(importPath, relativeFilePath, mainFilePath);
  });
};
  • 5
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值