+1

Yarn: Package manager cho JavaScript

Bài dịch từ trang Code.Facebook

Trong cộng đồng Javascript, có hàng trăm ngày đoạn code được các coder chia sẻ để chúng ta có thể tránh việc viết lại các components cơ bản, libraries hoặc frameworks. Mỗi đoạn code này lại phụ thuộc tuần tự vào các đoạn code khác, và những dependencies này được quản lý bởi Package manager. Package manager phổ biến nhất trong JavaScript là npm, cung cấp hơn 300,000 packages, hơn 5 triệu kĩ sư sử dụng và có 5 tỷ lượt tải mỗi tháng.

Chúng tôi đã sử dụng npm cho nhiều dự án tại Facebook trong một thời gian dài, nhưng khi kích thước của codebase và số kỹ sư của chúng tôi tăng lên, chúng tôi gặp một số vấn đề về consistency, security, và performance. Sau khi cố gắng giải quyết từng vấn đề được đưa ra, chúng tôi đã quyết định xây dựng một giải pháp mới để giúp quản lý các dependencies một cách đáng tin cậy hơn. Chúng tôi gọi nó là Yarn - nhanh, đáng tin cậy và an toàn hơn npm.

Khi phát triền Yarn, chúng tôi cũng nhận được sự cộng tác và giúp đỡ từ Exponent, Google, và Tilde. Với Yarn, các kĩ sư vẫn có thể tiếp tục truy cập vào npm, nhưng có thể cài đặt các packages nhanh hơn, quản lý các dependencies một cách nhất quán hơn. Yarn cho phép các kĩ sư cảm thấy nhanh hơn và tự tin khi sử dụng những đoạn code được chia sẻ, họ có thể tập trung vào những gì quan trọng trong việc xây dựng các sản phẩm và tính năng mới.

Sự phát triển của Yarn tại Facebook

Trước khi các Package managers được sử dụng, các coder JS của chúng tôi thường lưu trực tiếp các dependencies trong thư mục project hoặc sử dụng CDN. Npm là package manager JS đầu tiên, được xây dựng sau khi Node.js được giới thiệu. Npm nhanh chóng trở thành một trong những package manager phổ biến nhất trên thế giới. Hàng ngàn source projects đã được tạo ra và các coder đã chia sẻ các đoạn code của mình nhiều hơn bao giờ hết.

Nhiều dự án của chúng tôi tại Facebook, như React, phụ thuộc vào code trong npm registry. Tuy nhiên, khi chúng tôi có nhiều nhân lực hơn, chúng tôi phải đối mặt với các vấn đề về tính nhất quán khi cài đặt các dependencies giữa các máy và người dùng khác nhau. Khoảng thời gian cần thiết để kéo các dependencies và có một số mối quan tâm về bảo mật với cách thức npm lấy code về từ một vài dependencies một cách tự động. Chúng tôi đã cố gắng xây dựng các giải pháp để giải quyết những vấn đề này. Tuy nhiên mỗi lần như vậy lại có thêm các vấn đề mới nảy sinh.

Cố gắng nhân rộng npm client

Ban đầu, theo các quy tắc tốt nhất được quy định, chúng tôi chỉ kiểm tra trong package.json và yêu cầu các kỹ sư chạy npm install. Điều này đã làm việc tốt cho các kỹ sư, nhưng đã phá vỡ sự kết nối liên tục của chúng tôi, cần phải là môi trường sandbox và cắt đứt từ internet vì lý do an ninh và độ tin cậy.

Giải pháp tiếp theo mà chúng tôi thực hiện là kiểm tra tất cả node_modules ở trong repository. Khi làm việc, npm đã thực hiện một số hoạt động đơn giản một cách khá khó khăn. Ví dụ: cập nhật một phiên bản nhỏ của babel đã tạo ra 800.000 dòng commit, kích hoạt các quy tắc lint cho các chuỗi byte utf8 không hợp lệ, và nhiều hơn nữa. Kết hợp các thay đổi với node_modules thường sẽ làm các kỹ sư mất cả cả ngày. Nhóm kiểm soát nguồn của chúng tôi cũng chỉ ra rằng thư mục node_modules đã phải chịu trách nhiệm kiểm tra một lượng siêu dữ liệu vô cùng lớn. Gói React Native package.json hiện chỉ liệt kê 68 sự phụ thuộc, nhưng sau khi chạy npm install, cài đặt thư mục node_modules chứa 121.358 tệp tin.

Chúng tôi đã thực hiện một nỗ lực cuối cùng để xây dựng lại npm client nhằm hỗ trợ số lượng lớn các kỹ sư tại Facebook và số lượng mã mà chúng tôi cần phải cài đặt. Chúng tôi quyết định nén toàn bộ thư mục node_modules và tải nó lên một CDN nội bộ để cả kỹ sư và các hệ thống tích hợp liên tục của chúng tôi có thể tải xuống và sử dụng các tệp tin một cách nhất quán. Điều này cho phép chúng tôi loại bỏ hàng trăm nghìn tệp từ source control, nhưng nó còn giúp các kỹ sư truy cập internet không chỉ để pull code mới mà còn xây dựng nó.

