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

Trải nghiệm gỡ lỗi được cải thiện

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 để phát hành các điểm cải tiến cho trải nghiệm gỡ lỗi trong Công cụ của Chrome cho nhà phát triển. Mọi người của cả hai nhóm đã làm việc cùng nhau và thực hiện các bước nhằm cho phép nhà phát triển gỡ lỗi và lập hồ sơ cho các ứng dụng web từ góc độ chuyên môn: về ngôn ngữ nguồn và cấu trúc dự án, với quyền truy cập thông tin quen thuộc và phù hợp với họ.

Bài đăng này sẽ xem xét chi tiết để biết những thay đổi nào cần thiết trong Angular và Công cụ của Chrome cho nhà phát triển để đạt được điều này. Mặc dù một số thay đổi trong số này được thể hiện thông qua Angular, nhưng bạn cũng có thể áp dụng những thay đổi này 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 và điểm tiện ích bản đồ nguồn mới để chúng cũng có thể mang lại trải nghiệm gỡ lỗi tốt hơn cho người dùng.

Mã danh sách 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 mã của họ, chứ không phải xem mã của khung bên dưới hoặc một số phần phụ thuộc được cất giữ 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 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 tạo gói. Giờ đây, khi một khung sử dụng tiện ích này, tác giả sẽ tự động tránh được những đoạn mã mà họ không muốn nhìn thấy hoặc không muốn sử dụng mà không phải định cấu hình trước.

Trong thực tế, Công cụ của Chrome cho nhà phát triển có thể tự động ẩn đoạn mã đã xác định được như vậy trong dấu vết ngăn xếp, cây Nguồn, hộp thoại Mở nhanh, đồng thời 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ạ trước và sau khi Công cụ cho nhà phát triển. Lưu ý làm thế nào trong quá trình Công cụ cho nhà phát triển hình ảnh hiển thị Mã được tạo trong cây, không còn đề xuất bất kỳ tệp khung nào trong trình đơn "Mở nhanh" và hiển thị dấu vết ngăn xếp rõ ràng hơn nhiều ở bên phải.

Tiện ích 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ê các chỉ mục của tất cả nguồn 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 thông tin này để xác định phần mã nào cần được đưa vào danh sách bỏ qua.

Dưới đây là bản đồ nguồn cho một tệp out.js đã tạo. Có 2 sources gốc đã góp phần tạo ra tệp đầu ra: foo.jslib.js. Ví dụ thứ hai là nội dung do một nhà phát triển trang web viết ra và tệp thứ hai 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 đưa vào 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ị những tệp này theo mặc định trên Trình gỡ lỗi:

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

Có một phần thông tin bổ sung hiện có thể được đưa vào bản đồ nguồn để xác định những nguồn đó 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 tham chiếu đến mảng sources: 1. Điều này cho biết rằng các khu vực được ánh xạ tới lib.js thực tế là mã của bên thứ ba và cần đượ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, các 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ó bao gồm trường này để kết nối với các 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ừ Angular phiên bản 14.1.0, nội dung của các thư mục node_moduleswebpack được đánh dấu là "cần bỏ qua".

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

Trình bổ trợ gói web mà các kỹ sư của chúng tôi đã tạo đã nối 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à gói web 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 "làm thế nào tôi đến đây được", nhưng thông thường, điều này là từ góc độ của máy và không nhất thiết phải là điều gì đó phù hợ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 để xảy ra không đồng bộ sau đó: vẫn có thể thú vị khi biết "nguyên nhân gốc" hoặc khía cạnh lập lịch của các hoạt động đó, nhưng chính xác thì đó sẽ không phải là một phần của dấu vết ngăn xếp không đồng bộ.

V8 trong nội bộ có cơ chế theo dõi các tác vụ không đồng bộ như vậy khi sử dụng các dữ liệu gốc để lập lịch trình duyệt chuẩn, chẳng hạn như setTimeout. Việc này được thực hiện theo mặc định trong các trường hợp đó, vì vậy các nhà phát triển có thể kiểm tra những nội dung này! Nhưng trong những 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 một khung có cơ chế lập lịch nâng cao hơn – ví dụ: một khung thực hiện việc theo dõi vùng, xếp hàng đợi công việc tuỳ chỉnh hoặc tách các 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à hoạt động được lên lịch cũng như vị trí thực thi các hoạt động 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 đối với mã được thực thi không đồng bộ theo các 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ộ mà không có thông tin về thời điểm lên lịch. Lớp này chỉ hiển thị dấu vết ngăn xếp bắt đầu từ `requestAnimationFrame` nhưng không lưu giữ thông tin nào kể từ thời điểm được 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ùng với thông tin về thời điểm lên lịch. Hãy lưu ý cách thức, không giống như trước đây, tính năng này bao gồm "businessLogic" và "lịch biểu" trong dấu vết ngăn xếp.

Để làm được điều này, hãy sử dụng phương thức console mới có tên là console.createTask() do API Gắn thẻ ngăn xếp không đồng bộ cung cấp. Chữ ký của tổ chức 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 hoạt động không đồng bộ cũng có thể được lồng vào nhau và “nguyên nhân gốc” sẽ hiển thị theo trình tự trong dấu vết ngăn xếp.

Tác vụ có thể được chạy với số lần bất kỳ và tải 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ụ được thu gom 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ụ, hệ thống sẽ sử dụng console.createTask() (nếu có). Thực thể Task thu được được lưu trữ để sử dụng thêm. 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 xuất hiện 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ữ mẫu khi xây dựng dự án, chẳng hạn như các mẫu Angular hoặc JSX biến mã có dạng HTML thành JavaScript thuần tuý mà 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 là một số tên ít người biết đến hoặc xa lạ ngay cả khi chúng không được viết tắt.

Trong Angular, bạn thường thấy các khung lệnh gọi 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ợ đổi tên các chức năng này thông qua bản đồ nguồn. Nếu một bản đồ nguồn có một mục nhập tên để bắt đầu phạm vi hàm (nghĩa là dấu ngoặc đơn bên trái của danh sách tham số), khung lệnh gọi phải hiển thị tên đó trong dấu vết ngăn xếp.

Khung hình cuộc gọi thân thiện ở dạng góc

Việc đổi tên khung cuộc gọi trong Angular là một nỗ lực không ngừng. Chúng tôi hy vọng những cải tiến này sẽ dần ra mắt 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 sẽ tạo mã TypeScript, mã này cuối cùng sẽ được chuyển đổi 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 tìm hiểu cách đưa tên hàm vào trường "name" của bản đồ nguồn và tham chiếu các tên đó trong mục ánh xạ 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 của hàm này không thân thiện hoặc bị xoá trong quá trình thu nhỏ, thì 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 "names" và mục ánh xạ ở đầu phạm vi hàm giờ đây có thể tham chiếu đến tên này (nghĩa 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 khung cuộc gọi trong dấu vết ngăn xếp.

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

Sử dụng Angular làm chương trình thí điểm thử nghiệm để xác minh công việc của chúng tôi là một trải nghiệm tuyệt vời. Chúng tôi rất 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ề những điểm mở rộng này.

Còn có nhiều lĩnh 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 phân tích tài nguyên trong Công cụ cho nhà phát triển.