Webpack · Part 2 — The Config Anatomy
webpack.config.js from scratch — mode, entry, output, context, and resolve. Turn the zero-config magic into explicit configuration you control, including aliases and extensions. With an interactive config builder.
Zero-config giúp khởi đầu, nhưng project thật cần kiểm soát. Ngay khi bạn muốn tên output tùy chỉnh, một alias, hay một loader, bạn sẽ cần webpack.config.js. Phần này giải mã bộ khung mà mọi config đều chia sẻ.
Bật/tắt tùy chọn bên dưới và xem một config thật ráp lại:
1. Config chỉ là một object JS
webpack.config.js xuất một object thường (hoặc một hàm trả về object):
const path = require("path");
module.exports = {
mode: "production",
entry: "./src/index.js",
output: {
filename: "bundle.js",
path: path.resolve(__dirname, "dist"),
clean: true,
},
};
Vì là JavaScript, bạn có thể tính giá trị, đọc biến môi trường, và rẽ nhánh có điều kiện.
2. mode
mode đặt một loạt mặc định hợp lý:
| mode | Làm gì |
|---|---|
development | build lại nhanh, output dễ đọc, lỗi rõ |
production | minify, tree shaking, bật tối ưu |
none | không mặc định — bạn tự cấu hình hết |
Nó cũng đặt process.env.NODE_ENV cho code và phụ thuộc của bạn. Đừng ship bản development lên production — bạn mất mọi tối ưu.
3. entry
Nơi đồ thị bắt đầu. Một chuỗi cho một entry, hoặc một object cho nhiều:
// single
entry: "./src/index.js",
// multiple — produces app.js and admin.js
entry: {
app: "./src/index.js",
admin: "./src/admin.js",
},
Nhiều entry là cách bạn build các trang riêng hoặc một vendor bundle (dù splitChunks ở Phần 6 mới là cách hiện đại để tách vendor).
4. output
Bundle đi đâu và tên gì:
output: {
filename: "[name].[contenthash].js", // [name] = entry key
path: path.resolve(__dirname, "dist"), // MUST be absolute
clean: true, // wipe dist/ each build (Webpack 5)
publicPath: "/", // base URL for assets at runtime
}
path phải là tuyệt đối — đó là lý do path.resolve(__dirname, ...) ở khắp nơi. Các token [name], [contenthash] là placeholder mẫu Webpack điền; ta dùng [contenthash] cho caching dài hạn ở Phần 8. clean: true thay cho clean-webpack-plugin cũ.
5. context
Thư mục gốc Webpack giải quyết entry và loader; mặc định là cwd của tiến trình. Bạn hiếm khi đặt nó, nhưng biết nó giải thích vì sao đường dẫn entry tương đối lại resolve ở đó:
context: path.resolve(__dirname, "src"), // now entry: "index.js" works
6. resolve — cách tìm import
resolve điều khiển cách Webpack biến một chuỗi import thành đường dẫn file. Hai cài đặt bạn thực sự dùng:
resolve: {
// try these extensions so you can write import "./math" (no .js)
extensions: [".js", ".jsx", ".ts", ".tsx"],
// import "@/components/Button" instead of "../../components/Button"
alias: {
"@": path.resolve(__dirname, "src"),
},
},
extensions cho bạn bỏ đuôi file trong import. alias diệt địa ngục import ../../../ và phải khớp paths trong tsconfig.json nếu bạn dùng TypeScript.
7. Tách config dev và prod
Khi config lớn lên, tách chúng và merge:
// webpack.common.js — shared
// webpack.dev.js — dev server, cheap source maps
// webpack.prod.js — minify, contenthash
npm install --save-dev webpack-merge
// webpack.prod.js
const { merge } = require("webpack-merge");
const common = require("./webpack.common.js");
module.exports = merge(common, { mode: "production", devtool: "source-map" });
Cách này giữ mỗi file gọn và tránh mớ if (isProd).
8. Bài tập
1. Webpack ném “output.path không phải đường dẫn tuyệt đối”. Sai ở đâu?
Lời giải
output.path phải tuyệt đối — bọc trong path.resolve(__dirname, "dist").
2. Bạn muốn viết import Button from "@/components/Button". Hai cài đặt nào làm nó chạy (trong Webpack và TS)?
Lời giải
resolve.alias trong Webpack và compilerOptions.paths khớp trong tsconfig.json.
3. Bundle của bạn to và không minify ở production. Bạn lỡ đặt mode thành gì?
Lời giải
development (hoặc none) — chỉ production bật minify và tree shaking.
Nâng cao:trong builder, bật nhiều entry và để ý filename thêm [name]. để hai bundle không đụng nhau.
Điểm chính
- Config là object JS thường xuất từ
webpack.config.js. modeđặt loạt mặc định — luônproductionkhi ship.output.pathphải tuyệt đối; dùng token mẫu như[name]/[contenthash].resolve.extensionsvàresolve.aliasdọn dẹp import.- Tách config dev/prod và gộp bằng
webpack-merge.
Tiếp theo
Phần 3 — Loader: cách Webpack biến đổi file không phải JS — babel-loader, css-loader/style-loader, asset module — và vì sao thứ tự loader (phải-sang-trái) quan trọng.