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:
css-loadergiải quyết@importvàurl()và biến CSS thành module JS.style-loaderlấ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
| Loader | Biến |
|---|---|
babel-loader | JS tương thích trình duyệt |
css-loader | CSS → module JS |
style-loader | CSS đã JS-hóa → <style> tiêm vào |
sass-loader | Sass/SCSS → CSS |
postcss-loader | chạ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
usechạy phải-sang-trái. babel-loaderlo TS/JSX; luônexclude: /node_modules/.- CSS xâu chuỗi
["style-loader", "css-loader"](+sass-loadercho 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.