Chúng tôi cũng đã phải giải quyết các vấn đề với tính năng shrinkwrap của npm, chúng tôi sử dụng để khóa các phiên bản dependency. Các tệp shrinkwrap không được tạo ra theo mặc định và sẽ mất đồng bộ nếu các kỹ sư quên tạo ra chúng, vì vậy chúng tôi đã viết một công cụ để xác minh rằng nội dung của tệp shrinkwrap khớp với những gì trong nút_modules. Các tệp này là các đốm màu JSON với các khóa không được sắp xếp, tuy nhiên, do đó những thay đổi đối với chúng sẽ tạo ra các commit khổng lồ, rất khó kiểm tra. Để giảm thiểu việc này, chúng tôi cần thêm một tập lệnh bổ sung để sắp xếp tất cả các entries.

Cuối cùng, cập nhật một dependency với npm cũng cập nhật nhiều file không liên quan dựa trên các quy tắc phiên bản ngữ nghĩa. Điều này làm cho mọi thay đổi lớn hơn nhiều so với dự đoán, và phải làm những việc như là committing node_modules hoặc uploading vào CDN làm cho quá trình này trở nên không lý tưởng cho các kỹ sư.

Xây dựng một client mới Thay vì tiếp tục xây dựng cơ sở hạ tầng xung quanh npm client, chúng tôi quyết định thử xem xét vấn đề một cách toàn diện hơn. Điều gì sẽ xảy ra nếu thay vào đó chúng tôi đã cố gắng xây dựng một clien mới nhằm giải quyết các vấn đề chính mà chúng tôi đang trải qua ? Sebastian McKenzie tại văn phòng London của chúng tôi bắt đầu vào ý tưởng này và chúng tôi nhanh chóng trở nên hứng thú về tiềm năng của nó.

Khi chúng tôi nghiên cứu về vấn đề này, chúng tôi đã bắt đầu nói chuyện với các kỹ sư trong ngành và nhận thấy rằng họ đã gặp phải một số vấn đề tương tự và đã cố gắng thực hiện nhiều giải pháp tương tự, thường tập trung vào giải quyết một vấn đề duy nhất tại một thời điểm. Rõ ràng là bằng cách cộng tác trên toàn bộ các vấn đề mà cộng đồng đang phải đối mặt, chúng ta có thể phát triển một giải pháp phù hợp với mọi người. Với sự trợ giúp của các kỹ sư từ Exponent, Google và Tilde, chúng tôi đã xây dựng được Yarn client, kiểm tra và xác nhận hiệu suất của nó trên mọi khung chính JS và các trường hợp sử dụng bổ sung bên ngoài Facebook.

Giới thiệu về Yarn Sợi là một package manager mới thay thế quy trình làm việc hiện tại cho npm client hoặc các package manager khác trong khi vẫn tương thích với bộ máy đăng ký npm. Nó có cùng một tính năng thiết lập như công việc hiện tại trong khi hoạt động nhanh hơn, an toàn hơn, và đáng tin cậy hơn. Chức năng chính của bất kỳ package manager nào là cài đặt một số package - đoạn code nhằm mục đích cụ thể - từ global registry vào môi trường local của coder. Mỗi gói có thể hoặc không thể phụ thuộc vào các gói khác. Một dự án điển hình có thể có hàng chục, hàng trăm, thậm chí hàng ngàn gói trong cây phụ thuộc của nó.

Những dependencies được phiên bản hóa và cài đặt dựa trên phiên bản ngữ nghĩa (semver). Semver định nghĩa một lược đồ phiên bản phản ánh các loại thay đổi trong mỗi phiên bản mới, cho dù một thay đổi phá vỡ một API, thêm một tính năng mới hay sửa lỗi. Tuy nhiên, semver dựa vào các package developers không mắc sai lầm - những thay đổi đột phá hoặc những lỗi mới có thể tìm ra cách để cài đặt dependencies nếu các phụ thuộc không bị khóa.

Kiến trúc Trong hệ sinh thái Node, các thuộc tính được đặt trong một thư mục node_modules trong project của bạn. Tuy nhiên, cấu trúc tệp tin này có thể khác với cây dependency thực tế vì các phụ thuộc trùng lặp được hợp nhất lại với nhau. Khách hàng npm cài đặt các dependency vào thư mục node_modules không xác định. Điều này có nghĩa là dựa trên thứ tự dependency được cài đặt, cấu trúc của một thư mục node_modules của mỗi người có thể khác nhau. Những khác biệt này có thể gây ra lỗi mà phải mất một thời gian dài chúng ta mới có thể tháo gỡ.

