+48

Frontend build chậm quá thì chạy về khóc với Vite

■ Intro.

Thời gian này không biết anh chị em mình có theo dõi SEA Games 31 không nhỉ ^^ Hai ngày cuối tuần vừa rồi có ai "đi bão" không =))) Chưa bao giờ chiến thắng và tinh thần thể thao cao đẹp lại thổi mạnh mẽ trên khắp con phố như vậy! Quả là một kỳ thi đấu thành công cho đoàn thể thao Việt Nam, khép lại một mùa SEA Games quá trọn vẹn 🙌  🙌  🙌

Xin chúc mừng tất cả các tuyển thủ một lần nữa!!!

Bởi vậy mới mới nói:

- Chút thay đổi chiến thuật có thể viết nên cả một lịch sử;
  Và tỉ số thì chẳng thể nào được khẳng định cho đến phút 90 của trận đấu 😌😌

Ấy là câu chuyện về trái bóng bên sân cỏ. Còn với lập trình viên chúng ta thì sao 😸😸 Chút thay đổi trong code đôi khi cũng có thể làm thay đổi cả luồng logic rồi ấy nhỉ, và tính đúng đắn cũng chẳng thể nào khẳng định được cho tới khi chương trình đã chạy xong =)))

Vậy đó giờ anh chị em đã tham gia dự án nào có build time hệ  s l o w  m o t i o n  chưa? Phải chờ tận vài giây (hoặc nhiều hơn thế =))) để chờ hot-reload sau khi chỉnh sửa vài dòng mã chẳng hạn? Hoặc thậm chí có thể mất tới 20 - 45' để có thể deploy "xong" một tiến trình - dù chỉ là lần sửa một lỗi nho nhỏ? 🥲🥲

Phím với chiếc Buddy trong team về vấn đề này, mình được gợi ý từ khoá Vite - một build tool được cộng đồng ví von là Next Generation Frontend Tooling.

Nom "chất lượng" quá nhỉ, cơ mà tìm hiểu một mình thì "buồn ơi là buồn", đồng hành cùng mình trong bài viết này nhé!

Đầu tiên, chúng ta ngó lại Module Bundler một chút!

Bạn nào rành đoạn này rồi thì có thể chuyển qua Mục tiếp theo luôn nhaa ^^

■ Module Bundler (*)

Để bắt đầu xây dựng một website theo phong cách "kinh điển" đó giờ, tất cả những gì chúng ta cần là HTML, CSS và đôi dòng JavaScript.

Nâng cấp hơn xíu xiu, khi muốn sử dụng những thư viện ngoài (Bootstrap, lodash chẳng hạn), chúng ta sẽ download chúng về và nhúng vào HTML/CSS.

Điều này thì chẳng còn xa lạ gì đối với các anh chị em web developer rồi nhỉ 😸😸

Cơ mà nếu dự án có nhiều dependencies quá thì chúng ta quản lý như thế nào đây? Luôn phải manually download mãi hay sao? Kể cả khi chúng có các bản cập nhật mới?

Đó là lý do các Package Manager như Bower, NPM, Yarn... được sinh ra "cho đời bớt khổ" =))

Với NPM chẳng hạn, chúng ta sẽ có một package.json lưu thông tin dự án, một thư mục node_modules chứa tất cả các packages - cái dễ dàng được cài đặt thông qua dòng lệnh:

$ npm i PACKAGE_NAME

và rồi đính kèm chúng vào HTML/CSS:

<script src="node_modules/.../package_1.js"></script>
<script src="node_modules/.../package_2.js"></script>
...
<script src="main.js"></script> 

<!-- Mỗi script X được định nghĩa bởi 01 global variable
=>   X có thể được dùng ở bất kì script nào được-load-sau-nó -->

Việc phải đào sâu vào node_modules để tìm vị trí của từng package và lần lượt thêm thủ công gây ra bất tiện quá!!! (sad)

Để phá vỡ nguyên tắc này, CommonJS - dự án đưa ra các đặc tả về modules - đã cho phép JavaScript được import/export:

const lodash = require('lodash');
// FYI, NodeJS là một trong những implementation phần modules của CommonJS

Nhưng Browser không có quyền truy cập đến các file hệ thống, nên để dùng module theo cách này, chúng cần được load động, bằng cách đồng bộ (sẽ làm chậm quá trình thực thi) hoặc bất đồng bộ (có thể có vấn đề về thời điểm load).

