jvinhit//lab

Search posts

Type to search across journal entries.

navigate open esc close

Webpack · Part 1 — The Mental Model & Your First Build

Why bundlers exist, the dependency graph Webpack builds from a single entry, the four core concepts (entry, output, loaders, plugins), and your first real build. With an interactive dependency-graph visualizer.

Webpack has a reputation for being intimidating, but the core idea is simple {Webpack mang tiếng đáng sợ, nhưng ý tưởng cốt lõi rất đơn giản}. Once you see the dependency graph in your head, every config option afterwards makes sense {Một khi bạn hình dung được đồ thị phụ thuộc, mọi tùy chọn config sau đó đều hợp lý}. This part builds that mental model and gets a real bundle out the door {Phần này xây mô hình tư duy đó và cho ra một bundle thật}.

Press play below to watch Webpack walk from one entry file across every import into a single bundle {Bấm play bên dưới để xem Webpack đi từ một file entry qua mọi import vào một bundle}:


1. Why bundlers exist {Vì sao có bundler}

Browsers used to force you to ship dozens of <script> tags in the right order, with everything sharing one global scope {Trình duyệt từng buộc bạn ship hàng chục thẻ <script> đúng thứ tự, mọi thứ chia chung một global scope}. ES modules helped, but shipping hundreds of small files means hundreds of requests, and you still can’t import CSS, images, or transform TypeScript/JSX in the browser {ES module giúp ích, nhưng ship hàng trăm file nhỏ nghĩa là hàng trăm request, và bạn vẫn không thể import CSS, ảnh, hay biến đổi TypeScript/JSX trong trình duyệt}.

A bundler solves this: it reads your source modules, resolves all dependencies, transforms what needs transforming, and emits a small number of optimized files the browser can load efficiently {Một bundler giải quyết điều này: nó đọc các module nguồn, giải quyết mọi phụ thuộc, biến đổi thứ cần biến đổi, và phát ra một số ít file tối ưu trình duyệt tải hiệu quả}.


2. The dependency graph {Đồ thị phụ thuộc}

This is the one idea to internalize {Đây là ý tưởng duy nhất cần thấm}. Webpack starts at an entry file and follows every import (and require) recursively, building a graph of every module your app touches {Webpack bắt đầu ở một file entry và đi theo mọi import (và require) đệ quy, dựng một đồ thị của mọi module ứng dụng chạm tới}:

index.js (entry)
├─ app.js
│  ├─ math.js
│  │  └─ utils.js
│  └─ data.json
└─ styles.css

Anything not reachable from the entry is not included {Bất cứ thứ gì không tới được từ entry sẽ không được gồm vào}. That’s the foundation of tree shaking (Part 7) {Đó là nền tảng của tree shaking (Phần 7)}. Notice CSS and JSON are nodes too — to Webpack, everything is a module {Để ý CSS và JSON cũng là node — với Webpack, mọi thứ đều là module}.


3. The four core concepts {Bốn khái niệm cốt lõi}

Everything in Webpack maps to one of these {Mọi thứ trong Webpack đều thuộc một trong số này}:

ConceptQuestion it answers {Câu hỏi nó trả lời}
EntryWhere does the graph start? {Đồ thị bắt đầu ở đâu?}
OutputWhere do the bundles go, and what are they named? {Bundle đi đâu, tên là gì?}
LoadersHow do I transform non-JS files (TS, CSS, images)? {Biến đổi file không phải JS thế nào?} (Part 3)
PluginsHow do I hook into the build to do anything else? {Móc vào build để làm việc khác thế nào?} (Part 4)

Hold these four in your head and you can read any webpack.config.js {Giữ bốn cái này trong đầu và bạn đọc được mọi webpack.config.js}.


4. Your first build {Build đầu tiên}

Set up a tiny project {Dựng một project nhỏ}:

mkdir webpack-intro && cd webpack-intro
npm init -y
npm install --save-dev webpack webpack-cli

Create the source {Tạo source}:

// src/index.js
import { greet } from "./greet.js";
document.body.innerHTML = greet("Webpack");
// src/greet.js
export function greet(name) {
  return `Hello, ${name}!`;
}

Now run Webpack with zero config {Giờ chạy Webpack không cần config}:

npx webpack

