tháng 5 28, 2021

Tìm hiểu TailwindCSS và AlpineJS trong Phoenix (Phần 1)

Tìm hiểu TailwindCSS và AlpineJS trong Phoenix (Phần 1)

TAPE là chú phượng hoàng Phoenix (Live View), mang trong mình dòng máu thần Elixir, khoác trên mình bộ lông bắt mắt TailwindCSS và bay lượn nhẹ nhàng trong không trung cùng AlpineJS. Với TAPE stack, chúng ta có thể dễ dàng tạo ra những ứng dụng web mạnh mẽ và hiện đại. Qua se-ri bài viết này, ta sẽ cùng tìm hiểu về phần front-end của TAPE, bao gồm TailwindCSS và AlpineJS.

TailwindCSS là gì?

Các framework CSS như Bootstrap, Foundation, Bulma đi theo hướng tiếp cận “Component first”, cung cấp sẵn các component, giúp lập trình viên nhanh chóng xây dựng nên giao diện trang web. Điều này khá phù hợp với các trang web không yêu cầu nhiều về giao diện nhưng khi cần tuỳ biến thì sẽ nảy sinh nhiều vấn đề khá phiền toái. Vậy với những người không rành về CSS như mình thì giải pháp là gì? Đó chính là một low-level framework CSS. Nó cho phép lập trình viên không phải bỏ thời gian và công sức ngồi viết code CSS thuần nhưng vẫn đủ tuỳ biến để xây dựng các trang web giao diện phức tạp. Và low-level framework CSS phổ biến nhất chính là TailwindCSS.

TailwindCSS đi theo hướng tiếp cập "Utility-first". Nói nôm na thì các thuộc tính CSS (khoảng 85%) đã được class hoá và chỉ cần sử dụng các class để tạo ra giao diện mong muốn chứ không cần phải viết code CSS.

Bên cạnh đó thì cũng có khá nhiều component được mọi người chia sẻ, ta có thể tham khảo và sử dụng (tìm hiểu thêm tại đây).

Ở đây mình xin không trình bày sâu hơn về TailwindCSS mà đi vào luôn phần thiết lập TailwindCSS cho một project Phoenix.

Thiết lập Tailwind cho dự án Phoenix

Phoenix sử dụng webpack để quản lý assets của web. Pipeline xử lý code CSS trong dự án của webpack như sau:

Webpack pipeline

Bước 1: Cài đặt Tailwind

Đầu tiên ta cài đặt các package cần thiết bằng cách chạy câu lệnh sau trong thư mục web của dự án:

$ cd assets
$ npm install tailwindcss@latest postcss@latest postcss-loader@4.2 postcss-import@latest autoprefixer@latest --save-dev
  • postcss-loader: load và chèn kết quả xử lý của pipeline PostCSS vào pipeline webpack. Chú ý: webpack đi kèm với Phoenix hoạt động với bản 4.2.0.
  • postcss: là công cụ để ghép nối các plugin PostCSS thành pipeline.
  • postcss-import: hợp nhất các file CSS riêng lẻ qua câu lệnh @import khi build.
  • tailwindcss: thay các code của tailwindcss bằng code CSS thuần tương ứng.
  • autoprefixer: thêm các prefix của các vendor như -webkit, -moz, -ms vào code CSS.

Bước 2: Thiết lập PostCSS pipeline

Tiếp đó, ta cần thiết lập PostCSS pipeline. Tạo file postcss.config.js

$ cd assets
$ touch postcss.config.js

với nội dung sau.

module.exports = {
  plugins: {
    "postcss-import": {},
    tailwindcss: {},
    autoprefixer: {}
  }
}
Thứ tự các plugin trong pipeline không được thay đổi

Bước 3: Nối PostCSS pipeline vào Webpack pipeline

Sau khi PostCSS được thiết lập xong, ta cần kết nối nó vào Webpack pipeline bằng postcss-loader. Mở file assets/webpack.config.js và tìm phần thiết lập cho CSS