Đó là chưa kể trong quá trình phát triển, chúng ta còn cài đặt thêm các pre-processor (như Pug, SCSS,..); sử dụng ES6; tích hợp TypeScript; hay là React với JSX; rồi thì áp dụng một số phương pháp performance optimization như Code-spliting, Lazy-loading theo modules... với mục đích nâng cao developer experience. Trong khi đó, browser lại chỉ cần HTML, CSSJavaScript thôiii!?!

Với tất cả các vấn đề kể trên, một chiếc Module bundler sẽ giúp chúng ta compile, transform, optimize, minify... rồi đóng gói các modules này lại, tạo ra kết quả cuối cùng tương thích với browser.

(*) Nội dung này được tóm lược trong bài viết Giải thích về Javascript thời hiện đại cho khủng long siêu-hayyy siêu-chi-tiếttt của anh Tạ Duy Anh (respect)x10 👍️ 👍️

Có thể kể tới một vài công cụ module bundler phổ biến mà bạn có thể đã từng nghe qua như: Webpack, Parcel, Rollup, Browserify... này, và bây giờ là Vitemà chúng ta sẽ tìm hiểu ngay trong phần tiếp theoo!

■ Vite

Theo Trang chủ:

Vite is a build tool that aims to provide a faster and leaner development experience for modern web projects.

Tương tự các build tools phổ biến hiện nay, Vite có các chức năng cốt lõi như:

  • Project scaffolding thông qua các CLI generators
  • Hot Reload Module (HRM) - tự động reload modules trong quá trình dev
  • Plugin system cho phép config, custom thêm một số chức năng
  • ...


🐾 Chút Fun fact, có thể bạn ...thừa biết =)))

Vite được đọc là /vit/🔊, trong tiếng Pháp có nghĩa là "nhanh chóng".

Build tool này được phát triển bởi anh Evan You - cha đẻ của VueJS. Bảo sao mà cóV-prefix và phong cách viết document của VueVite "da same" thế (LOL).

Bên cạnh mảng Coding, anh này học cả Art, DesignUI/UX nữa nên cũng nghệ lắm anh chị em ạ (yaoming) =='



Ban đầu, Vite được tạo ra để phục vụ cho "gà cưng" VueJS, về sau thì hỗ trợ thêm React, PreactSvelte nữa 😸😸 .

Điều khiến Vite nhận được sự đón nhận tích cực từ cộng đồng là về tốc độ nổi bật của nó. Để lý giải tại sao Vite lại "nhanh" như vậy? Chúng ta cùng tìm hiểu cách hoạt động của nó trong Development buildProduction build nhé!

■ How Vite is faster?

■ Unbundled dev build

Khi chúng ta bắt đầu khởi chạy ứng dụng, Vite phân loại các modules thành 02 categories:

  • Dependency modules:

    • Chủ yếu là các plain JavaScript hoặc các modules được import từ node_modules, không thay đổi thường xuyên trong quá trình phát triển.
    • Ví dụ: Một số libraries, packages như Antd, Bootstrap, etc.
    • Các modules này sẽ được pre-bundle bằng esbuild - một JavaScript bundler được viết bằng Golang, hứa hẹn nhanh hơn người anh Webpack khoảng từ 10–100x về mặt tốc độ.
  • Application modules:

    • Là các non-plain JavaScript - cần được chuyển đổi, biên dịch,... và thường được chỉnh sửa thường xuyên.
    • Ví dụ: Component.jsx, styles.scss, etc.
    • Dùng Native ES Modules (ESM).

Với tôn chỉ On-demand compilation, Vite không-gói-tất-cả các modules lại với nhau (điều này giảm được một khối lượng công việc đáng kể). Vite chỉ cung cấp cácmodules mà trình duyệt cần. Chúng có thể là Application modules kèm Dependency modules - cái mà đã được pre-compile bằng esbuild ở lần chạy đầu tiên.

Anh Evan You cũng đã chia sẻ về hiệu quả của Native ESM dev build trong show The Open Source Friday của Github, bạn xem thêm nhé ^^

■ Bundled prod build

Ngược lại với no-bundle dev build phía trên, Vite tiếp cận prod build vẫn theo hướng bundle thông qua một module bundler có tên là Rollup.

Hmmm...

Tới đây thì một vài câu hỏi được đặt ra...

(?) Dev build phía trên sử dụng ESM rồi sao Production build không dùng luôn?

Theo chia sẻ của anh Evan You, dù hiện tại, các ESM đã được hỗ trợ ở tất cả các trình duyệt chính, song, việc gom một bundle.js kèm các kĩ thuật performance optimization: tree-shaking, lazy-loading, chunk splitting,... vẫn mang lại hiệu suất tổng thể tốt hơn là hình thức unbundled - cái mà sẽ tạo ra nhiều extra HTTP requests hơn.

Okayy, câu tiếp theo =)))

(?) Bảo esbuild nhanh, thế tại sao sang Production build, Vite còn dùng thêm Rollup chi vậy?

Vẫn theo lời anh Evan You =)) Có một số tác vụ khó thực hiện hơn khi dùng esbuild như CSS code-splitting, tự động tối ưu các đoạn mã không đồng bộ,... nên dù thời gian prod build chậm hơn chút, nhưng sẽ có performance tốt hơn cho end user. Nom như là một sự đánh đổi 😹😹

Chi tiết về bài phỏng vấn này, bạn có thể đọc thêm tại đây nhé!

Giờ thì đặt Vite cạnh Webpack - một "tượng đài" module bundler được tin dùng và sử dụng rộng rãi - để so sánh chút nào!

■ Vite vs. Webpack

■ Operating mechanism

Ngay chính trên Trang chủ, Webpack đặt nhẹ một slogan:

Bundle your scripts; Bundle your images; Bundle your styles; Bundle your assets.

Quả là một người anh bundle "cả thế giới" (J4F) =))

Theo workflow, trước một browser request, Webpack sẽ thu thập, xử lý, gom góp, đóng gói các modules lại thành 01 bundle.js để sử dụng như hình mô tả dưới:

So sánh với Vite ở phía trên một chút:

Scope Webpack Vite
Supported modules ES Modules, CommonJS, AMD Modules ES Modules
Dev Server Bundled modules served via webpack-dev-server using Express.js ES-Modules served via Vite using Koa - a lightweight node web server
Production build Webpack Rollup

Vậy còn về tốc độ thì sao?

■ Speed

Trong trận "battle" này, chúng ta sẽ so sánh một ứng dụng ReactJS lần lượt sử dụng ViteWebpack nhé!

FYI, nếu đã tiếp cận với ReactJS, hẳn bạn đã từng dùng qua Create-React-App (CRA) để khởi tạo dự án rồi nhỉ? CRA nhà mình sử dụng Webpack như 01 build tool nha. Bạn có thể ghé qua bài viết Điều React luôn giữ kín trong tim nếu muốn tìm hiểu thêm về nó.

Xem kết quả về tốc độ cho một sample app với 02 routes, 06 componentstrên cùng một máy tính:

Scope React with Webpack in CRA React with Vite
Server start duration 12s 298ms
Build duration 16.66s 9.11s

Thật ra, với ví dụ bé con phía trên, từ ms tới vài s, chúng ta vẫn có thể dễ dàng hài lòng và chấp nhận được. Song, nếu tính tỉ lệ %, giả sử quá trình build ứng dụng hiện tại của bạn đang là 30', giờ có thêm Vite, đời bỗng vui với thời gian chờ còn lại chỉ còn khoảng ~12-15'. Nghe vẻ ấn tượng quá nhỉ!

Bạn có thể xem thêm một ví dụ khác về Creation time, Project size, Build time, Build size của một anh Ấn tại video này 😸😸.


🐾 Đừng hiểu nhầm nhé !!!

Mình không cố "dìm" Webpack và "ca tụng" Vite đâu 😺😺

Chẳng phải tự nhiên mà Webpackđược tin dùng và sử dụng rộng rãi như vậy đúng không nào ^^ Bản thân nó đã và đang làm rất tốt rồi. Bắt đầu như một JavaScript-focused bundler, Webpack có các default configurations vô cùng đơn giản, cho phép chúng ta customize rất-rất-đa-dạng.

Chính vì có tính configurable linh hoạt như vậy, đa phần 90% các công cụ sử dụng Webpack đều phải config các conventions thường hay được sử dụng trong một hệ sinh thái nào đó (giả sử như việc compile ES6, JSX trong React chẳng hạn, chúng ta có Create React App).

Mục-đích-chính anh Evan You tạo ra Vite là xây dựng những default configurations tương ứng với các libraries, giúp chúng ta tập trung vào nghiệp vụ quan trọng hơn. Bên cạnh đó, vì không phải default configurationsnào cũng phù hợp nên Vite cũng cho phép chúng ta customize chút thông qua các plugins.

Thế nhưng Vite không-có-mục-tiêu-thay-thế-hoàn-toàn Webpack nha. Việc lựa chọn Vite, Webpack, Parcel hay bất kì một build tools nào cho dự án cũng tương tự như việc lựa chọn công nghệ để theo đuổi vậy. Không có công nghệ nào là tốt nhất, quan trọng hơn cả vẫn là sự phù hợp.