Yarn xử lý các vấn đề này xung quanh version và on-determinism bằng cách sử dụng lockfiles và một thuật toán cài đặt đó là xác định và đáng tin cậy. Các lockfiles này khóa các phụ thuộc được cài đặt vào một version cụ thể và đảm bảo rằng mọi kết quả sẽ được kết hợp với cùng một cấu trúc tập tin giống nhau trong node_modules trên tất cả các máy. Kịch bản bằng văn bản sử dụng một định dạng súc tích với các phím được đặt hàng để đảm bảo rằng những thay đổi là tối thiểu và đánh giá là đơn giản.

Quá trình cài đặt được chia thành ba bước: - 1. Resolution: Yarn bắt đầu giải quyết các mối quan hệ dependency bằng cách yêu cầu đăng ký và tìm kiếm từng loại dependency. - 2. Fetching: Tiếp theo, Yarn tìm trong một thư mục bộ nhớ cache global để xem nếu package cần thiết đã được tải về. Nếu không, Yarn sẽ tìm kiếm package tarball cho package và đặt nó vào bộ nhớ cache global để nó có thể hoạt động ngoại tuyến và sẽ không cần phải tải về các dependency nhiều hơn một lần. Dependency cũng có thể được đặt trong kiểm soát nguồn như tarballs cho cài đặt ngoại tuyến đầy đủ. - 3. Linking: Cuối cùng, Yarn kết nối tất cả mọi thứ bằng cách sao chép tất cả các tệp tin cần thiết từ bộ nhớ cache global vào thư mục node_modules địa phương.

Bằng cách phá vỡ các bước này một cách sạch sẽ và có kết quả xác định, Yarn có thể song song hóa các hoạt động, tối đa hóa việc sử dụng resource và làm cho tiến trình cài đặt nhanh hơn. Trên một số dự án của Facebook, Yarn giảm quá trình cài đặt theo thứ tự độ lớn, từ vài phút đến vài giây. Yarn cũng sử dụng một mutex để đảm bảo rằng nhiều trường hợp chạy CLI không va chạm và gây ô nhiễm lẫn nhau.

Trong suốt quá trình này , Yarn buộc phải đảm bảo nghiêm ngặt về cài đặt package. Bạn có quyền kiểm soát vòng đời nào được thực hiện cho gói nào. Gói checksums cũng được lưu trữ trong lockfile để đảm bảo rằng bạn nhận được cùng một gói mỗi thời gian duy nhất.

Tính năng Ngoài việc cài đặt nhanh hơn và đáng tin cậy hơn, Yarn có các tính năng bổ sung để đơn giản hóa công việc quản lý dependency. - Khả năng tương thích với cả công việc NPM và Bower và hỗ trợ việc đăng ký trộn. - Khả năng hạn chế giấy phép của các modules installed và phương tiện để xuất ra thông tin giấy phép. - Trình bày một API JS công khai ổn định với khai thác thông qua các công cụ xây dựng. - Có thể đọc, tối thiểu, kết xuất CLI khá.

Yarn trong sản xuất Tại Facebook, chúng tôi đã sử dụng Yarn trong công việc, và chúng tôi đang làm việc rất tốt. Nó hỗ trợ dependency và quản lý package cho nhiều dự án JavaScript của chúng tôi. Với mỗi lần di chuyển, chúng tôi đã cho phép các kỹ sư xây dựng ngoại tuyến và giúp tăng tốc công việc của họ. Bạn có thể xem thời gian cài đặt cho Yarn và ví dụ như thế nào so sánh với phản ứng Native trong các điều kiện khác nhau mà bạn có thể tìm thấy ở đây.

Getting started Rất đơn giản để cài đặt Yarn

npm install -g yarn
yarn

Yarn CLI thay thế cho NPM trong quy trình phát triển của bạn, hoặc với một lệnh phù hợp hoặc một lệnh mới tương tự: - npm install → yarn : Không có đối số nào, lệnh yarn sẽ đọc package.json gói của bạn, lấy các packages từ đăng ký npm và nạp thư mục node_modules của bạn. Nó tương đương với chạy npm install - npm install --save <name> → yarn add <name> : Chúng tôi gỡ bỏ hành vi "ẩn danh không nhìn thấy được" của npm install <name> và chia lệnh. Chạy yarn thêm <name> tương đương với chạy npm install --save <name>.

Tương lai Nhiều người trong chúng ta đã cùng nhau xây dựng Yarn để giải quyết các vấn đề chung và chúng tôi biết rằng chúng tôi muốn Yarn là một dự án cộng đồng thật sự mà mọi người đều có thể sử dụng. Yarn có sẵn trên GitHub và chúng tôi đã sẵn sàng cho cộng đồng Node làm những gì tốt nhất: Sử dụng Yarn, chia sẻ ý tưởng, viết tài liệu, hỗ trợ lẫn nhau và giúp xây dựng một cộng đồng lớn để chăm sóc nó. Chúng tôi tin rằng yarn đã được khởi sự tuyệt vời, và có thể được tốt hơn với sự giúp đỡ của bạn.


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí