Di chuyển Puppeteer sang TypeScript

Chúng tôi là những người hâm mộ cuồng nhiệt TypeScript trong nhóm DevTools. Đến mức mã mới trong DevTools đang được tạo trong đó và chúng tôi đang trong quá trình di chuyển toàn bộ mã nguồn để được TypeScript kiểm tra kiểu. Bạn có thể tìm hiểu thêm về quá trình di chuyển đó trong bài nói chuyện của chúng tôi tại Hội nghị Nhà phát triển Chrome năm 2020. Do đó, việc xem xét di chuyển toàn bộ mã nguồn của Puppeteer sang TypeScript cũng hoàn toàn hợp lý.

Lập kế hoạch di chuyển

Khi lên kế hoạch di chuyển, chúng tôi muốn có thể tiến hành từng bước nhỏ. Việc này giúp giảm mức hao tổn của quá trình di chuyển – bạn chỉ làm việc trên một phần nhỏ của mã tại một thời điểm bất kỳ – và cũng giảm rủi ro. Nếu có sự cố xảy ra ở một trong các bước, bạn có thể dễ dàng khôi phục bước đó. Puppeteer có rất nhiều người dùng và một bản phát hành bị lỗi sẽ gây ra vấn đề cho nhiều người dùng trong số đó. Vì vậy, điều quan trọng là chúng tôi phải giảm thiểu nguy cơ thay đổi có thể gây lỗi.

Chúng tôi cũng rất may mắn khi Puppeteer có một bộ kiểm thử đơn vị mạnh mẽ để bao gồm tất cả chức năng của nó. Điều này có nghĩa là chúng tôi có thể tự tin rằng chúng tôi không làm hỏng mã khi di chuyển, nhưng cũng không đưa ra các thay đổi đối với API của mình. Mục tiêu của việc di chuyển là hoàn tất quá trình này mà không để người dùng Puppeteer nào nhận ra rằng chúng tôi đã di chuyển. Các thử nghiệm là một phần quan trọng trong chiến lược đó. Nếu chưa có phạm vi kiểm thử tốt, chúng tôi sẽ thêm phạm vi đó trước khi tiếp tục di chuyển.

Việc thực hiện bất kỳ thay đổi nào về mã mà không có kiểm thử đều rất rủi ro, nhưng những thay đổi mà bạn đang tác động đến toàn bộ tệp hoặc toàn bộ mã nguồn sẽ đặc biệt rủi ro. Khi thực hiện các thay đổi về cơ chế, bạn rất dễ bỏ lỡ một bước. Trong nhiều trường hợp, các thử nghiệm đã phát hiện ra một vấn đề mà cả người triển khai và người đánh giá đều bỏ qua.

Một điều chúng tôi đã đầu tư thời gian ngay từ đầu là thiết lập tính năng Tích hợp liên tục (CI). Chúng tôi nhận thấy các lần chạy CI đối với yêu cầu kéo không ổn định và thường thất bại. Điều này xảy ra thường xuyên đến mức chúng tôi đã quen với việc bỏ qua CI và vẫn hợp nhất các yêu cầu kéo, giả sử rằng lỗi là vấn đề chỉ xảy ra một lần trên CI chứ không phải là vấn đề trong Puppeteer.

Sau một số hoạt động bảo trì chung và dành thời gian để khắc phục một số lỗi kiểm thử thông thường, chúng tôi đã đưa ứng dụng vào trạng thái vượt qua nhất quán hơn, cho phép chúng tôi lắng nghe CI và biết rằng lỗi cho thấy một vấn đề thực tế. Công việc này không hề hào nhoáng và việc xem các lần chạy CI liên tục rất khó chịu, nhưng điều quan trọng là phải có bộ kiểm thử chạy một cách đáng tin cậy khi số lượng yêu cầu kéo mà quá trình di chuyển đang gửi đến bộ kiểm thử này.

Chọn và thả một tệp

Tại thời điểm này, chúng tôi đã sẵn sàng di chuyển và có một máy chủ CI mạnh mẽ với đầy đủ các bài kiểm thử để hỗ trợ chúng tôi. Thay vì đi sâu vào một tệp bất kỳ, chúng tôi cố ý chọn một tệp nhỏ để di chuyển. Đây là một bài tập hữu ích vì giúp bạn xác thực quy trình mà bạn sắp thực hiện. Nếu cách này hiệu quả với tệp này, thì phương pháp của bạn là hợp lệ; nếu không, bạn có thể quay lại từ đầu.

Ngoài ra, việc chuyển đổi từng tệp một (và với các bản phát hành Puppeteer thông thường, nên không phải tất cả thay đổi đều được đưa vào cùng một phiên bản npm) giúp giảm thiểu rủi ro. Chúng tôi chọn DeviceDescriptors.js làm tệp đầu tiên vì đây là một trong những tệp đơn giản nhất trong toàn bộ mã nguồn. Có thể bạn sẽ cảm thấy hơi thất vọng khi thực hiện tất cả công việc chuẩn bị này và chỉ thay đổi một chút, nhưng mục tiêu không phải là thực hiện những thay đổi lớn ngay lập tức, mà là tiến hành một cách thận trọng và có phương pháp theo từng tệp. Thời gian dành cho việc xác thực phương pháp này chắc chắn sẽ giúp bạn tiết kiệm thời gian sau này trong quá trình di chuyển khi bạn gặp phải những tệp phức tạp hơn.

Chứng minh mẫu và lặp lại

Rất may là thay đổi đối với DeviceDescriptors.js đã được đưa vào toàn bộ mã nguồn thành công và kế hoạch đã hoạt động như chúng tôi mong đợi! Đến đây, bạn đã sẵn sàng bắt tay vào việc và tiếp tục thực hiện, đó chính xác là những gì chúng tôi đã làm. Việc sử dụng nhãn GitHub là một cách rất hay để nhóm tất cả các yêu cầu kéo lại với nhau và chúng tôi thấy rằng điều này rất hữu ích để theo dõi tiến trình.

Di chuyển và cải thiện sau

Đối với mọi tệp JavaScript riêng lẻ, quy trình của chúng tôi là:

  1. Đổi tên tệp từ .js thành .ts.
  2. Chạy trình biên dịch TypeScript.
  3. Khắc phục mọi vấn đề.
  4. Tạo yêu cầu lấy dữ liệu.

Hầu hết công việc trong các yêu cầu lấy dữ liệu ban đầu này là trích xuất giao diện TypeScript cho các cấu trúc dữ liệu hiện có. Trong trường hợp yêu cầu kéo đầu tiên di chuyển DeviceDescriptors.js mà chúng ta đã thảo luận trước đó, mã đã chuyển từ:

module.exports = [
  { 
    name: 'Pixel 4',
    … // Other fields omitted to save space
  }, 
  …
]

Và trở thành:

interface Device {
  name: string,
  …
}

const devices: Device[] = [{name: 'Pixel 4', …}, …]

module.exports = devices;

Trong quá trình này, chúng tôi đã kiểm tra từng dòng trong toàn bộ mã nguồn để tìm lỗi. Cũng như mọi toàn bộ mã nguồn đã tồn tại vài năm và phát triển theo thời gian, có những cơ hội để cải tiến mã và cải thiện tình hình. Đặc biệt là khi chuyển sang TypeScript, chúng tôi nhận thấy rằng việc tái cấu trúc mã một chút sẽ giúp chúng tôi dựa vào trình biên dịch nhiều hơn và cải thiện mức độ an toàn về kiểu.

Ngược lại, bạn không nên thực hiện ngay những thay đổi này. Mục tiêu của quá trình di chuyển là đưa toàn bộ mã nguồn vào TypeScript. Trong suốt quá trình di chuyển quy mô lớn, bạn nên cân nhắc rủi ro gây ra lỗi cho phần mềm và người dùng. Bằng cách giảm thiểu những thay đổi ban đầu, chúng tôi đã giảm thiểu rủi ro đó. Sau khi hợp nhất và di chuyển tệp sang TypeScript, chúng tôi có thể thực hiện các thay đổi tiếp theo để cải thiện mã nhằm tận dụng hệ thống kiểu. Hãy đảm bảo bạn đặt ra ranh giới nghiêm ngặt cho quá trình di chuyển và cố gắng tuân thủ ranh giới đó.

Di chuyển các bài kiểm thử để kiểm tra định nghĩa loại của chúng tôi

Sau khi di chuyển toàn bộ mã nguồn sang TypeScript, chúng tôi có thể tập trung vào các bài kiểm thử. Các bài kiểm thử của chúng tôi có phạm vi bao phủ rộng, nhưng tất cả đều được viết bằng JavaScript. Điều này có nghĩa là một trong những thứ họ không kiểm thử là định nghĩa kiểu của chúng tôi. Một trong những mục tiêu dài hạn của dự án (mà chúng tôi vẫn đang nỗ lực thực hiện) là cung cấp các định nghĩa kiểu chất lượng cao ngay khi xuất xưởng cùng với Puppeteer, nhưng chúng tôi không có bất kỳ quy trình kiểm tra nào trong toàn bộ mã nguồn về các định nghĩa kiểu của mình.

Bằng cách di chuyển các kiểm thử sang TypeScript (theo cùng quy trình, từng tệp một), chúng tôi đã phát hiện ra các vấn đề với TypeScript mà nếu không thì người dùng sẽ phải tìm cho chúng tôi. Giờ đây, các bài kiểm thử của chúng tôi không chỉ bao gồm tất cả chức năng mà còn đóng vai trò là một quy trình kiểm tra chất lượng cho TypeScript!

Chúng tôi đã hưởng lợi rất nhiều từ TypeScript với tư cách là những kỹ sư làm việc trên toàn bộ mã nguồn Puppeteer. Cùng với môi trường CI được cải thiện đáng kể, chúng tôi đã có thể làm việc hiệu quả hơn khi sử dụng Puppeteer và TypeScript có thể phát hiện các lỗi mà nếu không thì sẽ xuất hiện trong bản phát hành npm. Chúng tôi rất vui mừng khi cung cấp các định nghĩa TypeScript chất lượng cao để tất cả nhà phát triển sử dụng Puppeteer cũng có thể hưởng lợi từ công việc này.

Tải các kênh xem trước xuống

Hãy cân nhắc sử dụng Chrome Canary, Dev hoặc Beta làm trình duyệt phát triển mặc định. Các kênh xem trước này cho phép bạn truy cập vào các tính năng mới nhất của Công cụ cho nhà phát triển, kiểm thử các API nền tảng web tiên tiến và giúp bạn tìm ra các vấn đề trên trang web của mình trước khi người dùng tìm thấy!

Liên hệ với nhóm Chrome DevTools

Hãy sử dụng các lựa chọn sau để thảo luận về các tính năng mới, nội dung cập nhật hoặc bất kỳ nội dung nào khác liên quan đến Công cụ cho nhà phát triển.