Webpack · Part 12 — Production Capstone + Migration
Assemble every technique from the series into one battle-tested production config, with a copy-paste dev/prod split — then a clear-eyed guide to when and how to migrate to Vite or Rspack. With a config capstone builder.
Mười một phần, một config. Phần kết này ghép tất cả — mode, hash, splitting, tách CSS, source map, ngân sách, cache — thành một thiết lập production bạn có thể dán vào dự án thật. Rồi câu hỏi thật lòng: bạn còn nên ở lại Webpack không?
Bật/tắt từng kỹ thuật bên dưới để xây config và xem điểm sẵn-sàng-production:
1. Tách dev và prod
Đừng nhồi cả hai mode vào một file đầy if (isProd). Dùng một base chung và gộp config theo mode bằng webpack-merge:
// 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"), clean: true },
module: {
rules: [{ test: /\.[jt]sx?$/, 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, open: true, historyApiFallback: true },
});
2. Config production
// 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", // Part 7: minify + tree shake
devtool: "source-map", // Part 5: debuggable prod
output: {
filename: "[name].[contenthash].js", // Part 8: caching
chunkFilename: "[name].[contenthash].js",
},
module: {
rules: [{ test: /\.css$/, use: [MiniCssExtractPlugin.loader, "css-loader"] }],
},
optimization: {
splitChunks: { chunks: "all" }, // Part 6
runtimeChunk: "single", // Part 8
moduleIds: "deterministic", // Part 8: stable hashes
},
performance: { maxEntrypointSize: 250000, hints: "error" }, // Part 9
cache: { type: "filesystem" }, // Part 9: fast rebuilds
plugins: [new MiniCssExtractPlugin({ filename: "[name].[contenthash].css" })],
});
// package.json
{
"scripts": {
"dev": "webpack serve --config webpack.dev.js",
"build": "webpack --config webpack.prod.js"
}
}
Mỗi dòng truy về một phần của series này. Demo capstone phía trên chính là config này, ghép từng toggle.
3. Danh sách production
- cờ quan trọng nhất.
- cho caching.
- tách vendor khỏi code app.
- để stack trace production đọc được.
- tách CSS, không
style-loader. - ngân sách để fail CI khi phình to.
- analyzer trong CI để theo dõi kích thước.
4. Bạn có nên di trú?
Webpack trưởng thành, linh hoạt, thực chiến — nhưng công cụ mới nhanh hơn nhiều cho dev. Thành thật về tình huống của bạn:
| Tool | Vì sao chuyển | Trở ngại |
|---|---|---|
| Vite | dev server tức thì, DX tuyệt | mô hình config khác; vài plugin khác |
| Rspack | API tương thích Webpack, nhanh kiểu Rust | mới hơn, hệ sinh thái nhỏ hơn |
| Turbopack | bundler của Next.js, rất nhanh | gắn với Next.js hiện tại |
Ở lại Webpack nếu bạn dựa vào Module Federation, loader/plugin ngách, hoặc một config lớn ổn định đang chạy tốt. Di trú nếu khởi động dev chậm gây đau hằng ngày và stack của bạn phổ thông.
5. Di trú sang Vite — hình hài
Chuyển tư duy: Vite phục vụ ESM native trong dev (không bundle) và dùng Rollup cho build prod. Đa số khái niệm ánh xạ được:
| Webpack | Vite |
|---|---|
entry | index.html là entry |
| loaders | tích hợp sẵn + plugin |
resolve.alias | resolve.alias cùng ý tưởng |
splitChunks | tự động qua Rollup |
DefinePlugin | define / import.meta.env |
devServer | tích hợp, tức thì |
Tin tốt: mọi thứ bạn học ở đây đều chuyển giao. Code splitting, tree shaking, hash, ngân sách là khái niệm bundler phổ quát, không phải mẹo riêng Webpack. (Đó chính là điều series tiếp theo bàn tới.)
6. Bài tập
1. Vì sao dùng webpack-merge với tách common/dev/prod thay vì một config đầy nhánh NODE_ENV?
Lời giải
Sạch hơn, ít lỗi hơn, mỗi file tập trung; config dev và prod không vô tình rò rỉ thiết lập vào nhau.
2. Trong demo capstone, toggle đơn nào cho điểm nhảy lớn nhất, và vì sao?
Lời giải
mode: "production" (+20) — nó bật minify, tree shaking, và tối ưu production cùng lúc.
3. Nỗi đau của team là dev-server khởi động chậm, stack là React SPA chuẩn, không dùng Module Federation. Di trú hay ở lại?
Lời giải
Lý do mạnh để di trú sang Vite — stack phổ thông, không phụ thuộc federation, và tốc độ dev đúng là thứ Vite thắng.
Nâng cao:trong demo capstone, đạt điểm 90+, rồi tự viết phần nào của series dạy mỗi kỹ thuật đã bật.
Điểm chính
- Tách config thành common / dev / prod bằng
webpack-merge. - Config production chỉ là series ghép lại.
mode: "production"là thiết lập đòn bẩy cao nhất.- Di trú sang Vite/Rspack khi tốc độ dev gây đau và stack phổ thông; ở lại cho Module Federation và thiết lập ngách.
- Khái niệm chuyển giao — giờ bạn hiểu bundler, không chỉ Webpack.
Hoàn thành series
Bạn đã đi từ “bundle là cái gì?” tới config production, loader và plugin tùy chỉnh, Module Federation, và chiến lược di trú. Giờ bạn không chỉ dùng Webpack — bạn hiểu mọi bundler đang làm gì bên dưới.