Luyện Phỏng Vấn IT — 2000+ Câu Hỏi Phỏng Vấn IT Có Đáp Án 2026

Danh mục

Build Tools iconBuild Tools

Vite là build tool thế hệ mới của Evan You.

  • Dev server không bundle — browser request file nào thì Vite transform file đó on-demand qua native ESM, cold start gần như instant bất kể project size. esbuild pre-bundling: lần đầu start, Vite dùng esbuild (Rust-based, 10-100x nhanh hơn JS bundlers) để bundle node_modules thành single module — tránh browser phải request hàng nghìn files nhỏ; result được cache trong node_modules/.vite.
  • Native ESM serving: source files served dưới dạng ES modules trực tiếp, browser handle dependency graph — chỉ transform file cần thiết cho request hiện tại.
  • Production: dùng Rollup để bundle vì Rollup có tree shaking tốt hơn và output nhỏ hơn esbuild cho production; cũng dùng esbuild để minify (nhanh hơn Terser).
  • Plugin ecosystem: Vite plugins compatible với Rollup plugin API — vite-plugin-react (React Fast Refresh), @vitejs/plugin-vue, vite-plugin-pwa.
  • Framework integrations: Vite là foundation cho SvelteKit, Qwik, Astro, và Remix (một phần).
  • HMR: chỉ invalidate module thay đổi và direct importers — không re-process toàn bộ bundle graph.

pnpm dùng content-addressable store: mỗi package version lưu một lần trong global store (~/.pnpm-store), tất cả projects symlink đến store — tiết kiệm disk đáng kể (100 projects dùng React chỉ lưu 1 copy). node_modules structure: pnpm tạo non-flat node_modules — mỗi package chỉ thấy dependencies được khai báo trong package.json của nó (strict mode).

  • Phantom dependencies: npm/yarn hoist packages lên root node_modules, code có thể import packages không khai báo trong dependencies — chạy được locally nhưng fail ở nơi khác; pnpm strict mode ngăn phantom deps bằng cách không hoist.
  • Workspace protocol: pnpm-workspace.yaml khai báo workspace packages; 'my-lib': 'workspace:*' trong dependencies để ref local packages — pnpm tự resolve khi install, thay bằng version thật khi publish.
  • Performance: pnpm nhanh hơn npm vì hardlinks, parallel installs; tương đương hoặc nhanh hơn Yarn.
  • Strict mode có thể break legacy code dùng phantom deps — dùng shamefully-hoist: true hoặc .npmrc để workaround. pnpm ngày càng phổ biến cho monorepos (Turborepo + pnpm là stack phổ biến).

Webpack là module bundler truyền thống — mạnh và linh hoạt nhưng config phức tạp và dev server chậm (bundle toàn bộ app khi start); đang bị thay thế bởi Vite/Turbopack trong projects mới.

  • Webpack là module bundler tổng hợp tất cả assets (JS, CSS, images) thành bundle files tối ưu.
  • Core concepts: Entry — điểm bắt đầu của dependency graph (thường src/index.js); Output — nơi emit bundles (dist/bundle.js); Loaders — transform file types thành modules (babel-loader chuyển JSX, css-loader parse CSS imports); Plugins — can thiệp vào build lifecycle (HtmlWebpackPlugin tạo HTML, MiniCssExtractPlugin tách CSS ra file riêng, DefinePlugin inject constants); Mode (development/production) — tự động apply optimizations.
  • Dev server: webpack-dev-server serve bundles in-memory, HMR thay module mà không reload page.
  • Code splitting với dynamic import(): Webpack tự tạo chunk files, load on demand.
  • Tại sao đang bị thay thế: config quá phức tạp (webpack.config.js dài hàng trăm dòng), dev server chậm vì bundle toàn bộ app khi start và khi HMR — Vite/Turbopack giải quyết vấn đề này với native ESM.
  • Vẫn phổ biến: nhiều enterprise projects, Create React App (eject), custom build pipelines cần flexibility cao.

