Bài này ngắn ngủn à 🥲

Astro và OpenProps là gì?

Rần rần mấy nay, Astro (lại) là một web framework mới. Điểm khác biệt so với NextJS hay Remix là Astro tập trung ưu tiên vào server-side rendering (SSR) trước, giúp giảm phần JavaScript được gửi xuống client. Sau đó đối với những phần cần tương tác trong ứng dụng (ví dụ như carousel, collapsible, etc.), Astro sẽ coi nó như một hòn đảo độc lập và render riêng. Hướng tiếp cận này gọi là Component Islands. Astro xịn ở chỗ cho phép bạn render component của bất cứ thư viện nào, dù đó là React, Vue, Solid, etc. vào các hòn đảo. Ehkoo sẽ có bài riêng về Astro sau này, đón đọc nhe.

Còn OpenProps là một tập hợp các biến CSS (CSS variables hay CSS custom properties). OpenProps sử dụng bảng màu của Open Color, ngoài ra còn khai báo thêm những biến khác liên quan đến border, border radius, spacing, gradients, typography, animations, etc. Nói chung nhiều lắm 😃

Bạn có thể dùng các biến của OpenProps như thế này:

.block-wrap {
  display: flex;
  flex-wrap: wrap;
  flex-basis: var(--size-content-2);
  gap: var(--size-5) var(--size-8);
  align-items: flex-start;
}

Vì khả năng rất cao là bạn không sử dụng hết tất cả biến CSS trong OpenProps nên chúng ta sẽ dùng thêm postcss-jit-props. Đây là một plugin của PostCSS giúp bạn quét hết tất cả stylesheets và loại bỏ những biến không được sử dụng. Kết quả cuối cùng sẽ làm tập tin CSS nhỏ gọn hơn 🥳

Bắt đầu

Trước hết hãy tạo một dự án Astro căn bản bằng lệnh:

$ npm create astro@latest

Bạn có thể bỏ qua bước này nếu dự án đã có sẵn ha. Sau đó chúng ta cài open-propspostcss-jit-props.

$ npm install -S -E open-props postcss-jit-props

Chúng ta sẽ tạo một tập tin postcss.config.js tại thư mục gốc của dự án. Vì Astro dùng Vite bên dưới nên PostCSS đã được hỗ trợ ngay từ đầu rồi.

// postcss.config.js
const postcssJitProps = require('postcss-jit-props')
const OpenProps = require('open-props')

module.exports = {
  plugins: [postcssJitProps(OpenProps)],
}

Sau đó chúng ta cần import 'open-props' vào src/layouts/Layout.astro nữa là xong.

---
import 'open-props'
// Còn đây là CSS chính cho toàn dự án
import '../styles/main.css'
---

<!DOCTYPE html>
<html lang="en">…</html>

⁉️ Tại sao phải import vào Layout.astro mà không bỏ vào thư mục public/ và dùng <link />?

Vì Astro sẽ bỏ qua việc xử lý, chuyển đổi, tối ưu các tập tin CSS trong thư mục public/ nên chúng ta sẽ không tận dụng được postcss-jit-props. Cũng vì lý do này mà bạn nên đưa phần CSS mà bạn viết vào src/

src/styles/
├── _normalize.css
├── _spacing.css
└── main.css

Nếu bạn dùng stylesheets của các thư viện khác như Bootstrap hay Bulma, và bạn biết chắc là mình không muốn chỉnh sửa gì chúng thì có thể bỏ vào public/ ha.

Kết quả

Nếu bạn thử inspect demo ở đây 🔗 sẽ thấy :root chỉ chứa những props được sử dụng trong src/components/Card.css. Hoặc bạn inspect Ehkoo cũng được 😉.

Chúng ta cũng có thể sử dụng những plugins khác của PostCSS, chẳng hạn như:

// postcss.config.js
const postcssJitProps = require('postcss-jit-props')
const OpenProps = require('open-props')

const plugins = [
  // Cho phép bạn import CSS từ node_modules, etc.
  // Lưu ý là plugin này luôn phải là plugin đầu tiên nhe.
  require('postcss-import'),
  require('postcss-custom-media'),
  require('postcss-calc'),
  require('postcss-each'),
  require('postcss-nested'),
  require('autoprefixer'),
  postcssJitProps(OpenProps),
]

module.exports = { plugins }

Hi vọng bạn thấy bài viết này hữu ích. Hẹn gặp lại 👋