Nghiên cứu điển hình: Gỡ lỗi góc hiệu quả hơn bằng Công cụ cho nhà phát triển

Victor Porof
Victor Porof
Bramus
Bramus

Cải thiện trải nghiệm gỡ lỗi

Trong vài tháng qua, nhóm Công cụ của Chrome cho nhà phát triển đã cộng tác với nhóm Angular để cải tiến trải nghiệm gỡ lỗi trong Công cụ của Chrome cho nhà phát triển. Thành viên của cả hai nhóm đã làm việc cùng nhau và thực hiện các bước hướng tới tạo điều kiện cho các nhà phát triển gỡ lỗi và phân tích tài nguyên về ứng dụng web từ góc độ tác giả: xét về ngôn ngữ nguồn và cấu trúc dự án, đồng thời có quyền truy cập vào thông tin quen thuộc và phù hợp với họ.

Bài đăng này sẽ xem xét nâng cao để biết cần có những thay đổi nào trong Angular và Chrome Công cụ cho nhà phát triển để đạt được điều này. Mặc dù một số thay đổi này được thể hiện thông qua Angular, nhưng cũng có thể áp dụng cho các khung khác. Nhóm Công cụ của Chrome cho nhà phát triển khuyến khích các khung khác áp dụng API bảng điều khiển mới và các điểm tiện ích của bản đồ nguồn để họ cũng có thể cung cấp trải nghiệm gỡ lỗi tốt hơn cho người dùng.

Mã trang thông tin bỏ qua

Khi gỡ lỗi ứng dụng bằng Công cụ của Chrome cho nhà phát triển, tác giả thường chỉ muốn xem chỉ mã của họ chứ không muốn xem mã của khung bên dưới hoặc một phần phụ thuộc nào đó nằm gọn trong thư mục node_modules.

Để đạt được điều này, nhóm Công cụ cho nhà phát triển đã giới thiệu một tiện ích cho bản đồ nguồn, có tên là x_google_ignoreList. Tiện ích này được dùng để xác định các nguồn của bên thứ ba, chẳng hạn như mã khung hoặc mã do trình gói tạo. Khi một khung sử dụng tiện ích này, tác giả giờ đây sẽ tự động tránh sử dụng mã mà họ không muốn xem hoặc thực hiện mà không phải định cấu hình trước phần mở rộng này theo cách thủ công.

Trong thực tế, Công cụ của Chrome cho nhà phát triển có thể tự động ẩn mã được xác định trong dấu vết ngăn xếp, cây Nguồn, hộp thoại Mở nhanh, đồng thời cũng cải thiện hành vi bước và tiếp tục trong trình gỡ lỗi.

Ảnh GIF động minh hoạ Công cụ cho nhà phát triển trước và sau. Lưu ý cách Công cụ cho nhà phát triển hình ảnh sau hiển thị Mã tác giả trong cây, không còn đề xuất bất kỳ tệp khung nào trong trình đơn "Mở nhanh" nữa và hiển thị dấu vết ngăn xếp gọn gàng hơn nhiều ở bên phải.

Phần mở rộng về bản đồ nguồn x_google_ignoreList

Trong bản đồ nguồn, trường x_google_ignoreList mới tham chiếu đến mảng sources và liệt kê chỉ mục của mọi nguồn của bên thứ ba đã biết trong bản đồ nguồn đó. Khi phân tích cú pháp bản đồ nguồn, Công cụ của Chrome cho nhà phát triển sẽ sử dụng công cụ này để tìm ra những phần nào của mã nên được đưa vào danh sách bỏ qua.

Dưới đây là bản đồ nguồn cho một tệp đã tạo out.js. Có hai sources gốc đã góp phần tạo ra tệp đầu ra: foo.jslib.js. Lý do là một nhà phát triển trang web đã viết ra, còn phần sau là một khung mà họ sử dụng.

{
  "version" : 3,
  "file": "out.js",
  "sourceRoot": "",
  "sources": ["foo.js", "lib.js"],
  "sourcesContent": ["...", "..."],
  "names": ["src", "maps", "are", "fun"],
  "mappings": "A,AAAB;;ABCDE;"
}

sourcesContent được bao gồm cho cả hai nguồn ban đầu này và Công cụ của Chrome cho nhà phát triển sẽ hiển thị các tệp này theo mặc định trên Trình gỡ lỗi:

  • Dưới dạng tệp trong cây Nguồn.
  • Kết quả trong hộp thoại Mở nhanh.
  • Khi các vị trí khung lệnh gọi đã được ánh xạ trong dấu vết ngăn xếp lỗi khi tạm dừng trên một điểm ngắt và trong khi bước.

Có thêm một thông tin bổ sung hiện có thể được đưa vào bản đồ nguồn để xác định nguồn nào trong số đó là mã của bên thứ nhất hay mã của bên thứ ba:

{
  ...
  "sources": ["foo.js", "lib.js"],
  "x_google_ignoreList": [1],
  ...
}

