跳至正文

📦 什么是打包工具?

📖 定义

**打包工具(Bundler)**是将多个文件和模块合并成一个或几个文件的工具。它优化JavaScript、CSS、图片等各种资源,并将它们转换为可在浏览器中高效加载的形式。代表性的有Webpack、Vite、Rollup、Parcel等。

🎯 通过比喻理解

搬家公司比喻

将打包工具比作搬家公司:

搬家前(打包前)
家里的物品:
├─ 客厅: 沙发、电视、桌子 (JavaScript文件)
├─ 卧室: 床、书桌、衣柜 (CSS文件)
├─ 厨房: 冰箱、餐具 (图片文件)
└─ 浴室: 洗手池、毛巾 (字体文件)

问题:
- 一件一件搬 = 效率低
- 未整理 = 难找
- 浪费空间 = 慢

搬家公司(打包工具):
1. 物品分类
2. 装箱
3. 贴标签
4. 高效摆放
5. 装车

搬家后(打包后):
📦 箱子1: 家具 (main.js)
📦 箱子2: 厨房用品 (styles.css)
📦 箱子3: 小物件 (assets)

优点:
- 一次搬完 = 快
- 整理好 = 好找
- 空间利用 = 优化

图书馆比喻

散乱的书(打包前)
- 1000本书散落在地上
- 难找
- 浪费空间
- 积灰

图书馆系统(打包工具)
1. 按主题分类
2. 整理到书架
3. 创建索引
4. 贴标签

整理后的图书馆(打包后)
- 按类别的书架
- 快速搜索
- 空间利用率高
- 整洁管理

烹饪准备比喻

准备食材前(打包前)
整个冰箱:
- 20种蔬菜
- 5种肉类
- 30种调味料
- 全都放在不同位置

厨师(打包工具):
1. 确认今天的菜单
2. 只选择需要的食材
3. 处理食材
4. 按烹饪顺序摆放

备菜完成(打包后)
- 只整理需要的食材
- 可以立即烹饪
- 高效
- 节省时间

⚙️ 工作原理

1. 模块系统的必要性

// 问题: 全局污染
// 在HTML中加载多个脚本
<!DOCTYPE html>
<html>
<head>
<script src="utils.js"></script>
<script src="math.js"></script>
<script src="app.js"></script>
</head>
</html>

// utils.js
var name = 'Utils';
function log(msg) {
console.log(msg);
}

// math.js
var name = 'Math'; // ❌ 冲突! 覆盖了utils.js的name
function add(a, b) {
return a + b;
}

// app.js
console.log(name); // 输出'Math' (期望: 'Utils')
log('Hello'); // 能工作但不清楚函数来自哪里

// 问题:
// 1. 变量名冲突
// 2. 依赖顺序重要
// 3. 全局命名空间污染
// 4. 文件多时HTTP请求多
// 5. 也会加载未使用的代码

2. 模块系统

// ✅ ES6 Modules (ESM)
// utils.js
export const name = 'Utils';
export function log(msg) {
console.log(msg);
}

// math.js
export const name = 'Math';
export function add(a, b) {
return a + b;
}
export function subtract(a, b) {
return a - b;
}

// app.js
import { log } from './utils.js';
import { add, subtract } from './math.js';

log('Hello'); // 清楚!
console.log(add(1, 2)); // 3

// 优点:
// - 命名空间隔离
// - 明确的依赖关系
// - 可以Tree Shaking
// - 易于重用

// 但是问题:
// 1. 旧浏览器不支持
// 2. HTTP请求仍然很多
// 3. 模块解析慢

// → 需要打包工具!

3. 打包工具的工作流程

// 步骤1: Entry Point (入口点)
// webpack.config.js
module.exports = {
entry: './src/index.js' // 起点
};

// 步骤2: Dependency Graph (依赖图)
// index.js
import { render } from './render.js';
import './styles.css';
import logo from './logo.png';

// render.js
import { createElement } from './dom.js';
import { formatDate } from './utils.js';

// dom.js
import { debounce } from './helpers.js';

// 依赖树:
index.js
├─ render.js
│ ├─ dom.js
│ │ └─ helpers.js
│ └─ utils.js
├─ styles.css
└─ logo.png

// 步骤3: Loaders (转换)
// - CSS → JavaScript
// - SCSS → CSS → JavaScript
// - 图片 → Base64 or 文件
// - TypeScript → JavaScript
// - JSX → JavaScript

// 步骤4: Plugins (附加任务)
// - HTML生成
// - 代码压缩
// - 环境变量注入
// - 源码映射生成

// 步骤5: Output (输出)
// dist/
// ├─ bundle.js (所有JS合并)
// ├─ styles.css (提取的CSS)
// └─ logo.abc123.png (添加哈希)

// 结果:
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="dist/styles.css">
</head>
<body>
<script src="dist/bundle.js"></script>
<!-- 一个文件! -->
</body>
</html>

4. Tree Shaking

// math.js
export function add(a, b) {
return a + b;
}

export function subtract(a, b) {
return a - b;
}

export function multiply(a, b) {
return a * b;
}

export function divide(a, b) {
return a / b;
}

// app.js
import { add, subtract } from './math.js';

console.log(add(1, 2)); // 使用
console.log(subtract(5, 3)); // 使用

// multiply和divide未使用!

// 打包工具 (Tree Shaking后)
// bundle.js
function add(a, b) {
return a + b;
}
function subtract(a, b) {
return a - b;
}
console.log(add(1, 2));
console.log(subtract(5, 3));

// multiply和divide被删除!
// 打包体积减小!

// Tree Shaking条件:
// 1. 使用ES6 Modules
// 2. 无副作用的代码
// 3. Production模式

5. Code Splitting

// 代码分割 (Code Splitting)

// ❌ 所有代码打包到一个文件
import Home from './pages/Home';
import About from './pages/About';
import Dashboard from './pages/Dashboard';
import Admin from './pages/Admin';

// bundle.js (2MB) - 太大!

// ✅ 用动态import分割
// app.js
const routes = {
'/': () => import('./pages/Home'),
'/about': () => import('./pages/About'),
'/dashboard': () => import('./pages/Dashboard'),
'/admin': () => import('./pages/Admin')
};

// 路由器
async function navigate(path) {
const loadPage = routes[path];
if (loadPage) {
const module = await loadPage();
module.default.render();
}
}

// 结果:
// bundle.js (100KB) - 基础代码
// home.chunk.js (50KB) - 仅首页
// about.chunk.js (30KB) - 仅关于页
// dashboard.chunk.js (200KB) - 仅仪表板
// admin.chunk.js (500KB) - 仅管理员

// 优点:
// - 初始加载快
// - 需要时才加载
// - 用户感觉更快

// React中的Code Splitting
import { lazy, Suspense } from 'react';

const Dashboard = lazy(() => import('./pages/Dashboard'));

function App() {
return (
<Suspense fallback={<div>加载中...</div>}>
<Dashboard />
</Suspense>
);
}

💡 实际示例

Webpack配置

// webpack.config.js (基本)
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');

module.exports = {
// 1. 入口点
entry: './src/index.js',

// 2. 输出
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.[contenthash].js', // 缓存失效的哈希
clean: true // 构建前清理dist文件夹
},

// 3. 模式
mode: 'production', // or 'development'

// 4. Loaders (文件转换)
module: {
rules: [
// JavaScript (Babel)
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env', '@babel/preset-react']
}
}
},

// CSS
{
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader, // 提取CSS文件
'css-loader' // CSS → JS
]
},

// SCSS
{
test: /\.scss$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader',
'sass-loader' // SCSS → CSS
]
},

// 图片
{
test: /\.(png|jpg|gif|svg)$/,
type: 'asset',
parser: {
dataUrlCondition: {
maxSize: 8 * 1024 // 8KB以下内联为Base64
}
}
},

// 字体
{
test: /\.(woff|woff2|eot|ttf|otf)$/,
type: 'asset/resource'
}
]
},

// 5. Plugins (附加功能)
plugins: [
// HTML生成
new HtmlWebpackPlugin({
template: './src/index.html',
minify: true
}),

// CSS文件提取
new MiniCssExtractPlugin({
filename: 'styles.[contenthash].css'
})
],

// 6. 开发服务器
devServer: {
static: './dist',
port: 3000,
hot: true, // Hot Module Replacement
open: true
},

// 7. 源码映射 (调试)
devtool: 'source-map',

// 8. 优化
optimization: {
splitChunks: {
chunks: 'all', // 代码分割
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
priority: 10
}
}
}
}
};

