Turbopack 与编译器配置深入解析
调整 Turbopack、转换流程和基于 SWC 的编译器,以加快构建并缩小输出。
Turbopack 与编译器配置深入解析 是 CoddyKit 上的免费 Next.js 15 Fullstack (App Router + Server Actions) 课时。 这是第 2 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Next.js 15 Fullstack (App Router + Server Actions) 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Next.js 15 Fullstack (App Router + Server Actions) 课程共包含 4 节课。
本课时的部分内容尚未翻译,以英文显示。
Why Turbopack Exists
Next.js 15 ships Turbopack as the default bundler for next dev. It was built in Rust to replace the JavaScript-based Webpack pipeline that powered Next.js for years.
The core problem Webpack faced at scale: every file change triggered a JavaScript graph traversal and re-evaluation. At 10,000 modules, a single edit could take 8–15 seconds before HMR landed in the browser.
Turbopack solves this with three architectural bets:
- Incremental computation — only the modules affected by a change are re-evaluated, not the whole graph.
- Parallel compilation — Rust's fearless concurrency lets multiple CPU cores transform files simultaneously.
- Persistent caching — transform results are stored on disk and survive process restarts.
The result: cold start times drop by roughly 50–75% on large apps, and HMR latency falls to single-digit milliseconds in most cases.
Enabling Turbopack in next.config.ts
In Next.js 15, next dev --turbopack is the recommended way to opt in during development. For production builds, Webpack remains the default until Turbopack reaches full parity, so you control the flag per command in package.json.
You can also embed Turbopack options directly inside next.config.ts under the experimental.turbo key (renamed to turbopack in the stable API).
Key points to keep in mind:
- The
turbopackkey only affectsnext dev; production builds still use Webpack unless you pass--turbopacktonext build(experimental in v15). - Options in
turbopackare merged on top of Turbopack's built-in defaults — you never have to replicate the full config. - The TypeScript config file (
next.config.ts) gives you full type safety for these options via theNextConfigtype.
// next.config.ts
import type { NextConfig } from 'next';
const config: NextConfig = {
turbopack: {
// Turbopack-specific options go here
// (rules, resolveAlias, resolveExtensions, etc.)
},
};
export default config;Turbopack Loaders: Replacing Webpack Rules
Webpack used module.rules with loaders like babel-loader or raw-loader. Turbopack has an equivalent called rules inside the turbopack config block.
Each rule maps a file-extension glob to one or more Turbopack-compatible loaders. Note that Webpack loaders are not directly compatible — Turbopack requires loaders that implement its own transform API, though many popular loaders (e.g. @svgr/webpack, @mdx-js/loader) have published Turbopack-compatible versions.
Anatomy of a rule:
test— a glob or regex string matching file pathsuse— an array of loader objects, each with aloaderpackage name and an optionaloptionsobject
Loaders run right-to-left, exactly as in Webpack.
// next.config.ts
import type { NextConfig } from 'next';
const config: NextConfig = {
turbopack: {
rules: {
// Transform .svg files into React components
'*.svg': {
loaders: ['@svgr/webpack'],
as: '*.js',
},
// Transform raw .txt files into string modules
'*.txt': {
loaders: ['raw-loader'],
as: '*.js',
},
},
},
};
export default config;Module Aliases with resolveAlias
Path aliases let you write import { Button } from '@ui/Button' instead of ../../components/ui/Button. Turbopack supports this via turbopack.resolveAlias, which mirrors Webpack's resolve.alias.
You should also keep your tsconfig.json paths in sync — the TypeScript compiler uses paths for type checking, while Turbopack uses resolveAlias for bundling. A mismatch causes "module not found" errors at build time even though types look correct in your editor.
Common pattern: define the canonical mapping in one place and derive both configs from it, or use next/jest which auto-reads tsconfig.json paths for Jest.
// next.config.ts
import type { NextConfig } from 'next';
import path from 'path';
const config: NextConfig = {
turbopack: {
resolveAlias: {
'@ui': path.resolve(__dirname, 'src/components/ui'),
'@lib': path.resolve(__dirname, 'src/lib'),
'@server': path.resolve(__dirname, 'src/server'),
},
},
};
export default config;
// tsconfig.json (keep in sync)
// {
// "compilerOptions": {
// "paths": {
// "@ui/*": ["./src/components/ui/*"],
// "@lib/*": ["./src/lib/*"],
// "@server/*": ["./src/server/*"]
// }
// }
// }SWC: Next.js's Built-in Compiler
Alongside Turbopack, Next.js uses SWC (Speedy Web Compiler) as its code transformer. SWC is also written in Rust and handles TypeScript stripping, JSX transformation, minification, and optional syntax transforms.
Important distinction:
- Turbopack is the bundler — it builds the module graph, resolves imports, and orchestrates code splitting.
- SWC is the transformer — it converts individual files (TS → JS, JSX → React.createElement calls, etc.).
Both are active by default in Next.js 15. SWC replaces Babel for most projects; if you still have a .babelrc in your repo, Next.js will fall back to Babel and disable SWC — this is a common source of slow builds on migrated projects.
To confirm SWC is active, run next build and look for "SWC minify" in the output.
Configuring SWC Transforms in next.config.ts
SWC transforms are configured at the top level of NextConfig (not inside turbopack). The most commonly tuned options are:
compiler.styledComponents— enables the SWC plugin for styled-components, adding display names and deterministic class names.compiler.emotion— same for the Emotion CSS-in-JS library.compiler.removeConsole— stripsconsole.*calls from production builds. You can whitelist specific methods (e.g. keepconsole.error).compiler.reactRemoveProperties— removes custom React props (likedata-testid) from production output, reducing HTML payload.
These transforms run on every file during compilation, so enabling only what you need keeps build times tight.
// next.config.ts
import type { NextConfig } from 'next';
const isProd = process.env.NODE_ENV === 'production';
const config: NextConfig = {
compiler: {
// Remove console.log but keep console.error in production
removeConsole: isProd
? { exclude: ['error', 'warn'] }
: false,
// Strip data-testid attributes from JSX in production
reactRemoveProperties: isProd
? { properties: ['^data-testid$'] }
: false,
// Enable styled-components SWC plugin
styledComponents: true,
},
};
export default config;SWC Minification vs Terser
Next.js 15 uses SWC for minification by default (swcMinify: true is now the implicit default). This replaces Terser, the JavaScript-based minifier that was standard for years.
Benchmark comparison on a medium Next.js app (~300 modules):
- Terser: ~18 seconds minification during
next build - SWC minifier: ~3 seconds — roughly 6× faster
SWC minification is also scope-aware and performs dead-code elimination (DCE) at the module level. Combined with tree-shaking from the bundler, this means unused exports that Terser might have kept can be eliminated.
If you encounter an edge case where SWC minification produces incorrect output (rare but possible), you can opt back to Terser:
// next.config.ts — only needed if SWC minifier causes issues
import type { NextConfig } from 'next';
const config: NextConfig = {
// Explicitly disable SWC minification and fall back to Terser
swcMinify: false,
};
export default config;
// Alternatively, to tune SWC minification behavior:
// (no direct config exposed yet — SWC minifier config is internal)
// The recommended approach is to leave swcMinify: true (default)
// and report any correctness bugs to the Next.js GitHub repo.Bundle Analyzer: Visualizing What You Ship
Before optimizing bundle size, you need to see it. The @next/bundle-analyzer package wraps webpack-bundle-analyzer and integrates it with Next.js builds.
After setup, running ANALYZE=true next build opens an interactive treemap in your browser showing every module and its contribution to each JS chunk.
What to look for:
- Large node_modules — e.g.
moment.js(>70 KB gzipped) when you only need date formatting. Replace withdate-fnsor nativeIntl.DateTimeFormat. - Duplicate packages — two versions of
reactorlodashappearing in the treemap signals a resolution conflict. - Server vs Client chunks — code that belongs on the server leaking into the client bundle (e.g. a DB client).
Note: bundle-analyzer currently works with the Webpack build (next build without --turbopack). A Turbopack-native analyzer is on the roadmap.
// next.config.ts
import type { NextConfig } from 'next';
import bundleAnalyzer from '@next/bundle-analyzer';
const withBundleAnalyzer = bundleAnalyzer({
enabled: process.env.ANALYZE === 'true',
openAnalyzer: true,
});
const config: NextConfig = {
// ... your other config
};
export default withBundleAnalyzer(config);
// package.json script:
// "analyze": "ANALYZE=true next build"Turbopack Persistent Cache Configuration
Turbopack's persistent cache stores transform and bundling artifacts in .next/cache/turbopack. On a second next dev run (or in CI after cache restoration), Turbopack reads from disk instead of recomputing — dramatically reducing cold-start time for CI pipelines.
Key behaviors to understand:
- The cache is content-addressed: a file's cache key is a hash of its content plus the content of all its dependencies. You will never get a stale cache hit.
- The cache directory can grow large over time.
next devhas a built-in LRU eviction policy, but you can wipe it manually withrm -rf .next/cache/turbopack. - In CI, cache the
.next/cachedirectory between runs. GitHub Actions example:
# .github/workflows/ci.yml (relevant excerpt)
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Restore Next.js cache
uses: actions/cache@v4
with:
path: |
~/.npm
${{ github.workspace }}/.next/cache
key: ${{ runner.os }}-nextjs-${{ hashFiles('**/package-lock.json') }}-${{ hashFiles('**/*.ts','**/*.tsx') }}
restore-keys: |
${{ runner.os }}-nextjs-${{ hashFiles('**/package-lock.json') }}-
- run: npm ci
- run: npm run buildControlling Code Splitting and Chunk Strategy
Next.js automatically code-splits at the route level (each page gets its own JS chunk), but you can further influence splitting with two techniques:
1. Dynamic imports (next/dynamic) — lazily load heavy components so they are excluded from the initial page bundle. This is the primary tool for reducing First Load JS.
2. optimizePackageImports — a Next.js 15 config option that tells the compiler to tree-shake specific packages that don't have proper ESM exports. Libraries like lucide-react, @radix-ui/*, and icon packs often benefit from this.
Both techniques work with Turbopack and Webpack. optimizePackageImports is especially powerful because it requires zero changes to your import statements — it's purely a bundler hint.
// next.config.ts
import type { NextConfig } from 'next';
const config: NextConfig = {
// Tell the compiler to tree-shake these packages
// even if they lack proper ESM export maps
experimental: {
optimizePackageImports: [
'lucide-react',
'@radix-ui/react-icons',
'recharts',
'@heroicons/react',
],
},
};
export default config;
// In your component — no change needed:
// import { ChevronRight, User } from 'lucide-react';
// Only ChevronRight and User are bundled, not the full icon library.Measuring Build Performance with next build --profile
When build times spike unexpectedly, Next.js provides built-in profiling to pinpoint bottlenecks. Two flags are most useful:
next build --profile— emits a React profiler trace and a.cpuprofilefile you can open in Chrome DevTools to see which transforms or plugins are consuming time.NEXT_TELEMETRY_DEBUG=1 next build— prints detailed timing breakdowns per phase (compilation, type checking, static generation, etc.) to stdout.
For Turbopack specifically, the --turbopack flag surfaces compile times per route segment in the terminal output. A single route taking disproportionately long often indicates a missing resolveAlias causing Turbopack to traverse a deep relative path on every HMR cycle.
Practical workflow: run with profiling → identify the slowest phase → apply the relevant config change → re-measure. Never guess at optimizations on a complex bundler.
// scripts/build-perf.ts — a small helper to time build phases
// Run with: npx ts-node scripts/build-perf.ts
import { execSync } from 'child_process';
function timed(label: string, cmd: string): void {
const start = Date.now();
console.log(`\n>>> Starting: ${label}`);
try {
execSync(cmd, { stdio: 'inherit', env: { ...process.env } });
} catch {
console.error(`[FAILED] ${label}`);
process.exit(1);
}
const elapsed = ((Date.now() - start) / 1000).toFixed(2);
console.log(`<<< Done: ${label} in ${elapsed}s`);
}
timed('Type check', 'npx tsc --noEmit');
timed('Next.js build', 'npx next build');Knowledge Check: Turbopack Loaders vs Webpack Loaders
Test your understanding of the key difference between Turbopack's loader system and Webpack's loader system in Next.js 15.
Lesson Recap: Turbopack and Compiler Configuration
In this lesson you explored the full compiler and bundler configuration stack in Next.js 15:
- Turbopack architecture — incremental computation, parallel Rust workers, and persistent disk caching make it dramatically faster than Webpack for development workflows.
- turbopack config block — use
rulesfor file-level transforms,resolveAliasfor module path shortcuts, and keeptsconfig.jsonpaths in sync to avoid type/bundle mismatches. - SWC as the transformer — distinct from Turbopack (the bundler), SWC handles TS stripping, JSX, and minification. A
.babelrcin your project silently disables SWC. - compiler options —
removeConsole,reactRemoveProperties, and CSS-in-JS plugins are configured at the top-levelcompilerkey, not insideturbopack. - Bundle analysis — use
@next/bundle-analyzerto visualize chunk composition and catch large dependencies or server-code leaking into client bundles. - optimizePackageImports — a zero-touch hint that enables tree-shaking for packages with poor ESM export maps.
- CI caching — cache
.next/cachebetween runs to leverage Turbopack's persistent cache and cut CI build times significantly.
The key mental model: Turbopack owns the graph, SWC owns the files, and next.config.ts is the single control plane for both.
用 AI 导师学习 TypeScript — 免费
在浏览器中编写并运行真实代码,获得全天候 AI 导师的即时帮助,并在网页或应用中继续学习。
- 课程
- 22
- 课程
- 88
常见问题解答
「Turbopack 与编译器配置深入解析」课时是免费的吗?
是的 — 「Turbopack 与编译器配置深入解析」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Next.js 15 Fullstack (App Router + Server Actions) 课程的其余内容,请升级到 CoddyKit PRO。 Next.js 15 Fullstack (App Router + Server Actions) 课程共包含 4 节课。
「Turbopack 与编译器配置深入解析」这节课中我会学到什么?
调整 Turbopack、转换流程和基于 SWC 的编译器,以加快构建并缩小输出。 你通过在浏览器中直接运行的动手代码来练习 Next.js 15 Fullstack (App Router + Server Actions),全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 Next.js 15 Fullstack (App Router + Server Actions) 需要有经验吗?
无需任何先前经验。CoddyKit 上的 Next.js 15 Fullstack (App Router + Server Actions) 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 2 节课,共 4 节。
「Turbopack 与编译器配置深入解析」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 Next.js 15 Fullstack (App Router + Server Actions) 课中编写并运行代码吗?
能。每节 Next.js 15 Fullstack (App Router + Server Actions) 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。
此课程中的所有课时
- 分析并缩小客户端包
- Turbopack 与编译器配置深入解析
- 使用 server-only 与 client-only 划分模块边界
- 动态导入、代码拆分与延迟水合