Webpack 5 has sensible defaults: entry ./src/index.js, output ./dist/main.js, mode production {Webpack 5 có mặc định hợp lý: entry ./src/index.js, output ./dist/main.js, mode production}. Open dist/main.js and you’ll see your two modules merged and minified into one file {Mở dist/main.js và bạn thấy hai module được gộp và minify thành một file}.


5. Adding npm scripts {Thêm npm scripts}

Don’t type npx webpack forever — wire up scripts {Đừng gõ npx webpack mãi — gắn scripts}:

{
  "scripts": {
    "build": "webpack --mode production",
    "dev": "webpack --mode development --watch"
  }
}

--watch rebuilds on every save {--watch build lại mỗi lần lưu}. We’ll upgrade this to a live-reloading dev server in Part 5 {Phần 5 sẽ nâng cấp lên dev server tự tải lại}.


6. What a build actually does {Build thực sự làm gì}

Run the visualizer above and watch the sequence {Chạy trình trực quan trên và xem trình tự}: Webpack resolves the entry, reads its imports, recursively resolves each dependency into the graph, runs loaders on non-JS modules, then packs everything into the output bundle, applying optimizations {Webpack giải quyết entry, đọc các import, đệ quy giải quyết từng phụ thuộc vào đồ thị, chạy loader trên module không phải JS, rồi đóng gói mọi thứ vào bundle output, áp dụng tối ưu}. Every later part of this series is just configuring one of those steps {Mọi phần sau của series chỉ là cấu hình một trong các bước đó}.


7. Exercises {Bài tập}

1. You add a helper.js file to your project but never import it anywhere. Is it in the bundle? Why? {Bạn thêm file helper.js nhưng không bao giờ import nó ở đâu. Nó có trong bundle không? Vì sao?}

Solution {Lời giải}

No — it’s unreachable from the entry, so it’s not part of the dependency graph {Không — nó không tới được từ entry, nên không thuộc đồ thị phụ thuộc}.

2. With no config file at all, where does npx webpack look for the entry and write the output? {Không có file config nào, npx webpack tìm entry ở đâu và ghi output ở đâu?}

Solution {Lời giải}

Entry defaults to ./src/index.js, output to ./dist/main.js {Entry mặc định ./src/index.js, output ./dist/main.js}.

3. Why can’t the browser just load your src/ files directly with <script type="module"> and skip Webpack? {Vì sao trình duyệt không thể tải thẳng file src/ bằng <script type="module"> và bỏ qua Webpack?}

Solution {Lời giải}

It can for plain JS, but not for non-standard imports (CSS, TS, JSX, images), and shipping many small files is request-heavy and unoptimized {Được với JS thuần, nhưng không với import phi chuẩn (CSS, TS, JSX, ảnh), và ship nhiều file nhỏ thì tốn request và không tối ưu}.

Stretch {Nâng cao}: in the visualizer, click each module to read its imports, then press build and confirm the resolution order matches a breadth-first walk from the entry {trong trình trực quan, bấm từng module để đọc import của nó, rồi bấm build và xác nhận thứ tự giải quyết khớp một lượt duyệt theo chiều rộng từ entry}.


Key takeaways {Điểm chính}

  • A bundler reads your modules, resolves dependencies, transforms them, and emits optimized files {Bundler đọc module, giải quyết phụ thuộc, biến đổi, và phát ra file tối ưu}.
  • Webpack builds a dependency graph from a single entry {Webpack dựng đồ thị phụ thuộc từ một entry duy nhất}.
  • To Webpack, everything is a module — JS, CSS, JSON, images {Với Webpack, mọi thứ là module — JS, CSS, JSON, ảnh}.
  • The four core concepts are entry, output, loaders, plugins {Bốn khái niệm cốt lõi là entry, output, loader, plugin}.
  • Webpack 5 builds with zero config thanks to sensible defaults {Webpack 5 build không cần config nhờ mặc định hợp lý}.

Next up {Tiếp theo}

Part 2 — The config anatomy: webpack.config.js from scratch — mode, entry, output, context, and resolve — turning the zero-config magic into explicit, readable configuration you control {Phần 2 — Giải phẫu config: webpack.config.js từ đầu — mode, entry, output, context, và resolve — biến phép màu zero-config thành cấu hình tường minh, dễ đọc bạn kiểm soát}.