Linear: Now
92

Thủ thuật

Linear tái cấu trúc ứng dụng React sang StyleX: Kinh nghiệm từ hơn 1.000 PR

(giờ Việt Nam)

Tóm tắt AI

Linear chuyển đổi từ styled-components sang StyleX để tối ưu hiệu năng React 18, kết hợp codemod và AI agent để xử lý hơn 1.000 PR một cách hiệu quả.

Bản dịch AI

Styling Linear for the future with StyleX

Mất nhiều thời gian hơn dự kiến và đôi khi là một cuộc vật lộn để duy trì đà phát triển, nhưng sau hơn 1.000 PR, cuối cùng chúng tôi đã chuyển đổi các ứng dụng React của Linear từ styled-components sang StyleX.

styled-components đã phục vụ Linear rất tốt trong một thời gian dài. API của nó rất linh hoạt, các kiểu dáng (styles) được đặt cùng chỗ với các thành phần (components) và bạn có thể sử dụng CSS thông thường bất cứ khi nào cần tùy chỉnh thêm. Điều đó rất phù hợp với chúng tôi vì đội ngũ của chúng tôi đặc biệt nhạy cảm với những chi tiết nhỏ, chẳng hạn như những đường bo góc (border radius) gây khó chịu.

Tuy nhiên, cuối cùng thì khả năng tùy biến vô tận lại trở thành một gánh nặng.

CSS vốn đã khiến việc tạo kiểu từ xa trở nên quá dễ dàng, và các mẫu như styled(Button) đã biến việc mở lại một component từ bên ngoài trở thành chuyện bình thường thay vì tạo ra một hợp đồng tạo kiểu (styling contract) rõ ràng. Chúng tôi đã cảm nhận rõ rệt nỗi đau này sau đợt thiết kế lại Linear vài tháng trước, điều khiến chúng tôi phải chạy theo xử lý hàng loạt các lỗi hồi quy UI (UI regressions).

Khi đội ngũ phát triển, chúng tôi muốn tạo ra một nền tảng vững chắc hơn cho cách thức cấu trúc UI. Việc xác định các ranh giới này đang trở nên đặc biệt quan trọng khi các tác nhân (agents) đóng góp ngày càng nhiều vào codebase của chúng tôi.

Một lý do thực tế khác cho việc chuyển đổi là hiệu năng. Chúng tôi quan tâm đến việc giữ cho Linear luôn nhanh và CSS-in-JS làm tăng khối lượng công việc trong quá trình render để tạo kiểu và chèn các quy tắc CSS. Giọt nước tràn ly là sự sụt giảm hiệu năng mà chúng tôi thấy sau khi nâng cấp lên React 18, phiên bản giới thiệu cơ chế render đồng thời (concurrent rendering), trong khi styled-components đã chuyển sang chế độ bảo trì.

Câu hỏi đặt ra là làm thế nào để chuyển đổi một codebase lớn và đang hoạt động mà không làm đình trệ công việc sản phẩm. Các đợt chuyển đổi có vẻ là lựa chọn tự nhiên cho các tác nhân lập trình vì phần lớn công việc mang tính lặp đi lặp lại, nhưng dự án này có quá nhiều trường hợp ngoại lệ để có thể bàn giao hoàn toàn.

Tuy nhiên, khi quá trình chuyển đổi kéo dài, năng lực của các mô hình đã thay đổi. Fable và Sol ra mắt giữa dự án, giúp các tác nhân có khả năng thực hiện công việc tốt hơn. Những gì theo sau đây là tất cả những gì chúng tôi đã học được trong một quá trình chuyển đổi kết hợp giữa công cụ xác định (deterministic tooling), tác nhân và sự đánh giá của con người, với mỗi yếu tố đảm nhận nhiều hoặc ít khối lượng công việc hơn khi dự án tiến triển.

Lý do chọn StyleX

