一、Turbopack冷启动慢的核心问题:缓存没找对地方
很多刚用Turbopack的开发者都会遇到一个糟心的问题:改个项目跑起来要等好几分钟,甚至比Webpack还慢。这背后90%的原因是缓存策略配错了——要么缓存没存对地方,要么没用到正确的缓存资源,导致每次启动都要重新编译所有代码。
先给大家明确什么是冷启动:就是你第一次跑Turbopack(比如刚拉完代码、换了新电脑、缓存被清空)的时候,Turbopack从0开始编译整个项目的过程。如果这个过程慢,说明缓存没有帮上忙,反而拖了后腿。
1.1 缓存的本质:避免重复做无用功
举个最通俗的例子:你做番茄炒蛋,第一次要洗番茄、切番茄、打鸡蛋、炒鸡蛋、炒番茄、装盘,整个流程下来要10分钟。但如果你提前把番茄切好、鸡蛋打好(相当于缓存了中间结果),下次再做只要3分钟——缓存就是帮你存下“已经做好的中间步骤”,下次直接用,不用重复做。
Turbopack的缓存也是这个逻辑:它会把编译好的JS、CSS、图片等资源,还有项目依赖(比如React、Vue这些第三方库)的编译结果存起来,下次启动的时候直接拿过来用,不用重新编译。
二、正确配置缓存的核心逻辑:分两类缓存分别优化
Turbopack的缓存分两大类:项目依赖缓存和项目源码缓存。这两类缓存的作用不一样,配置方法也完全不同,很多人就是混着配,导致缓存失效。
2.1 先搞懂两类缓存的区别
我用一个真实的项目场景给大家讲:假设你做一个电商网站,用React写,项目里有自己写的组件(比如商品卡片、购物车),还有用的第三方库(比如React、ReactDOM、antd)。
- 项目依赖缓存:存的是React、antd这些第三方库的编译结果。这些库的代码很少变,只要版本不变,编译结果就可以一直用。
- 项目源码缓存:存的是你自己写的组件、页面这些代码的编译结果。这些代码你每天都改,缓存的有效期比较短。
很多人配缓存的时候,要么把两类缓存混存在一个文件夹里,要么只开了其中一类,导致缓存要么用不上,要么更新不及时。
2.2 第一类缓存:项目依赖缓存的配置(最容易被忽略)
项目依赖缓存是冷启动提速的核心,因为第三方库的代码量通常很大(比如antd有几百个组件,编译一次要好几分钟)。如果依赖缓存没配好,每次冷启动都要重新编译所有依赖,速度肯定慢。
2.2.1 依赖缓存的默认问题:存错地方
Turbopack默认会把依赖缓存存在项目根目录的.turbo文件夹里。这个文件夹有个大问题:每次你拉新代码、换分支、或者清项目缓存的时候,都会把.turbo删掉,导致依赖缓存直接没了,下次启动又要重新编译。
举个例子:你今天拉了同事的新分支,执行pnpm dev,发现要等5分钟,一看.turbo文件夹没了——因为同事的分支里没提交.turbo(也不能提交,这个文件夹太大),所以你本地的依赖缓存直接失效了。
2.2.2 正确配置:把依赖缓存存在全局目录
解决方法很简单:把依赖缓存存在电脑的全局目录里,不管你拉什么项目、换什么分支,只要依赖的版本没变,就可以直接用全局的缓存。
这里给大家一个完整的配置示例,用的是pnpm + Turbopack + React技术栈(所有示例都用这个技术栈,不会乱):
首先,在项目根目录新建一个.turbo配置文件(注意是.turbo,不是.turbo.json),内容如下:
{
"cache": {
// 把依赖缓存存在全局目录,不管哪个项目都能用
"global": true,
// 全局缓存的存储路径(Windows、Mac、Linux都适用)
"globalCacheDir": "~/.turbo-global-cache"
}
}
然后,在package.json里的启动命令里加上缓存参数,告诉Turbopack启用全局缓存:
{
"scripts": {
"dev": "next dev --turbo --cacheDir=~/.turbo-global-cache"
}
}
2.2.3 配置后的效果验证
配完之后,你可以做个测试:
- 第一次跑
pnpm dev,等冷启动完成(假设花了3分钟); - 手动删掉项目根目录的
.turbo文件夹; - 再跑一次
pnpm dev,你会发现冷启动只花了10秒——因为依赖缓存存在全局目录,没有被删掉,直接用了上次的编译结果。
2.3 第二类缓存:项目源码缓存的配置(平衡速度和正确性)
源码缓存是你自己写的代码的编译结果,这个缓存不能存在全局目录,因为每个项目的源码都不一样,全局存反而会乱。
2.3.1 源码缓存的默认问题:要么太旧要么太新
Turbopack默认的源码缓存有两个坑:
- 坑1:缓存永远不更新,导致你改了代码,启动的时候还是用旧的编译结果,页面看不到变化;
- 坑2:缓存更新太频繁,每次改一行代码都要重新编译整个项目,速度慢。
2.3.2 正确配置:给源码缓存加“过期时间”和“变化检测”
解决方法是给源码缓存加两个规则:
- 缓存只保留1小时(你自己可以调,比如改成2小时),超过时间就重新编译;
- 只有当你改了源码里的文件(比如
src文件夹里的代码),才会更新缓存。
还是用刚才的技术栈,在.turbo配置文件里加源码缓存的配置:
{
"cache": {
"global": true,
"globalCacheDir": "~/.turbo-global-cache",
// 源码缓存的配置
"local": {
// 源码缓存的存储路径(项目根目录的.turbo-local)
"dir": ".turbo-local",
// 缓存过期时间:1小时(单位:秒,3600秒=1小时)
"ttl": 3600,
// 只有当src文件夹里的文件变化时,才会更新缓存
"watch": ["src/**/*"]
}
}
}
然后在package.json的启动命令里加上源码缓存的参数:
{
"scripts": {
"dev": "next dev --turbo --cacheDir=~/.turbo-global-cache --localCacheDir=.turbo-local"
}
}
2.3.3 配置后的效果验证
你可以做个测试:
- 第一次跑
pnpm dev,等冷启动完成; - 改
src/App.js里的代码,保存后页面会立刻更新(因为源码缓存检测到src文件夹变化,重新编译了这个文件); - 过1小时后再跑
pnpm dev,会重新编译所有源码(因为缓存过期了)。
三、容易踩的缓存坑:避开这些错误配置
很多人配缓存的时候,会犯一些低级错误,导致缓存完全没用,这里给大家列几个最常见的坑:
3.1 坑1:把依赖缓存和源码缓存混存在一个文件夹
比如有人在.turbo配置里只写了一个dir,把两类缓存都存在同一个文件夹里,结果:
- 换分支的时候,依赖缓存被删掉,下次启动又要重新编译;
- 改源码的时候,依赖缓存被更新,导致依赖的编译结果变了,页面出问题。
正确的做法是两类缓存分开存,像刚才的示例一样,依赖缓存存在全局目录,源码缓存存在项目本地的.turbo-local。
3.2 坑2:缓存路径里有中文或特殊字符
比如有人把全局缓存路径写成C:\用户\张三\.turbo-global-cache,或者~/.turbo 缓存,结果Turbopack找不到缓存路径,导致缓存完全没用。
正确的做法是缓存路径只用英文、数字、横杠、斜杠,不要有中文、空格、特殊字符(比如~/.turbo-global-cache是对的)。
3.3 坑3:启动命令里的缓存参数和配置文件不一致
比如配置文件里写的全局缓存路径是~/.turbo-global-cache,但启动命令里写的是--cacheDir=~/.turbo-cache,结果Turbopack找不到缓存,冷启动还是慢。
正确的做法是启动命令里的缓存参数和配置文件里的路径完全一致,最好的方法是把配置写在.turbo文件里,启动命令只加--turbo,这样不会乱。
四、不同场景下的缓存优化方案
不同的项目场景,缓存的配置也不一样,这里给大家列几个常见的场景:
4.1 场景1:个人开发项目(自己用)
个人项目的需求是速度快,所以可以把依赖缓存的过期时间调长(比如7天),源码缓存的过期时间调短(比如30分钟),这样改代码的时候缓存更新快,依赖缓存又能长期用。
配置示例:
{
"cache": {
"global": true,
"globalCacheDir": "~/.turbo-global-cache",
"local": {
"dir": ".turbo-local",
"ttl": 1800, // 源码缓存30分钟过期
"watch": ["src/**/*"]
}
}
}
4.2 场景2:团队开发项目(多人用)
团队项目的需求是一致性,所以要把依赖缓存的路径统一(比如大家都用~/.turbo-global-cache),并且把缓存的配置提交到代码仓库(.turbo文件),这样大家的缓存配置都一样,冷启动速度也一样。
注意:不要把.turbo-local(源码缓存)提交到代码仓库,因为每个开发者的源码不一样,源码缓存是本地用的。
4.3 场景3:CI/CD流水线(自动部署)
CI/CD流水线的需求是速度快,所以要把全局缓存存在流水线的缓存里(比如GitHub Actions的缓存),这样每次流水线跑的时候,都能用上上次的依赖缓存,不用重新编译。
比如GitHub Actions的配置示例:
name: Build
on: [push]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
# 缓存全局缓存目录
- uses: actions/cache@v3
with:
path: ~/.turbo-global-cache
key: ${{ runner.os }}-turbo-global-cache-${{ hashFiles('pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-turbo-global-cache-
- run: pnpm install
- run: pnpm build
五、缓存配置的优缺点和注意事项
5.1 缓存配置的优点
- 冷启动速度提升50%-90%:比如原来冷启动要5分钟,配完缓存只要30秒;
- 开发体验变好:改代码的时候页面更新更快,不用等很久;
- 团队效率提升:大家的冷启动速度都一样,不会出现有人快有人慢的情况;
- CI/CD速度提升:流水线跑的时间变短,部署更快。
5.2 缓存配置的缺点
- 可能出现缓存污染:如果缓存里的编译结果有问题,会导致所有用这个缓存的项目都出问题;
- 占用磁盘空间:全局缓存会存很多依赖的编译结果,可能占几个G的空间;
- 配置稍微复杂:要区分两类缓存,不能混着配。
5.3 注意事项
- 定期清理缓存:如果发现页面出问题,或者缓存占的空间太大,可以删掉全局缓存(
~/.turbo-global-cache)和本地源码缓存(.turbo-local),重新启动; - 版本更新后要清缓存:如果升级了Turbopack的版本,或者升级了依赖的版本,最好清一下缓存,避免旧缓存和新版本不兼容;
- 不要提交缓存文件夹:
.turbo(项目依赖缓存的配置文件可以提交,但缓存文件夹本身不能提交)、.turbo-local这些缓存文件夹要加到.gitignore里,避免提交到代码仓库; - 缓存路径不要用相对路径:比如不要把全局缓存路径写成
./.turbo-global-cache,要写成绝对路径(比如~/.turbo-global-cache),避免路径找不到。
六、总结
Turbopack冷启动慢的核心原因是缓存策略配错了,只要把依赖缓存和源码缓存分开配置,就能解决90%的问题。具体的步骤总结下来就是:
- 把依赖缓存存在全局目录,只要版本不变,就可以一直用;
- 把源码缓存存在项目本地,加过期时间和变化检测,平衡速度和正确性;
- 避开常见的缓存坑,比如路径不对、配置不一致;
- 根据不同的场景调整缓存配置,满足个人、团队、CI/CD的需求。
最后给大家一个完整的.turbo配置文件(适用于个人和团队开发的React项目):
{
"cache": {
"global": true,
"globalCacheDir": "~/.turbo-global-cache",
"local": {
"dir": ".turbo-local",
"ttl": 3600,
"watch": ["src/**/*"]
}
}
}
启动命令:
{
"scripts": {
"dev": "next dev --turbo",
"build": "next build --turbo"
}
}
只要配好这个,你的Turbopack冷启动速度就会快很多,开发体验也会变好。
评论
围绕“Turbopack构建性能调优实战:正确配置缓存策略避免冷启动缓慢”参与讨论