jvinhit//lab

Search posts

Type to search across journal entries.

navigate open esc close

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:

ToolVì sao chuyểnTrở ngại
Vitedev server tức thì, DX tuyệtmô hình config khác; vài plugin khác
RspackAPI tương thích Webpack, nhanh kiểu Rustmới hơn, hệ sinh thái nhỏ hơn
Turbopackbundler của Next.js, rất nhanhgắ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:

WebpackVite
entryindex.html là entry
loaderstích hợp sẵn + plugin
resolve.aliasresolve.alias cùng ý tưởng
splitChunkstự động qua Rollup
DefinePlugindefine / import.meta.env
devServertí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.