// package.json
{
"scripts": {
"dev": "webpack serve --mode development",
"build": "webpack --mode production"
}
}

// 使用方法:
// npm run dev - 运行开发服务器
// npm run build - 生产构建

Vite配置

// vite.config.js
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import path from 'path';

export default defineConfig({
// 1. 插件
plugins: [react()],

// 2. 别名
resolve: {
alias: {
'@': path.resolve(__dirname, './src'),
'@components': path.resolve(__dirname, './src/components'),
'@utils': path.resolve(__dirname, './src/utils')
}
},

// 3. 开发服务器
server: {
port: 3000,
open: true,
cors: true,
proxy: {
// API代理
'/api': {
target: 'http://localhost:5000',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, '')
}
}
},

// 4. 构建
build: {
outDir: 'dist',
assetsDir: 'assets',
sourcemap: true,

// 块大小限制
chunkSizeWarningLimit: 1000,

// Rollup选项
rollupOptions: {
output: {
// 手动块分割
manualChunks: {
'react-vendor': ['react', 'react-dom'],
'router': ['react-router-dom'],
'ui': ['@mui/material']
}
}
},

// 压缩
minify: 'terser',
terserOptions: {
compress: {
drop_console: true // 删除console.log
}
}
},

// 5. CSS
css: {
preprocessorOptions: {
scss: {
additionalData: `@import "@/styles/variables.scss";`
}
},
modules: {
localsConvention: 'camelCase'
}
},

// 6. 环境变量
define: {
__APP_VERSION__: JSON.stringify('1.0.0')
}
});

// package.json
{
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
}
}

// Vite的优点:
// 1. 非常快的开发服务器 (使用ESM)
// 2. 即时启动 (不打包)
// 3. HMR超快
// 4. 简单配置
// 5. 现代默认设置

Rollup配置 (用于库)

// rollup.config.js
import resolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
import babel from '@rollup/plugin-babel';
import { terser } from 'rollup-plugin-terser';
import pkg from './package.json';

export default {
// 入口点
input: 'src/index.js',

// 多个输出 (多种格式)
output: [
// CommonJS (Node.js)
{
file: pkg.main,
format: 'cjs',
sourcemap: true
},

// ES Module (用于打包工具)
{
file: pkg.module,
format: 'esm',
sourcemap: true
},

// UMD (用于浏览器)
{
file: pkg.browser,
format: 'umd',
name: 'MyLibrary',
sourcemap: true,
globals: {
react: 'React'
}
}
],

// 外部依赖 (不包含在打包中)
external: ['react', 'react-dom'],

// 插件
plugins: [
// 解析Node模块
resolve({
extensions: ['.js', '.jsx']
}),

// CommonJS → ESM
commonjs(),

// Babel转换
babel({
exclude: 'node_modules/**',
babelHelpers: 'bundled',
presets: ['@babel/preset-env', '@babel/preset-react']
}),

// 压缩
terser()
]
};

// package.json
{
"name": "my-library",
"version": "1.0.0",
"main": "dist/index.cjs.js", // CommonJS
"module": "dist/index.esm.js", // ES Module
"browser": "dist/index.umd.js", // UMD
"scripts": {
"build": "rollup -c"
}
}

// Rollup的优点:
// 1. 优秀的Tree Shaking
// 2. 更小的打包体积
// 3. 最适合库开发
// 4. 多格式输出

Parcel (零配置)

// package.json (不需要配置文件!)
{
"name": "my-app",
"scripts": {
"dev": "parcel src/index.html",
"build": "parcel build src/index.html"
}
}

// src/index.html
<!DOCTYPE html>
<html>
<head>
<title>Parcel App</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="./index.js"></script>
</body>
</html>

// src/index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './styles.css';
import App from './App';

ReactDOM.render(<App />, document.getElementById('root'));

// src/styles.css
body {
margin: 0;
font-family: sans-serif;
}

// src/App.jsx
import React from 'react';

function App() {
return <h1>Hello Parcel!</h1>;
}

export default App;

// 直接运行!
// npm run dev

// Parcel会自动:
// - Babel转换
// - CSS处理
// - 图片优化
// - HMR设置
// - 代码分割

// Parcel的优点:
// 1. 零配置
// 2. 快速启动
// 3. 自动优化
// 4. 对初学者友好

