jvinhit//lab

Search posts

Type to search across journal entries.

navigate open esc close

Webpack · Part 3 — Loaders

How Webpack transforms non-JS files into modules — babel-loader for TS/JSX, css-loader and style-loader, Sass, and built-in asset modules — plus why loader chains run right-to-left. With an interactive loader pipeline.

Webpack chỉ hiểu JavaScript và JSON từ đầu. Loader là bộ chuyển đổi biến mọi thứ khác — TypeScript, CSS, Sass, ảnh — thành module nó có thể thêm vào đồ thị. Đây là nơi “mọi thứ là module” trở thành thật.

Chọn một loại file bên dưới và chạy nó qua chuỗi loader:


1. Loader là gì

Loader là một hàm nhận nội dung file làm input và trả output đã biến đổi. Bạn khai báo chúng trong module.rules, khớp file bằng regex test:

module.exports = {
  module: {
    rules: [
      { test: /\.css$/i, use: ["style-loader", "css-loader"] },
      { test: /\.tsx?$/, use: "babel-loader", exclude: /node_modules/ },
    ],
  },
};

Mỗi rule nói: “với file khớp test, chạy chúng qua use”.


2. Chuỗi loader chạy phải-sang-trái

Điều này làm ai cũng vấp. Khi use là mảng, loader thực thi từ cuối lên đầu:

use: ["style-loader", "css-loader"]
// execution: css-loader FIRST, then style-loader

Đọc như hợp hàm — style-loader(css-loader(source)). Với CSS thì đúng y vậy:

  1. css-loader giải quyết @importurl() và biến CSS thành module JS.
  2. style-loader lấy cái đó và tiêm thẻ <style> vào DOM lúc chạy.

Đảo thứ tự là hỏng. Chạy ví dụ Sass trong demo để xem chuỗi ba loader.


3. Các loader bạn thực sự dùng

npm install --save-dev babel-loader @babel/core @babel/preset-env \
  css-loader style-loader sass-loader sass
LoaderBiến
babel-loaderJS tương thích trình duyệt
css-loaderCSS → module JS
style-loaderCSS đã JS-hóa → <style> tiêm vào
sass-loaderSass/SCSS → CSS
postcss-loaderchạy PostCSS

Ở production bạn thường thay style-loader bằng MiniCssExtractPlugin.loader để phát ra file .css thật thay vì tiêm (Phần 4).


4. babel-loader thực tế

{
  test: /\.(js|jsx|ts|tsx)$/,
  exclude: /node_modules/,
  use: {
    loader: "babel-loader",
    options: {
      presets: ["@babel/preset-env", "@babel/preset-react", "@babel/preset-typescript"],
    },
  },
}

exclude: /node_modules/ quan trọng — transpile phụ thuộc thì chậm và thường không cần. options của loader cấu hình phép biến đổi.


5. Asset module — không cần loader

Webpack 5 có xử lý asset tích hợp sẵn, thay cho file-loader, url-loader, và raw-loader. Dùng type thay vì use:

{ test: /\.(png|jpe?g|svg|gif)$/i, type: "asset/resource" }   // emits a file, import → URL
{ test: /\.svg$/i, type: "asset/inline" }                       // inlines as a base64 data URI
{ test: /\.txt$/i, type: "asset/source" }                       // imports raw text
{ test: /\.png$/i, type: "asset" }                              // auto: inline if small, file if big

asset (mặc định thông minh) nội tuyến file dưới 8 KB thành data URI và phát file lớn hơn riêng — ít request cho asset nhỏ, cache cho cái lớn.


6. Tùy chọn khớp rule

Ngoài test, rule hỗ trợ include, exclude, oneOf (khớp đầu tiên thắng, nhanh hơn), và resourceQuery:

{
  oneOf: [
    { test: /\.module\.css$/, use: ["style-loader", { loader: "css-loader", options: { modules: true } }] },
    { test: /\.css$/, use: ["style-loader", "css-loader"] },
  ],
}

oneOf là cách bạn xử lý CSS Modules (.module.css) khác CSS thường.


7. Bài tập

1. Bạn viết use: ["css-loader", "style-loader"] và bị lỗi hoặc style không áp dụng. Vì sao?

Lời giải

Sai thứ tự — chuỗi chạy phải-sang-trái, nên style-loader chạy trước trên CSS thô. Phải là ["style-loader", "css-loader"].

2. Bạn muốn icon nhỏ nội tuyến thành data URI nhưng ảnh lớn phát ra file, tự động. Loại asset module nào?

Lời giải

type: "asset" — nội tuyến dưới ~8 KB và phát file ở trên.

3. Build chậm vì Babel transpile mọi thứ trong node_modules. Sửa?

Lời giải

Thêm exclude: /node_modules/ vào rule babel-loader.

Nâng cao:trong demo pipeline, chạy ví dụ theme.scss và xác nhận thứ tự thực thi là sass-loader → css-loader → style-loader, ngược với mảng config.


Điểm chính

  • Loader biến đổi file không phải JS thành module, khai báo trong module.rules.
  • Chuỗi loader trong mảng use chạy phải-sang-trái.
  • babel-loader lo TS/JSX; luôn exclude: /node_modules/.
  • CSS xâu chuỗi ["style-loader", "css-loader"] (+ sass-loader cho Sass).
  • Asset module của Webpack 5 (type) thay file/url/raw-loader.

Tiếp theo

Phần 4 — Plugin: loader biến đổi từng file, còn plugin móc vào cả build — HtmlWebpackPlugin, DefinePlugin, MiniCssExtractPlugin — và cách hệ thống plugin/hook hoạt động.