Trường x_google_ignoreList mới chứa một chỉ mục duy nhất tham chiếu đến mảng sources: 1. Điều này chỉ rõ rằng những khu vực được liên kết tới lib.js thực tế là mã của bên thứ ba và sẽ được tự động thêm vào danh sách bỏ qua.

Trong một ví dụ phức tạp hơn, như minh hoạ bên dưới, chỉ mục 2, 4 và 5 chỉ định rằng các khu vực được ánh xạ tới lib1.ts, lib2.coffeehmr.js đều là mã của bên thứ ba cần được tự động thêm vào danh sách bỏ qua.

{
  ...
  "sources": ["foo.html", "bar.css", "lib1.ts", "baz.js", "lib2.coffee", "hmr.js"],
  "x_google_ignoreList": [2, 4, 5],
  ...
}

Nếu bạn là nhà phát triển khung hoặc trình đóng gói, hãy đảm bảo bản đồ nguồn được tạo trong quá trình xây dựng có trường này để kết nối với những tính năng mới này trong Công cụ của Chrome cho nhà phát triển.

x_google_ignoreList trong Angular

Kể từ phiên bản Angular v14.1.0, nội dung của các thư mục node_moduleswebpack đã được đánh dấu là "để bỏ qua".

Điều này đạt được nhờ thay đổi trong angular-cli bằng cách tạo một trình bổ trợ kết nối với mô-đun Compiler của webpack

Trình bổ trợ webpack mà các kỹ sư của chúng tôi đã tạo các hook vào giai đoạn PROCESS_ASSETS_STAGE_DEV_TOOLING và điền sẵn trường x_google_ignoreList trong bản đồ nguồn cho những thành phần cuối cùng mà webpack tạo ra và trình duyệt tải.

const map = JSON.parse(mapContent) as SourceMap;
const ignoreList = [];

for (const [index, path] of map.sources.entries()) {
  if (path.includes('/node_modules/') || path.startsWith('webpack/')) {
    ignoreList.push(index);
  }
}

map[`x_google_ignoreList`] = ignoreList;
compilation.updateAsset(name, new RawSource(JSON.stringify(map)));

Dấu vết ngăn xếp được liên kết

Dấu vết ngăn xếp trả lời cho câu hỏi "tôi làm cách nào để truy cập vào đây", nhưng thông thường, điều này là từ góc độ của máy móc và không nhất thiết phải khớp với quan điểm của nhà phát triển hoặc mô hình tư duy của họ trong thời gian chạy ứng dụng. Điều này đặc biệt đúng khi một số thao tác được lên lịch diễn ra không đồng bộ sau này: bạn vẫn có thể biết được "nguyên nhân gốc" hoặc khía cạnh lập lịch của các thao tác đó, nhưng chính xác thì đó không phải là một phần của dấu vết ngăn xếp không đồng bộ.

Trong nội bộ V8 có cơ chế theo dõi các tác vụ không đồng bộ đó khi sử dụng các dữ liệu gốc trong quá trình lập lịch trình duyệt chuẩn, chẳng hạn như setTimeout. Theo mặc định, quy trình này sẽ được thực hiện trong những trường hợp đó để nhà phát triển có thể kiểm tra! Nhưng trong các dự án phức tạp hơn, điều đó không đơn giản như vậy, đặc biệt là khi sử dụng khung có cơ chế lên lịch nâng cao hơn – ví dụ: một khung thực hiện theo dõi vùng, xếp hàng tác vụ tuỳ chỉnh hoặc chia nội dung cập nhật thành nhiều đơn vị công việc chạy theo thời gian.

Để giải quyết vấn đề này, Công cụ cho nhà phát triển hiển thị một cơ chế có tên là "API gắn thẻ ngăn xếp không đồng bộ" trên đối tượng console. Cơ chế này cho phép các nhà phát triển khung gợi ý cả vị trí mà thao tác được lên lịch cũng như nơi thực thi các thao tác này.

API gắn thẻ ngăn xếp không đồng bộ

Nếu không có tính năng Gắn thẻ ngăn xếp không đồng bộ, dấu vết ngăn xếp cho mã được thực thi không đồng bộ theo những cách phức tạp bằng khung sẽ xuất hiện mà không có kết nối với mã đã được lên lịch.

Dấu vết ngăn xếp của một số mã được thực thi không đồng bộ không có thông tin về thời điểm lên lịch mã. Lớp này chỉ hiện dấu vết ngăn xếp bắt đầu từ "requestAnimationFrame" nhưng không chứa thông tin nào về thời điểm lên lịch.

Với tính năng Gắn thẻ ngăn xếp không đồng bộ, bạn có thể cung cấp ngữ cảnh này và dấu vết ngăn xếp sẽ có dạng như sau:

Dấu vết ngăn xếp của một số mã được thực thi không đồng bộ có thông tin về thời điểm lên lịch mã. Hãy lưu ý rằng, không giống như trước đây, thuộc tính này đưa "businessLogic" và "schedule" vào dấu vết ngăn xếp như thế nào.

