使用 pnpm 和 turbo 构建提速从12分到4分钟

简介: 使用 pnpm 和 turbo 构建提速从12分到4分钟

背景0

本地机器 MacBook Pro 芯片 Apple M1 Pro 线上机器 openjdk_java8_nodejs (不知道这个实际配置)



背景1

构建提速是 umi@4 的一个较大的特性,项目中使用 umi@4 构建,只需要12秒左右。

➜  nocode-1 git:(master) pnpm build:app
> @ build:app /Users/congxiaochen/Documents/nocode-1
> cross-env APP_ROOT=packages/app umi build
info  - Using Main Path Plugin
info  - Using Request Plugin
info  - Using Dva Plugin
info  - Using ClassNames Plugin
info  - Using UseModel Plugin
info  - Using Antd Plugin
event - Compiled successfully in 12091 ms (4646 modules)
info  - Memory Usage: 501.55 MB (RSS: 1277.97 MB)
event - Build index.html
复制代码

如果使用传统的交付方式,我本地打包之后,通过 ftp 文件上传部署,可能整个上线流程只要几分钟时间。但是传统的交付部署模式,其实存在着很多的不可信任的人为操作问题,比如说包同步之后,线上没有同步,你很难断言说是人员操作失误,还是静态资源容器缓存。



背景2

项目中使用 menorepo(多包管理),构建项目之前需要先构建本地的子包。 使用的是 yarn 和 lerna 的管理方式。

使用 build: lerna run build构建 10 个子包,每个子包构建时长为 10s-43s 不等。



背景3

所以整个 zcm 构建流程就是 容器启动(24s)、拉取代码(11s)、执行依赖安装(82s)、执行子包编译(231s)、执行子包编译(231s)、执行项目编译(52.71s)、云构建流程,将要回写数据到zcm中(5s)、构建镜像(16s)、推送上线(11s)

#!/bin/bash
# 安装 yarn
# 避免重复执行
if [[ ! -h ~/.yarn/berry ]]; then
  curl -SsLf http://gitlab.iwhalecloud.com/rlc/cicd/raw/master/scripts/react/install_yarn.sh | bash -
fi
log_info "Start installing packages..."
if [[ -f ".yarnrc.yml" ]]; then
  yarn install --immutable
else
  yarn install --frozen-lockfile
fi
log_info "Start building..."
yarn build
log_info "Start building app..."
# 执行产物编译 
yarn build:app
复制代码



解决思路

其实我一开始看到的是这个时间线

image.png


切换 npm 源

主要的时间是花在构建环节,和本地机器差异较大,所以我很想当然的以为是依赖安装问题,所以在本地切换了公司内部的源,并将锁定了源的 yarn.lock 上传到仓库中。这个对安装时间有提升,但是不明显。看了下构建日志,发现zcm 会自动把 npm 源设置到公司源。


继续跟踪日志,我发现子包编译过程执行了两次,并且在子包编译结束时程序没有很良好的推出编译进入下一个环节。本地构建时也会偶发 lerna run build推出较慢的问题,(没有深入去跟踪问题)。


使用 pnpm

所以使用 pnpm 替换 lerna。

-  "build": "lerna run build",
+  "build": "pnpm -r --filter ./packages run build",
复制代码


然后修改构建脚本

#!/bin/bash
# 安装 pnpm
# 避免重复执行
if [[ ! -h ~/.pnpm-state/pnpm-state.json ]]; then
  curl -fsSL https://get.pnpm.io/install.sh | PNPM_VERSION=7.0.0-beta.2 sh -
fi
log_info "Start installing packages..."
pnpm i
log_info "Start building..."
pnpm build
log_info "Start building app..."
# 执行产物编译 
pnpm build:app
复制代码


发现整个过程快了5分钟左右,有两方面的原因,一个是 pnpm 安装依赖更快,另一个是每一个构建流程完成之后都很顺利的进入下一个环节。

最终得到了一个 6分25秒 构建的时间线

image.png


使用 turbo

既然依赖安装部分尽力了,那构建环节是不是还可以更快呢?刚好最近在 umi 项目开发中引入了 turbo 编译速度有很大的提升,也是抱着尝试的心态,将 turbo 引入到项目中(从 umi 抄作业)。


1、只需要安装三个包

"esno": "^0.14.1",
   "ts-node": "^10.7.0",
   "turbo": "^1.1.9",
复制代码


2、加一个配置文件 turbo.json

{
  "$schema": "https://turborepo.org/schema.json",
  "baseBranch": "origin/master",
  "pipeline": {
    "build": {
      "dependsOn": ["^build"]
    }
  },
  "globalDependencies": []
}
复制代码


3、一个构建脚本 scripts/turbo.ts

