jvinhit//lab

Search posts

Type to search across journal entries.

navigate open esc close

Vite · Part 6 — CSS Handling

CSS in Vite with zero config: plain side-effect imports, scoped CSS Modules, built-in Sass/Less/Stylus, the ?inline query for Shadow DOM, automatic PostCSS, Lightning CSS, and code-split CSS in the build. With a CSS pipeline explorer.

CSS là nơi danh tiếng “chạy là được” của Vite xứng đáng nhất. Không loader, không MiniCssExtractPlugin, không config cho trường hợp phổ biến — bạn import một stylesheet và nó chạy khi dev (hot-swap) và khi build (tách và hash).

Chuyển giữa các kiểu CSS để xem bạn import gì và Vite tạo ra gì:


1. CSS thường — import tác dụng phụ

import "./button.css";

Vậy thôi. Import không có binding — nó là tác dụng phụ thêm style vào trang. Khi dev, Vite chèn vào thẻ <style> và hot-swap khi sửa. Khi build, chúng được tách vào file .css đã hash và link.

Vướng mắc: tên class là toàn cục, nên va chạm là vấn đề của bạn.


2. CSS Modules — scope mặc định

Đặt tên file *.module.css và Vite biến nó thành CSS Module:

import styles from "./Button.module.css";
// styles = { btn: "btn_a1b2c3" }  ← hashed, scoped

<button className={styles.btn}>Go</button>;

Mỗi tên class được hash và scope cục bộ, nên .btn ở file này không bao giờ đụng .btn ở file khác. Bạn import một object JS ánh xạ tên của bạn sang tên được sinh. Cấu hình đặt tên qua css.modules:

export default defineConfig({
  css: { modules: { localsConvention: "camelCase" } }, // styles.myClass
});

3. Preprocessor — chỉ cần cài

Sass, Less, Stylus chạy không config — cài trình biên dịch và import file:

npm install -D sass-embedded
import "./styles.scss"; // compiled automatically

Kết hợp với Modules: Component.module.scss cho bạn lồng scope. Vite dùng API hiện đại của Sass mặc định (API cũ bị bỏ ở Vite 7).


4. Hậu tố query — ?inline?raw

Mặc định import CSS sẽ chèn nó. Đôi khi bạn muốn văn bản thay thế:

import css from "./theme.css?inline"; // css = the stylesheet as a string

?inline trả về CSS đã biên dịch dạng chuỗi mà không chèn, để bạn gắn nơi mình muốn — phổ biến nhất là root Shadow DOM cho web component. (?raw cho nội dung file chưa biến đổi — bàn cùng asset ở Phần 7.)


5. PostCSS & Lightning CSS

Đặt postcss.config.js ở gốc và Vite chạy PostCSS trên mọi stylesheet tự động:

// postcss.config.js
export default { plugins: [autoprefixer()] };

Đây là cách Tailwind, autoprefixer, và plugin nesting tích hợp — không cần dây nối riêng cho Vite. Vite cũng hỗ trợ Lightning CSS (trình biến đổi/minify Rust nhanh) như lựa chọn opt-in cho biến đổi và minify:

export default defineConfig({
  css: { transformer: "lightningcss" },
  build: { cssMinify: "lightningcss" },
});

6. CSS cũng được tách code

Trong build production, CSS được import bởi chunk async sẽ tách thành file riêng và chỉ tải khi chunk đó tải. Nên style của route lazy không phình CSS ban đầu. Cái này tự động — cùng việc tách code bạn thấy với JS trong series Webpack, áp cho CSS. Bạn có thể ép tất cả vào một file với build.cssCodeSplit: false nếu thích.


7. Bài tập

1. Hai component đều định nghĩa class toàn cục .title với style khác nhau và đụng nhau. Cách sửa kiểu Vite?

Lời giải

Dùng CSS Modules: đổi tên thành *.module.css và tham chiếu styles.title — tên được hash và scope cục bộ.

2. Bạn xây web component và cần CSS dạng chuỗi để gắn vào Shadow DOM của nó, không chèn vào trang. Sao?

Lời giải

Import với query ?inline: import css from "./theme.css?inline" trả về văn bản stylesheet mà không chèn.

3. Làm sao thêm Sass và autoprefixer vào dự án Vite?

Lời giải

npm i -D sass-embedded rồi import .scss trực tiếp; thêm postcss.config.js với autoprefixer() — Vite chạy cả hai tự động, không cần config loader.

Nâng cao:trong explorer, so tab Plain vs CSS Modules và để ý đúng cái khác trong output — selector toàn cục vs cái đã hash, scope.


Điểm chính

  • Import CSS thường là tác dụng phụ; tên class toàn cục.
  • *.module.css = tên class scope, hash, không config.
  • Preprocessor chạy sau một lần cài.
  • ?inline trả CSS dạng chuỗi cho Shadow DOM v.v.
  • PostCSS tự chạy qua postcss.config.js; CSS được tách code khi build.

Tiếp theo

Phần 7 — Asset tĩnh & glob import: import ảnh và file dạng URL, query ?url / ?raw / ?worker, thư mục public/, và import.meta.glob để import hàng loạt.