Để đạt được điều này, hãy sử dụng một phương thức console mới có tên là console.createTask() mà API gắn thẻ ngăn xếp không đồng bộ cung cấp. Chữ ký của đoạn mã như sau:

interface Console {
  createTask(name: string): Task;
}

interface Task {
  run<T>(f: () => T): T;
}

Việc gọi console.createTask() sẽ trả về một thực thể Task mà sau này bạn có thể sử dụng để chạy mã không đồng bộ.

// Task Creation
const task = console.createTask(name);

// Task Execution
task.run(f);

Các thao tác không đồng bộ cũng có thể được lồng ghép và "nguyên nhân gốc" sẽ được hiển thị theo trình tự trong dấu vết ngăn xếp.

Tác vụ có thể chạy với số lần bất kỳ và tải trọng công việc có thể khác nhau giữa mỗi lần chạy. Ngăn xếp lệnh gọi tại trang web lên lịch sẽ được ghi nhớ cho đến khi đối tượng tác vụ là việc thu thập rác.

API gắn thẻ ngăn xếp không đồng bộ trong Angular

Trong Angular, các thay đổi đã được thực hiện đối với NgZone – ngữ cảnh thực thi của Angular vẫn tồn tại trên các tác vụ không đồng bộ.

Khi lên lịch cho một tác vụ, tính năng này sẽ sử dụng console.createTask() (nếu có). Thực thể Task thu được sẽ được lưu trữ để sử dụng tiếp. Khi gọi tác vụ, NgZone sẽ sử dụng thực thể Task đã lưu trữ để chạy tác vụ đó.

Những thay đổi này đã có trong NgZone 0.11.8 của Angular thông qua các yêu cầu lấy dữ liệu #46693#46958.

Khung cuộc gọi thân thiện

Các khung thường tạo mã từ tất cả các loại ngôn ngữ tạo mẫu khi xây dựng dự án, chẳng hạn như mẫu Angular hoặc JSX nhằm biến mã giống HTML thành JavaScript thuần tuý để rồi cuối cùng sẽ chạy trong trình duyệt. Đôi khi, những loại hàm được tạo này được đặt tên không thân thiện cho lắm — có thể là tên một chữ cái sau khi rút gọn hoặc một số tên ít người biết đến hoặc lạ lẫm ngay cả khi chúng không được dùng nữa.

Trong Angular, không phải là hiếm khi bạn thấy các khung gọi có các tên như AppComponent_Template_app_button_handleClick_1_listener trong dấu vết ngăn xếp.

Ảnh chụp màn hình dấu vết ngăn xếp có tên hàm được tạo tự động.

Để giải quyết vấn đề này, Công cụ của Chrome cho nhà phát triển hiện đã hỗ trợ việc đổi tên các hàm này thông qua bản đồ nguồn. Nếu bản đồ nguồn có mục tên được đặt ở đầu phạm vi hàm (tức là dấu ngoặc đơn bên trái của danh sách tham số), thì khung lệnh gọi phải hiển thị tên đó trong dấu vết ngăn xếp.

Khung cuộc gọi thân thiện trong Angular

Đổi tên khung gọi trong Angular là một nỗ lực không ngừng nghỉ. Chúng tôi hy vọng những cải tiến này sẽ dần được cải thiện theo thời gian.

Trong khi phân tích cú pháp các m��u HTML mà tác giả đã viết, trình biên dịch Angular tạo ra mã TypeScript. Mã này cuối cùng sẽ được dịch thành mã JavaScript mà trình duyệt tải và chạy.

Trong quá trình tạo mã này, bản đồ nguồn cũng được tạo. Chúng tôi hiện đang kh��m phá cách đưa tên hàm vào trường "tên" của bản đồ nguồn, đồng thời tham chiếu các tên đó trong mối liên kết giữa mã đã tạo và mã gốc.

Ví dụ: nếu một hàm cho trình nghe sự kiện được tạo và tên hàm không thân thiện hoặc bị xoá trong quá trình giảm kích thước, bản đồ nguồn giờ đây có thể bao gồm tên thân thiện hơn cho hàm này trong trường "tên". Giờ đây, mục ánh xạ cho phần đầu phạm vi hàm có thể tham chiếu đến tên này (tức là dấu ngoặc đơn bên trái của danh sách tham số). Sau đó, Công cụ của Chrome cho nhà phát triển sẽ sử dụng các tên này để đổi tên các khung gọi trong dấu vết ngăn xếp.

Hướng đến tương lai

Việc sử dụng Angular làm chương trình thí điểm thử nghiệm để xác minh rằng công việc của chúng tôi mang lại một trải nghiệm tuyệt vời. Chúng tôi muốn nghe ý kiến của các nhà phát triển khung và cung cấp cho chúng tôi ý kiến phản hồi về các điểm mở rộng này.

Còn có nhiều khu vực khác mà chúng tôi muốn khám phá. Cụ thể là cách cải thiện trải nghiệm lập hồ sơ trong Công cụ cho nhà phát triển.