import * as logger from '@umijs/utils/dist/logger';
import spawn from '@umijs/utils/compiled/cross-spawn';
import yArgs from '@umijs/utils/compiled/yargs-parser';
import { join } from 'path';
(async () => {
  const args = yArgs(process.argv.slice(2));
  const scope = args.scope || '!@example/*';
  const extra = (args._ || []).join(' ');
  await turbo({
    cmd: args.cmd,
    scope,
    extra,
    cache: args.cache,
    parallel: args.parallel,
  });
})();
/**
 * Why not use zx ?
 *  - `zx` not support color stdin on subprocess
 *  - see https://github.com/google/zx/blob/main/docs/known-issues.md#colors-in-subprocess
 *        https://github.com/google/zx/issues/212
 */
async function cmd(command: string) {
  const result = spawn.sync(command, {
    stdio: 'inherit',
    shell: true,
    cwd: join(__dirname, '../'),
  });
  if (result.status !== 0) {
    // sub package command don't stop when execute fail.
    // display exit
    logger.error(`Execute command error (${command})`);
    process.exit(1);
  }
  return result;
}
async function turbo(opts: {
  scope: string;
  cmd: string;
  extra?: string;
  cache?: boolean;
  parallel?: boolean;
}) {
  const extraCmd = opts.extra ? `-- -- ${opts.extra}` : '';
  const cacheCmd = opts.cache === false ? '--no-cache --force' : '';
  const parallelCmd = opts.parallel ? '--parallel' : '';
  const options = [
    opts.cmd,
    `--cache-dir=".turbo"`,
    `--scope="${opts.scope}"`,
    `--no-deps`,
    `--include-dependencies`,
    cacheCmd,
    parallelCmd,
    extraCmd,
  ]
    .filter(Boolean)
    .join(' ');
  return cmd(`turbo run ${options}`);
}
复制代码


4、更换一下执行命令

"build": "esno scripts/turbo.ts --cmd build",
复制代码


最终得到一个我非常满意的 4分30秒 的时间线

image.png


并且二次构建是有缓存的,如

image.png


总结

1、使用yarn2替换yarn1

yarn2 会比 yarn1 要快,但是 yarn2 有些框架不支持,有些第三方包会存在异常。所以我本人不太喜欢 yarn2

2、使用 pnpm 替换 yarn + lerna 的组合

3、使用 turbo 执行构建脚本



备注

其实主要信息都在总结,但是每个项目用到的框架和构建脚本都不一样,提供一下我的完整思路,希望能够引导你对你当前所在项目的构建提升作出优化。



目录
相关文章
|
5天前
|
缓存 Rust
第9期 新一代快速打包工具 Turbopack
第9期 新一代快速打包工具 Turbopack
98 0
|
5天前
|
人工智能 Shell 编译器
C/C++编译工具:makefile | AI工程化部署
Makefile是一种用于管理和组织源代码的工具,通常用于构建和编译软件项目。它由一系列规则组成,每个规则指定如何生成一个或多个目标文件。Makefile也包括变量和注释,使得用户能够灵活地配置和定制构建过程。【1月更文挑战第3天】
141 3
|
5天前
|
算法 编译器 C语言
【CMake install 命令】精通CMake安装:灵活、高效的构建和部署
【CMake install 命令】精通CMake安装:灵活、高效的构建和部署
127 0
|
5天前
|
算法 API C++
模型落地系列 | TensorRT应该如何添加自己的插件?
模型落地系列 | TensorRT应该如何添加自己的插件?
145 1
|
5天前
|
存储 资源调度 JavaScript
好包不等待:用 pnpm 加速你的项目依赖
好包不等待:用 pnpm 加速你的项目依赖
129 0
|
5天前
|
人工智能 C++ 计算机视觉
C/C++编译工具:cmake | AI工程化部署
CMake 是一个跨平台的开源构建工具,用于管理软件构建流程。它使用一个名为 CMakeLists.txt 的文本文件来描述构建过程。【1月更文挑战第4天】
159 0
|
5天前
|
Rust 前端开发 JavaScript
尤雨溪:Turbopack 真的比 Vite 快 10 倍吗?
尤雨溪:Turbopack 真的比 Vite 快 10 倍吗?
|
10月前
|
存储 资源调度 安全
pnpm:基础使用
pnpm:基础使用
335 0
|
缓存 JavaScript 前端开发
Umi 4 特性 04:build 阶段的构建提速
Umi 4 特性 04:build 阶段的构建提速
785 0
|
缓存 Rust 前端开发
比 Vite 快 10 倍的构建工具:Turbopack!
Vercel 的使命是提供代码创造者在灵感迸发瞬间所需的速度和可靠性。去年,我们专注于提升 Next.js 打包 App 的速度。