Loaders transform file types (right-to-left execution); Plugins can thiệp vào build lifecycle rộng hơn — rule of thumb: cần transform file → loader; cần hook vào build process → plugin.

  • Loaders transform file types thành modules — hoạt động ở file level trong module resolution pipeline.
  • Execution order: right-to-left (bottom-to-top trong config array) — ví dụ ['style-loader', 'css-loader', 'sass-loader'] chạy sass-loader trước.
  • Loaders phổ biến: babel-loader (ES6+/JSX→ES5), css-loader (parse @import và url()), style-loader (inject CSS vào DOM), sass-loader (SCSS→CSS), file-loader/asset modules (handle images/fonts), ts-loader/swc-loader (TypeScript).
  • Custom loader là function nhận source string, transform, return new string — đơn giản implement.
  • Plugins can thiệp vào Webpack compiler lifecycle qua hooks (beforeRun, emit, done).
  • Plugins phổ biến: HtmlWebpackPlugin (generate HTML với injected script tags), MiniCssExtractPlugin (tách CSS thành files riêng thay vì inject vào JS), TerserPlugin (minify JS), DefinePlugin (thay constants lúc build — NODE_ENV), BundleAnalyzerPlugin (visualize bundle).
  • Custom plugin phức tạp hơn loader: phải implement apply(compiler) method và tap vào compiler hooks.
  • Rule of thumb: cần transform file type → loader; cần can thiệp vào build process rộng hơn → plugin.
  • Cold start comparison: Webpack dev server bundle toàn bộ module graph trước khi server ready — project 1000 modules có thể mất 10-30 giây; Vite start trong <1 giây bất kể project size vì không pre-bundle source.
  • Dependency pre-bundling: Vite dùng esbuild pre-bundle node_modules một lần (cached), browser chỉ cần load vài files thay vì hàng nghìn; Webpack bundle tất cả cùng nhau.
  • HMR mechanism differences: Webpack HMR phải re-compile affected module và dependencies, có thể mất 1-10 giây với large modules; Vite HMR chỉ invalidate changed module và propagate lên import chain, thường <100ms.
  • Vite precision: Vite biết chính xác file nào thay đổi và chỉ update đúng phần đó; React Fast Refresh với Vite preserve component state khi update.
  • Trade-off: Vite dev (ESM) và production (Rollup bundled) có thể có behavior khác nhau — potential inconsistencies với circular imports hay module loading order.
  • Large projects: Vite advantage càng rõ khi project lớn hơn — Webpack cold start tăng linear với module count, Vite gần như constant.
  • Turbopack (Next.js 13+): Vercel's Webpack successor viết bằng Rust, cạnh tranh trực tiếp với Vite về speed trong dev mode.

Babel là JavaScript compiler với 3-phase pipeline: Parse (source code → AST via @babel/parser), Transform (plugins traverse và modify AST — ví dụ arrow function plugin chuyển () => {} thành function() {}), Generate (AST → output code via @babel/generator).

  • Polyfills vs transforms: transforms là syntax changes (const → var, class → prototype); polyfills là runtime additions cho missing APIs (Promise, Array.from, fetch) — Babel transforms syntax nhưng không tự polyfill APIs. core-js là polyfill library chuẩn — @babel/preset-env với useBuiltIns: 'usage' tự động import chỉ polyfills cần thiết dựa trên browserslist config. browserslist config (trong package.json hoặc .browserslistrc): target browsers list như '> 0.5%, last 2 versions, not dead' — preset-env compile chỉ những features không được target browsers hỗ trợ natively, giảm output size.
  • Plugin order: plugins chạy trước presets, plugins first-to-last, presets last-to-first (legacy behavior).
  • Babel vs SWC vs esbuild: Babel chậm nhất (JS) nhưng most customizable plugin ecosystem; SWC nhanh hơn 20-70x (Rust), ít plugins hơn; esbuild nhanh nhất nhưng không hỗ trợ custom transforms.

SWC (Speedy Web Compiler) là Rust-based JS/TS compiler — nhanh hơn Babel 20-70x single-thread, 70x với multi-core parallelization.

  • Next.js adoption: từ Next.js 12, SWC thay thế Babel cho transpilation và Terser cho minification — cold build 5x nhanh hơn, HMR 3x nhanh hơn; tự động detect và migrate từ Babel config khi có .babelrc.
  • Compatibility: SWC hỗ trợ hầu hết Babel transforms — preset-env equivalents, TypeScript, JSX, decorators.
  • Plugin system limitations: SWC plugins viết bằng WebAssembly (WASM) — khó implement hơn Babel plugins (JS), ecosystem nhỏ hơn nhiều; một số advanced Babel transforms (custom macros, babel-plugin-macros) chưa có SWC equivalent. @swc/core dùng trực tiếp trong Node.js scripts, swc-loader cho Webpack, @vitejs/plugin-react có thể dùng SWC.
  • Khi không thể dùng SWC: project phụ thuộc vào Babel plugins đặc biệt (babel-plugin-styled-components transformation, babel-plugin-import for tree shaking), hoặc cần custom transforms.
  • Deno sử dụng SWC internally cho TypeScript transpilation.

Webpack bundle toàn bộ code thành một hoặc nhiều file trước khi serve, nên startup trong development khá chậm, đặc biệt với dự án lớn.

  • Vite tận dụng ES Module native của trình duyệt để serve code trực tiếp mà không cần bundle trong development, kết hợp esbuild (viết bằng Go) để xử lý nhanh gấp nhiều lần.
  • Khi build production, Vite dùng Rollup để tạo bundle tối ưu.
  • Đánh đổi: Vite mới hơn nên hệ sinh thái plugin nhỏ hơn webpack, nhưng đang phát triển rất nhanh.
  • Dự án mới nên chọn Vite, dự án cũ đã ổn định thì webpack vẫn là lựa chọn an toàn.

Monolith frontend là kiến trúc một repo chứa toàn bộ code frontend, đơn giản nhưng khó scale khi team lớn vì mọi thay đổi đều phải deploy cùng lúc.

  • Micro-frontend chia frontend thành nhiều ứng dụng nhỏ độc lập, mỗi team quản lý và deploy riêng.
  • Module Federation cho phép các ứng dụng chia sẻ dependency tại runtime — ban đầu là tính năng của webpack, nhưng khái niệm này đã không còn giới hạn trong webpack: Vite có @originjs/vite-plugin-federation, Rspack/Rsbuild cũng hỗ trợ native.
  • Đánh đổi là tăng độ phức tạp về infrastructure, versioning, và trải nghiệm nhất quán — chỉ phù hợp cho tổ chức lớn có nhiều team phát triển song song.

Vite HMR nhanh hơn Webpack vì native ESM — chỉ invalidate module thay đổi thay vì recompile bundle graph; React Fast Refresh giữ component state khi edit function body, remount khi thay đổi hook order.

HMR thay thế modules trong running app mà không reload trang — giữ nguyên application state, chỉ update phần code thay đổi. Webpack HMR mechanism: Webpack watch filesystem, khi file thay đổi, compile lại module thành chunk update; dev server gửi manifest qua WebSocket cho browser; browser download update chunk; HMR runtime apply module update theo module graph — nếu module có module.hot.accept() handler, handler được gọi; nếu không, propagate lên parent modules; nếu không module nào handle, fallback toàn bộ page reload. Vite HMR: nhanh hơn nhiều vì native ESM — browser import file trực tiếp, khi file thay đổi Vite chỉ invalidate module đó và direct importers (không recompile cả bundle graph). React Fast Refresh (Vite plugin / Next.js): HMR cho React components giữ nguyên component state — edit function body, component re-render với state hiện tại (không reset state như full reload). Nếu thay đổi hooks order hay component signature → full remount. State preservation: chỉ local state được giữ; Redux/Zustand store state cũng giữ (stored outside component tree). Debugging HMR failures: nếu HMR không work, kiểm tra console — thường do circular dependencies hoặc module không có HMR handlers.

Không serve .map files publicly trong production — upload lên Sentry/Datadog trong CI để lấy readable stack traces mà không expose source code; hidden-source-map là strategy chuẩn cho production bundles.

Source maps ánh xạ compiled/minified code về original source code — khi error xảy ra trong production bundle, stack trace hiển thị file/line trong TypeScript source thay vì minified gibberish. Format: file .map JSON chứa mappings từ generated code → source; referenced trong bundle qua //# sourceMappingURL=bundle.js.map. Types trong Webpack/Vite: eval-source-map (dev, fast rebuild, in-bundle); source-map (production, external .map file, full quality); hidden-source-map (không expose URL trong bundle, upload .map file lên error tracking riêng); nosources-source-map (stack traces nhưng không expose source code). Production strategy: không serve .map files publicly (expose source code và IP); upload .map files lên Sentry/Datadog trong CI pipeline; Sentry webpack plugin/vite plugin tự động upload và delete .map files. TypeScript: "sourceMap": true trong tsconfig.json; "inlineSources": true để embed source content trong .map (không cần host original files). Vite: sourcemap: true trong vite.config.ts → explicit .map files; sourcemap: 'inline' → embed trong bundle (lớn hơn). Security: .map files chứa original source code — nếu serve publicly, users có thể đọc full source; production .map chỉ nên accessible bởi error tracking service.

ESM là standard với static imports và tree shaking — CJS dynamic require() không tree-shakeable; browser native support ESM; Vite dev server nhanh vì không bundle, serve native ESM; CJS không thể require() ESM (async).

CommonJS (CJS): require() synchronous, dynamic (có thể dùng trong if/function), module.exports là bất kỳ giá trị. Node.js default. Không tree-shakeable (bundler không biết exports nào được dùng vì dynamic). ESM: import/export static (phải ở top-level), asynchronous loading, chính thức là JavaScript standard (TC39). Tree-shakeable. Top-level await. import.meta.url. Tại sao ESM thắng: Tree shaking — ESM static structure cho phép bundler eliminate dead code (cùng import 1 hàm từ lodash-es vs lodash cũ); Async loading — ESM modules load async, CJS synchronous blocking; Standard — browsers native support ESM, Node.js thêm support từ v12; Better DX — Vite native ESM dev server cực nhanh vì không bundle. Node.js interop hiện tại: CJS có thể require() CJS; ESM có thể import CJS (chỉ default export); CJS không thể require() ESM (async) — phải dùng dynamic import(). Dual package (publish cả CJS lẫn ESM): exports field trong package.json với conditional exports. Pitfall: Dual package hazard — app có thể load cả CJS lẫn ESM version của cùng package (2 instances, state không share). TypeScript: "module": "ESNext" + "moduleResolution": "Bundler" cho modern projects.