//堆代码 duidaima.com import Header from '../components/header' import Footer from '../components/footer' export default function Home() { return ( <div> <Header /> <h1>Home</h1> <Footer /> </div> ) }当页面访问 /home 时 Header 和 Footer 会被标记为需要缓存 ,并被编译输出为 components_header.tsx.js 和 components_footer.tsx.js。而后更新 Footer 这个组件并保存,在 Webpack 中 Header 和 Footer 两个组件都会被重新编译,而仔细观察 Turbopack 输出的缓存文件,会发现只有 Footer 组件被重新编译,而 Header 组件则使用的是上一次的编译结果,如图所示 compoents_footer.tsx.js 的文件被刷新,而 header 则依旧是上一次的结果。
import Header from '../components/header' import Footer from '../components/footer' export default function Login() { return ( <div> <Header /> <h1>Login</h1> <Footer /> </div> ) }启动项目,在不到 1s 时间后控制台提示已经启动成功,但是文件目录下却没有输出任何缓存文件,这是由于 Turbopack 的按需编译机制,所有组件在启动时都未被使用,所以没有任何的编译操作。在浏览器中访问项目的首页地址,此时观察输出缓存文件则发现 /home 页面及其依赖的组件才被编译:
3.SWC 编译器 Turbopack 的速度如此之快有一个很大的原因是使用了 SWC 作为编译器。大部分 Webpack 的项目编译都是使用 Babel 编译和转换,由于 Babel 本身也是使用 Javascript 编写,转换效率并不理想,而 Turbopack 原生使用 SWC 作为编译器。SWC 是一款 Rust 编写的 Javascript 代码编译器,官方宣称其编译速度是 Babel 的20倍( Webpack 也可以使用SWC)。
4.本地持久化 根据作者的想法,未来编译结果不仅仅缓存在内存当中,还会本地持久化。本地持久化的意义是什么?在实际的生产环境中, 中大型的项目往往都需要打包 15 分钟甚至更久,编译结果持久化可以节省大量的打包时间。假设项目里有 50 个页面,本次迭代只修改了其中 10 个页面,Webpack 打包会全量重新打包 50 个页面,而 Turbopack 只需重新打包 10 个被修改的页面,未修改的 40 个页面直接从硬盘读取上一次打包结果,打包效率则得到非常大的提升。
const { add } = require('./math'); add(1, 2);ESM:
import img from './img.png'; import type { User } from '../server/types'; import { z } from 'zod';Dynamic Imports:
const getFeatureFlags = () => { return import('/featureFlags').then(mod => { return mod.featureFlags; }) }6.框架支持 原生支持 JSX/TSX,不需要引入 React 也能使用 JSX/TSX.
- import React from 'react'; const Component = () => { return <div /> }作者计划在未来通过插件的形式支持 Vue 和 Svelte。
npx create-next-app --example with-turbopack在启动代码里新增常规启动方式,分别使用两种方式启动项目,做个对比。
"scripts": { "dev": "next dev --turbo", "dev_normal": "next dev", "dev:tailwind": "concurrently "next dev --turbo" "npm run tailwind -- --watch"", "build": "next build", "start": "next start", "lint": "next lint", "tailwind": "tailwindcss -i styles/globals.css -o styles/dist.css", "format": "prettier --write "**/*.{js,ts,tsx,md}"", "postinstall": "npm run tailwind" },使用 Turbopack 启动时间:
npx create-next-app@latest安装 Turbo:
npm install turbo --save-dev启动服务:
npx turbo dev使用以下脚本批量生成模块,将代码 batch.js 文件保存在项目的根目录下,并在 pages 目录下新建 components 文件夹:
// 堆代码 duidaima.com const [nodeExeDir, fileDir, count] = process.argv ; var fs = require('fs'); const getJsx = (index) => { return `export function Comp${index}() { return <div>hello world ${index}</div> }` } (async () => { let importJsx = []; let renderJsx = []; for(var i=0;i<count;i++){ await fs.writeFileSync(`./pages/components/comp${i}.tsx`,getJsx(i),'utf-8'); importJsx.push(`import { Comp${i} } from './components/comp${i}';`); renderJsx.push(`<Comp${i} /> `) } await fs.writeFileSync(`./pages/page.tsx`,` ${importJsx.join('\r\n')} \r\n export default function Page() { return <div> ${renderJsx.join('\r\n')} </div> }`,'utf-8'); })();执行代码:
node batch.js 1000后面的数字为生成的模块数量,代码生成完成后将 page.tsx 引入并重启服务。分别生成 1000 ~ 10000 个模块的页面,并使用 Turbopack 运行, 记录多次编译所需的平均时间。作为参照使用 Webpack + Babel 的打包速度作为对比,操作方法同上。 得到以下曲线图:
除了上文所说的打包器之外,还有一款被大家熟知的打包器 Vite。相比 Webpack, Vite 的打包速度也比 Webpack 快非常多,但是流行程度依然没有 Webpack 这么高,比较重要的原因之一就是生态的问题。在 Webpack 的社区有丰富的插件供开发者使用,未来 Turbopack 也会遇到同样的问题。
与Vite不同的地方,Turbopack 由同一个作者开发,和 Webpack 是继承关系,但作者表示并不会对 Webpack 和 Turbopack 做 1:1 的兼容,意味着 Webpack 的插件是无法在 Turbopack 上使用,同时作者也表示会将在 Webpack 上广泛被使用的插件移植到 Turbopack。因此 Turbopack 想替代 Webpack,未来还有很长的路要走。