{
  test: /\.[s]?css$/,
  use: [
    MiniCssExtractPlugin.loader,
    'css-loader',
    'sass-loader',
  ]
}
Phoenix 1.5

Thêm 'postcss-loader' vào giữa 'css-loader' và 'sass-loader' như sau.

{
  test: /\.[s]?css$/,
  use: [
    MiniCssExtractPlugin.loader,
    'css-loader',
    'postcss-loader',  # <-------------- thêm vào đây
    'sass-loader',
  ]
}
Thứ tự các loader không được thay đổi

Bước 4: Thiết lập cho Tailwind

Đầu tiên, tạo file thiết lập tailwind.config.js với các giá trị mặc định bằng câu lệnh.

$ cd assets
$ npx tailwindcss init

Mặc định, tailwind sẽ sinh ra rất nhiều utility class. Điều này giúp thuận tiện cho việc phát triển vì luôn có sẵn mọi class để dùng. Tuy nhiên sẽ có rất nhiều class mà chúng ta sẽ không dùng tới và cần phải xoá đi trước khi đưa vào production.

Đối với Phoenix, CSS có thể được dùng trong các view module, các template và các file javascript, nên ta cần thêm danh sách các file này vào thiết lập purge của file tailwind.config.js như bên dưới.

module.exports = {
  purge: [
    '../lib/**/*.ex',
    '../lib/**/*.leex',
    '../lib/**/*.eex',
    './js/**/*.js'
  ],
  theme: {},
  variants: {},
  plugins: []
};

Và khi ta deploy production, Tailwind sẽ tìm các class được sử dụng trong dự án và loại bỏ phần không sử dụng.

"deploy": "NODE_ENV=production webpack --mode production"
Cập nhật câu lệnh deploy trong mục scripts của file package.json

Bước 5: Nhúng các utility class của Tailwind vào dự án

Cách 1: Sử dụng Tailwind directive

Thêm 3 directive sau vào đầu file assets/css/app.scss:

@tailwind base;
@tailwind components;
@tailwind utilities;

Và các file code CSS khác có thể được import vào bên dưới.

@import "./phoenix.css" /* có thể xoá nếu không sử dụng */
@import "./your-custom.css"

Khi làm việc với Tailwind, nếu một tập hợp các class được sử dụng nhiều nơi (ví dụ các style cho button), ta có thể tách chúng thành một component class riêng để tái sử dụng bằng directive @apply.

Các định nghĩa class riêng này được thêm vào file app.scss, ngay bên dưới 3 tailwind directive như ví dụ sau.

@tailwind base;
@tailwind components;
@tailwind utilities;

@layer components {
  .custom-btn-1 {
    @apply your-combination-classes-1;
  }
  
  .custom-btn-2 {
    @apply your-combination-classes-2;
  }
  ...
}

Việc đưa các component class vào trong @layer components là không bắt buộc nhưng nên thực hiện, vừa dễ quản lý vừa tránh xung đột về sau.

Cách 2: Sử dụng @import

Trong một dự án lớn, để dễ quản lý, thông thường ta sẽ chia các component class ra các file riêng (ví dụ components/buttons.css) và sau đó nhúng các file đó vào app.scss thông qua plugin postcss-import.

Bởi postcss-import yêu cầu tất cả các câu lệnh @import phải nằm ở đầu file nên thay vì sử dụng Tailwind directive ta sẽ sử dụng @import để nhúng các class của Tailwind trong thư mục node_modules vào đầu file app.scss như sau:

@import "tailwindcss/base";
@import "tailwindcss/components";
@import "tailwindcss/utilities";

@import "./components/buttons.css";

Như vậy sau 5 bước cài đặt trên, TailwindCSS đã sẵn sàng để sử dụng. Phần tiếp theo, ta sẽ tìm hiểu cách cài đặt AlpineJS.

(Còn tiếp...)