Trong quá trình tìm kiếm các giải pháp thay thế, chúng tôi đã chốt lại một bộ các yêu cầu bắt buộc cho thư viện tiếp theo của mình. Bất cứ thứ gì chúng tôi chọn đều phải thực hiện phần lớn việc tạo kiểu tại thời điểm build thay vì trong lúc ứng dụng render. Nó phải khiến việc tạo kiểu từ xa trở nên khó khăn một cách có chủ đích, chứ không chỉ là bị ngăn cản bởi quy ước, đồng thời cung cấp cho các component cách để công khai các hợp đồng tạo kiểu rõ ràng. Việc hợp nhất kiểu (style merging) phải có thể dự đoán được giữa các tệp mà không cần các trò chơi về độ ưu tiên (specificity games). Và thư viện đó phải hoạt động tốt với React, được duy trì tích cực và mang lại cảm giác an toàn cho mục tiêu dài hạn.

Công thái học cho nhà phát triển (Developer ergonomics) cũng rất quan trọng, và ngày càng quan trọng hơn là công thái học cho tác nhân (agent ergonomics). Các trường hợp phổ biến phải đơn giản, các kiểu dáng phải nằm gần các component và phải có các lối thoát thực dụng khi bạn cần.

Chúng tôi đã xem xét hầu hết các tùy chọn tạo kiểu chính có sẵn cho React. Giải pháp thay thế gần nhất là vanilla-extract, cung cấp cho chúng tôi khả năng trích xuất tĩnh và tính an toàn kiểu dữ liệu (type safety) mạnh mẽ. Nhưng API của nó có vẻ phân mảnh hơn và việc tách biệt giữa các tệp component và tệp style không phù hợp với cách chúng tôi làm việc.

StyleX của Meta mang lại sự cân bằng tốt hơn. Các kiểu dáng được đặt cùng chỗ với các component, API nhỏ gọn và việc phân giải kiểu dáng mang tính xác định. Nó cũng cung cấp cho chúng tôi các hợp đồng tạo kiểu an toàn về kiểu dữ liệu và cố tình làm cho việc can thiệp vào một component để tạo kiểu lại từ bên ngoài trở nên khó khăn hơn.

Những ràng buộc đó đi kèm với sự đánh đổi. Việc chuyển đổi từ sự linh hoạt hoàn toàn của CSS template literals sang một hệ thống nguyên tử (atomic system) bị hạn chế khiến một số mẫu trở nên khó thực hiện hơn, bao gồm các bộ chọn phụ thuộc vào cha (parent-dependent selectors), bộ chọn toàn cục và việc tạo kiểu lại component thông qua các wrapper. Tuy nhiên, trớ trêu thay, đó cũng chính là mục đích. Nhiều mẫu khó chuyển đổi nhất lại chính là những thứ khiến hệ thống cũ trở nên khó kiểm soát ở quy mô lớn.

Cách chúng tôi thực hiện một cuộc chuyển đổi khổng lồ

Nếu bắt đầu cuộc chuyển đổi này ngay hôm nay, chúng tôi sẽ dựa vào Fable và Sol nhiều hơn để thực hiện trực tiếp. Tuy nhiên, khi chúng tôi bắt đầu, styled-components đã khiến đây trở thành một cuộc chuyển đổi đặc biệt khó tự động hóa vì nó cung cấp một ngôn ngữ Turing-complete, toàn bộ sức mạnh của CSS và một API hoàn toàn mở. Có vô số cách để thể hiện cùng một ý định, và vào thời điểm đó, các tác nhân rất dễ đưa ra kết quả trông có vẻ đúng nhưng thực tế lại không phải vậy.

Việc Linear không có một hệ thống thiết kế (design system) chính thức đã làm cho điều này trở nên khó khăn hơn. Chúng tôi có các component dùng chung, nhưng nhiều trong số đó phát triển với các API rộng thay vì các hợp đồng tạo kiểu rõ ràng.

Với những ràng buộc này, tôi bắt đầu với một codemod mang tính xác định. styled-components-to-stylex-codemod bắt đầu như một bộ kiểm thử lớn và một kiến trúc khá thận trọng, sau đó các tác nhân đã giúp xây dựng nó. Nó bao gồm một playground trực tuyến, xử lý bộ chọn chéo tệp và phạm vi hồi quy cho hầu hết các trường hợp ngoại lệ mà chúng tôi đã gặp phải.

Giảm thiểu rủi ro trong quá trình chuyển đổi

styled-components và StyleX sẽ phải cùng tồn tại trong một thời gian vì chúng tôi không muốn đóng băng việc phát triển sản phẩm. Chúng tôi đã giảm thiểu rủi ro trong giai đoạn trung gian đó bằng một vài cách:

Khuyến khích áp dụng trên toàn đội ngũ

Ngoài các chi tiết kỹ thuật của quá trình chuyển đổi, chúng tôi cũng cần thúc đẩy mọi người rời xa styled-components. Chúng tôi muốn làm cho sự tiến bộ trở nên rõ ràng và tạo đà để đưa phần còn lại của codebase sang StyleX.

Chúng tôi đã thêm một bộ đếm vào thanh công cụ dev để theo dõi số lượng styled-components vẫn còn trên trang, vì vậy con số sẽ tăng hoặc giảm khi bạn điều hướng qua Linear.

Dark-themed interface showing a performance toolbar. A tooltip reading “styled-components CSS rule count” points to a highlighted metric showing a broom icon and the value 175, alongside Delay, Jank, Dark-themed interface showing a performance toolbar. A tooltip reading “styled-components CSS rule count” points to a highlighted metric showing a broom icon and the value 175, alongside Delay, Jank,

Chúng tôi cũng xây dựng một công cụ làm nổi bật những component nào đang sử dụng styled-components so với StyleX, giúp chúng tôi dễ dàng nhận biết liệu một phần cụ thể của codebase đã được chuyển đổi hay chưa, nhưng quan trọng hơn là nó đóng vai trò như nguồn cảm hứng để mọi người chuyển đổi khỏi styled-components.

Đã trôi qua 00:00

Thời gian còn lại không xác định

Chúng tôi liên tục tạo biểu đồ để theo dõi tiến độ chuyển đổi trên toàn bộ codebase và ước tính khi nào chúng tôi có thể chính thức nói lời tạm biệt với styled-components (vâng, chúng tôi đã ăn mừng bằng đồ uống trên Zoom).

Tỷ lệ áp dụng StyleX mỗi tuần

Các tệp Styled-components Các tệp chỉ dùng StyleX

Các tệp Styled-components được thêm vào mỗi tuần

Cuối cùng, một con bot đã cảnh báo về các styled-components mới trong các PR, giúp chúng tôi có trách nhiệm hơn và khiến các lỗi hồi quy khó lọt qua hơn.

Thực thi StyleX ở quy mô lớn

Chúng tôi cũng xây dựng công cụ để thực thi các quy ước mà chúng tôi muốn codebase có sau khi chuyển đổi.

Các quy tắc lint tùy chỉnh làm cho con đường dự định trở nên rõ ràng và ngăn chặn các mẫu cũ quay trở lại. Oxlint xử lý các kiểm tra nhanh, cục bộ, bao gồm các lỗi soạn thảo phổ biến, việc sử dụng design-token và các trường hợp mà React props có thể ghi đè lên đầu ra StyleX đã tạo.

Một số quy tắc cần nhiều ngữ cảnh hơn mức mà một trình linter theo từng tệp có thể cung cấp, vì vậy chúng tôi cũng đã xây dựng một trình kiểm tra kho lưu trữ tùy chỉnh có nhận thức về kiểu dữ liệu (type-aware). Nó theo dõi các component, import và style giữa các tệp để xác minh các API tạo kiểu và phát hiện các trường hợp mà hành vi hợp nhất cấp thuộc tính của StyleX có thể vô tình xóa bỏ các kiểu cơ sở hoặc kiểu có điều kiện.

Các quy tắc này được chia thành một vài nhóm chính:

Cuối cùng, chúng tôi đã thêm một vài tiện ích mở rộng tại thời điểm build cho Vite cho các hành vi mà StyleX không hỗ trợ trực tiếp, chẳng hạn như phản hồi nhất quán khi di chuột và nhấn trên các thiết bị con trỏ và cảm ứng.

ReactStyleXAI AgentRefactoringFrontend
Đọc bài gốc

Bài viết được AI dịch và tổng hợp tự động từ Linear: Now. Liên kết bài gốc ở phía trên. Dữ liệu đồng bộ qua API công khai được ghi nguồn tại AI HOT (canonical) ↗. AIHOT.vn luôn dẫn nguồn đầy đủ — nếu bạn thấy điểm cần chỉnh sửa, hãy gửi ý kiến tại trang phản hồi.