// 缺点:
// 1. 难以精细控制
// 2. 插件生态系统较小

实际项目结构

# Create React App (Webpack)
my-app/
├── node_modules/
├── public/
│ ├── index.html
│ └── favicon.ico
├── src/
│ ├── components/
│ │ ├── Header.js
│ │ └── Footer.js
│ ├── App.js
│ ├── App.css
│ └── index.js
├── package.json
└── README.md

# Vite
my-vite-app/
├── node_modules/
├── public/
│ └── vite.svg
├── src/
│ ├── assets/
│ ├── components/
│ ├── App.jsx
│ ├── App.css
│ └── main.jsx
├── index.html # 在根目录!
├── vite.config.js
└── package.json

# Next.js (Webpack + SWC)
my-next-app/
├── node_modules/
├── pages/
│ ├── api/
│ ├── _app.js
│ ├── _document.js
│ └── index.js
├── public/
├── styles/
├── next.config.js
└── package.json

性能优化示例

// webpack.config.js (生产优化)

const webpack = require('webpack');
const TerserPlugin = require('terser-webpack-plugin');
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
const CompressionPlugin = require('compression-webpack-plugin');
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');

module.exports = {
mode: 'production',

optimization: {
// 1. 代码压缩
minimize: true,
minimizer: [
new TerserPlugin({
terserOptions: {
compress: {
drop_console: true, // 删除console.log
drop_debugger: true, // 删除debugger
pure_funcs: ['console.log']
}
}
}),
new CssMinimizerPlugin()
],

// 2. 代码分割
splitChunks: {
chunks: 'all',
minSize: 20000,
maxSize: 244000,
cacheGroups: {
// React库
react: {
test: /[\\/]node_modules[\\/](react|react-dom)[\\/]/,
name: 'react',
priority: 20
},
// 其他库
vendors: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
priority: 10
},
// 公共代码
common: {
minChunks: 2,
name: 'common',
priority: 5,
reuseExistingChunk: true
}
}
},

// 3. 运行时块分离
runtimeChunk: 'single',

// 4. 模块ID稳定化
moduleIds: 'deterministic'
},

plugins: [
// 5. Gzip压缩
new CompressionPlugin({
filename: '[path][base].gz',
algorithm: 'gzip',
test: /\.(js|css|html|svg)$/,
threshold: 10240,
minRatio: 0.8
}),

// 6. 打包分析
new BundleAnalyzerPlugin({
analyzerMode: 'static',
openAnalyzer: false,
reportFilename: 'bundle-report.html'
}),

// 7. 环境变量
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify('production')
})
],

// 8. 缓存
cache: {
type: 'filesystem',
buildDependencies: {
config: [__filename]
}
},

// 9. 性能提示
performance: {
hints: 'warning',
maxEntrypointSize: 512000,
maxAssetSize: 512000
}
};

// 结果:
// Before: bundle.js (2.5MB)
// After:
// react.js (140KB)
// vendors.js (300KB)
// common.js (50KB)
// main.js (100KB)
// Total: 590KB (减少76%!)

环境特定配置

// webpack.common.js (公共)
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].[contenthash].js'
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: 'babel-loader'
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html'
})
]
};

// webpack.dev.js (开发)
const { merge } = require('webpack-merge');
const common = require('./webpack.common.js');

module.exports = merge(common, {
mode: 'development',
devtool: 'eval-source-map', // 快速源码映射
devServer: {
hot: true,
port: 3000
},
module: {
rules: [
{
test: /\.css$/,
use: ['style-loader', 'css-loader'] // CSS内联到JS
}
]
}
});

// webpack.prod.js (生产)
const { merge } = require('webpack-merge');
const common = require('./webpack.common.js');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');

module.exports = merge(common, {
mode: 'production',
devtool: 'source-map', // 准确的源码映射
module: {
rules: [
{
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader, // 提取CSS文件
'css-loader'
]
}
]
},
plugins: [
new MiniCssExtractPlugin({
filename: '[name].[contenthash].css'
})
]
});

// package.json
{
"scripts": {
"dev": "webpack serve --config webpack.dev.js",
"build": "webpack --config webpack.prod.js"
}
}

🤔 常见问题

Q1. Webpack vs Vite,应该选择哪个?

A: 根据项目特性选择:

// 选择Webpack时
const webpackUseCases = {
适合情况: [
'复杂的构建需求',
'需要精细控制',
'需要很多插件',
'遗留项目',
'旧浏览器支持'
],
优点: [
'成熟的生态系统',
'丰富的插件',
'完全控制',
'大型项目验证'
],
缺点: [
'慢的开发服务器',
'复杂配置',
'学习曲线高'
]
};

// 选择Vite时
const viteUseCases = {
适合情况: [
'新项目',
'想要快速开发体验',
'仅现代浏览器',
'偏好简单配置'
],
优点: [
'超快开发服务器',
'即时启动',
'简单配置',
'现代默认设置',
'HMR非常快'
],
缺点: [
'生态系统相对较小',
'部分遗留库有问题',
'生产构建使用Rollup'
]
};

// 速度比较:
// 开发服务器启动:
// Webpack: 10-60秒
// Vite: 0.5-2秒 (快20-100倍!)

// HMR (热模块替换):
// Webpack: 0.5-2秒
// Vite: 50-200ms (快10倍!)

// 生产构建:
// Webpack: 相似
// Vite: 相似 (都足够快)

// 推荐:
// - 新项目: Vite
// - 现有项目: 保持Webpack
// - 迁移: 谨慎考虑

Q2. 如何减小打包体积?

A: 使用多种优化技术:

// 1. Tree Shaking (删除未使用的代码)

// ❌ 坏例子 (完整导入)
import _ from 'lodash'; // 整个库 (70KB)
_.debounce(fn, 100);

// ✅ 好例子 (只要需要的)
import debounce from 'lodash/debounce'; // 仅2KB
debounce(fn, 100);

// 更好的例子 (lodash-es)
import { debounce } from 'lodash-es'; // 可以Tree Shaking

// 2. Code Splitting (代码分割)
// 按路由分割
const Home = lazy(() => import('./pages/Home'));
const About = lazy(() => import('./pages/About'));

// 条件加载
if (user.isAdmin) {
const AdminPanel = await import('./AdminPanel');
AdminPanel.render();
}

// 3. Dynamic Import (动态导入)
button.addEventListener('click', async () => {
const module = await import('./heavyFeature.js');
module.doSomething();
});

// 4. 使用外部CDN
// webpack.config.js
module.exports = {
externals: {
react: 'React',
'react-dom': 'ReactDOM'
}
};

// index.html
<script src="https://unpkg.com/react@18/umd/react.production.min.js"></script>
<script src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js"></script>

// 5. 图片优化
// - 使用WebP格式
// - 调整到合适大小
// - 懒加载

// webpack.config.js
{
test: /\.(png|jpg|jpeg)$/,
use: [
{
loader: 'image-webpack-loader',
options: {
mozjpeg: { quality: 75 },
pngquant: { quality: [0.65, 0.9] }
}
}
]
}

// 6. Compression (压缩)
// Gzip, Brotli
new CompressionPlugin({
algorithm: 'brotliCompress',
test: /\.(js|css|html|svg)$/
});

// 7. Bundle Analysis (分析)
npm install --save-dev webpack-bundle-analyzer

// webpack.config.js
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;

plugins: [
new BundleAnalyzerPlugin()
]

// 8. 替换Moment.js
// ❌ Moment.js (70KB)
import moment from 'moment';

// ✅ date-fns (2-5KB)
import { format } from 'date-fns';

// ✅ Day.js (2KB)
import dayjs from 'dayjs';

// 结果:
// Before: 2.5MB
// After: 500KB (减少80%!)

Q3. 开发服务器很慢怎么办?

A: 有几种优化方法:

// webpack.config.js (开发服务器优化)

module.exports = {
// 1. 启用缓存
cache: {
type: 'filesystem',
buildDependencies: {
config: [__filename]
}
},

// 2. 优化源码映射
devtool: 'eval-cheap-module-source-map', // 快!
// 'eval-source-map' - 中等
// 'source-map' - 慢 (用于生产)

// 3. Babel缓存
module: {
rules: [
{
test: /\.js$/,
use: {
loader: 'babel-loader',
options: {
cacheDirectory: true // 启用缓存
}
}
}
]
},

// 4. 解析优化
resolve: {
// 扩展名顺序
extensions: ['.js', '.jsx'], // 只要需要的

// 别名
alias: {
'@': path.resolve(__dirname, 'src')
},

// 模块路径
modules: ['node_modules'] // 明确指定
},

// 5. 开发服务器设置
devServer: {
hot: true, // HMR
liveReload: false, // 使用HMR时不需要
client: {
overlay: {
errors: true,
warnings: false // 警告仅在控制台
}
}
},

// 6. 禁用性能提示 (开发中)
performance: {
hints: false
},

// 7. 最小化统计
stats: 'errors-warnings'
};