Quay lại bài viết của chúng ta, với ưu điểm về tốc độ của Vite như vậy, có anh chị em nào đã nghĩ tới việc đề xuất ý kiến migrate build tool của dự án hiện tại sang Vite trong buổi Daily sắp tới của team chưaaa ạ?

Trước khi đưa ra quyết định thì chúng ta cùng xem việc chuyển đổi như vậy có tốn nhiều công sức không nhé! Mình sẽ lấy ví dụ với ReactJS.

■ React with Vite

■ Init a React app with Vite

Để khởi tạo một dự án ReactJS sử dụng Vite như một build tool, chúng ta chạy dòng lệnh:

$ npm init vite PROJECT_NAME --template react

Xem qua chút folder structure thì có vài điểm khác biệt so với CRA:

Scope CRA boilerplate Vite boilerplate
Entry point index.js index.html
Dependencies react-scripts @vitejs/plugin-react
Bundler config Webpack Vite

Từ sự khác biệt này, chúng ta có các bước để migrate từ một dự án CRA đang phát triển qua dùng Vite như sau:

■ Migrate CRA to Vite

Đầu tiên, bỏ/thêm một số dependencies:

$ npm remove react-scripts
$ npm install --save-dev @vitejs/plugin-react vite 
// Vite không dùng react-scripts mà dùng chính plugin của nó

Config chút:

import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";

export default ({ mode }) => defineConfig({
    plugins: [react()],
    define: {
        "process.env.NODE_ENV": `"${mode}"`,
    }
});

Di chuyển index.html ra ngoài:

...
<link rel="icon" href="/favicon.ico" />             <!-- Bỏ "%PUBLIC_URL%" --> 
...
<div id="root"></div>
<script type="module" src="/src/index.js"></script> <!-- Đính thêm script --> 

Cập lại chút script với vite:

{
    ...
    "scripts": {
        "start": "vite",
        "build": "vite build"
    },
}

Ngoài ra, với các .env (nếu có):

// Change
REACT_APP_ENV = https://haodev.wordpress.com
// To
VITE_ENV = https://haodev.wordpress.com

Cuối cùng thì:

$ npm start 

và trải nghiệm thôiii! 😸😸

■ Sumup

Như vậy là chúng ta đã cùng nhau Có cái nhìn tổng quan về Module Bundler; Tìm hiểu và khám phá cách hoạt động của Vite; So sánh chút với người anh Webpack và Tích hợp Vite vào ứng dụng ReactJS rồi nè!!!

Mặc dù Webpack vẫn là một build tool được Next.js, Create React App,... ưa chuộng nhưng chúng ta cũng chẳng thể nào phủ nhận Vite - một ứng cử viên sáng giá trong tương lai - với những ưu điểm vượt trội về tốc độ.

Bạn nghĩ sao về build tool này, hãy chia sẻ ý kiến xuống phía dưới comments nhé!

Hy vọng rằng bài viết này có thể giúp ích được các bạn. Cảm ơn các bạn đã đọc bài chia sẻ, mình rất vui nếu được ủng hộ 01 upvote để có thêm động lực cho những bài viết sắp tới ạ ❤️



🐾 Dành cho các ace quan tâm tới Vietnam Mobile Day 2022

FYI, Vietnam Mobile Day là sự kiện thường niên do Top Dev tổ chức. Hai năm sau COVID-19, Vietnam Mobile Day 2022 với chủ đề WE CONNECT đã quay trở lại hình thức offline tại hai thành phố lớn:

  • Hà Nội: 10/06/2022 | CTM Palace
  • Hồ Chí Minh: 03/06/2022 | Melisa Center

Thông tin chi tiết về sự kiện, mình để tại đây nhé!

Mình cũng có một chiếc Early bird rùi ^^ Các anh chị em đăng ký tham gia sự kiện thì có thể sử dụng thêm 01 Voucher:

  • GIAM50K@VMD2022 để được giảm -50k (Số lượng: 05)
  • HAODEV@VMD2022 để được giảm -30k (Cập nhật: Mã này đã deactivated)

khi mua vé nhaaa ^^

Lưu ý chút là các mã không áp dụng đồng thời và số lượng giới hạn ạ ^^


Chúc các bạn tuần làm việc hiệu quả! Tiện ghé qua nhà mình chơi một chút rồi về!

■ Credits


Happy coding!


All Rights Reserved

Viblo
Let's register a Viblo Account to get more interesting posts.