// 或者迁移到Vite!
// Webpack: 30秒启动
// Vite: 1秒启动 (快30倍!)

Q4. 可以不用打包工具开发吗?

A: 现代浏览器支持ES Modules,但有限制:

<!-- 不用打包工具 (使用ESM) -->
<!DOCTYPE html>
<html>
<head>
<title>No Bundler</title>
</head>
<body>
<div id="app"></div>

<!-- type="module" 必需 -->
<script type="module">
import { render } from './render.js';
import { utils } from './utils.js';

render();
</script>
</body>
</html>

<!-- render.js -->
<script type="module">
export function render() {
document.getElementById('app').innerHTML = '<h1>Hello!</h1>';
}
</script>

<!-- 优点: -->
- 不需要配置
- 即时启动
- 简单

<!-- 缺点: -->
- 需要HTTP/2 (很多请求)
- 不支持node_modules
- 不能转换TypeScript
- 不能使用JSX
- 难以处理图片/CSS
- 难以优化生产
- 不支持旧浏览器

<!-- Import Maps (实验性) -->
<script type="importmap">
{
"imports": {
"react": "https://esm.sh/react@18",
"react-dom": "https://esm.sh/react-dom@18"
}
}
</script>

<script type="module">
import React from 'react';
import ReactDOM from 'react-dom';

// 直接从CDN加载!
</script>

<!-- 结论: -->
<!-- 小型原型: 可以不用打包工具 -->
<!-- 实际项目: 必须用打包工具! -->

Q5. 如何将TypeScript与打包工具一起使用?

A: 大多数打包工具都支持TypeScript:

// Webpack + TypeScript
// webpack.config.js
module.exports = {
entry: './src/index.tsx',
module: {
rules: [
{
test: /\.tsx?$/,
use: 'ts-loader',
exclude: /node_modules/
}
]
},
resolve: {
extensions: ['.tsx', '.ts', '.js']
}
};

// tsconfig.json
{
"compilerOptions": {
"target": "ES2020",
"module": "ESNext",
"jsx": "react",
"moduleResolution": "node",
"esModuleInterop": true,
"strict": true,
"skipLibCheck": true
},
"include": ["src"]
}

// Vite + TypeScript (自动支持!)
// vite.config.ts
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';

export default defineConfig({
plugins: [react()]
});

// 直接编写.tsx文件!
// src/App.tsx
import React from 'react';

interface Props {
name: string;
age: number;
}

const App: React.FC<Props> = ({ name, age }) => {
return (
<div>
<h1>Hello, {name}!</h1>
<p>Age: {age}</p>
</div>
);
};

export default App;

// esbuild (超快)
// build.js
const esbuild = require('esbuild');

esbuild.build({
entryPoints: ['src/index.tsx'],
bundle: true,
outfile: 'dist/bundle.js',
loader: { '.tsx': 'tsx' },
minify: true
});

// SWC (Next.js默认)
// .swcrc
{
"jsc": {
"parser": {
"syntax": "typescript",
"tsx": true
},
"target": "es2020"
}
}

// 速度比较:
// tsc (TypeScript): 慢
// Babel: 中等
// esbuild: 快10-100倍
// SWC: 快20-70倍

// 推荐:
// - Vite: 内置esbuild
// - Next.js: 默认SWC
// - Webpack: ts-loader 或 babel-loader

🎓 下一步

理解了打包工具后,可以学习:

  1. 什么是Node.js? (文档待编写) - 打包工具运行环境
  2. 什么是Git? (文档待编写) - 版本控制实现安全开发
  3. 什么是CI/CD? - 自动构建和部署

🎬 总结

打包工具是现代Web开发的必备工具:

  • Webpack: 强大且成熟,配置复杂
  • Vite: 超快开发体验,现代化
  • Rollup: 库开发,优秀的Tree Shaking
  • Parcel: 零配置,对初学者友好

为项目选择合适的打包工具,并优化它来构建快速的Web应用!