Phân phát mã hiện đại cho các trình duyệt hiện đại để tải trang nhanh hơn

Xây dựng các trang web hoạt động tốt trên tất cả các trình duyệt chính là một nguyên tắc cốt lõi của hệ sinh thái web mở. Tuy nhiên, điều này có nghĩa là bạn phải làm thêm việc đảm bảo rằng tất cả mã bạn viết đều được hỗ trợ trong từng trình duyệt mà bạn dự định nhắm đến. Nếu muốn sử dụng các tính năng mới của ngôn ngữ JavaScript, bạn cần chuyển đổi mã nguồn các tính năng này sang định dạng tương thích ngược cho những trình duyệt không hỗ trợ các tính năng đó.

Babel là công cụ được sử dụng rộng rãi nhất để biên dịch mã có cú pháp mới hơn thành mã mà các trình duyệt và môi trường khác nhau (chẳng hạn như Node) có thể hiểu được. Hướng dẫn này giả định rằng bạn đang sử dụng Babel, vì vậy, bạn cần làm theo hướng dẫn thiết lập để đưa Babel vào ứng dụng nếu chưa làm. Chọn webpack trong Build Systems nếu bạn đang dùng webpack làm trình kết hợp mô-đun trong ứng dụng.

Để sử dụng Babel chỉ để chuyển đổi mã nguồn những gì cần thiết cho người dùng, bạn cần:

  1. Xác định trình duyệt mà bạn muốn nhắm đến.
  2. Sử dụng @babel/preset-env với các mục tiêu trình duyệt phù hợp.
  3. Sử dụng <script type="module"> để ngừng gửi mã được chuyển đổi sang trình duyệt không cần mã đó.

Xác định trình duyệt mà bạn muốn nhắm đến

Trước khi bắt đầu sửa đổi cách mã trong ứng dụng của bạn được chuyển đổi, bạn cần xác định những trình duyệt nào truy cập vào ứng dụng của bạn. Phân tích những trình duyệt mà người dùng đang sử dụng và những trình duyệt mà bạn dự định nhắm đến để đưa ra quyết định sáng suốt.

Sử dụng @babel/preset-env

Việc chuyển đổi mã thường tạo ra một tệp có kích thước lớn hơn so với dạng ban đầu. Bằng cách giảm thiểu lượng quá trình biên dịch mà bạn thực hiện, bạn có thể giảm kích thước của các gói để cải thiện hiệu suất của một trang web.

Thay vì đưa các trình bổ trợ cụ thể vào để biên dịch có chọn lọc một số tính năng ngôn ngữ mà bạn đang sử dụng, Babel cung cấp một số chế độ cài đặt sẵn để kết hợp các trình bổ trợ với nhau. Sử dụng @babel/preset-env để chỉ bao gồm các biến đổi và polyfill cần thiết cho những trình duyệt mà bạn dự định nhắm đến.

Thêm @babel/preset-env vào mảng presets trong tệp cấu hình Babel, .babelrc:

{
 "presets": [
   [
     "@babel/preset-env",
     {
       "targets": ">0.25%"
     }
   ]
 ]
}

Sử dụng trường targets để chỉ định những phiên bản trình duyệt mà bạn muốn đưa vào bằng cách thêm một truy vấn thích hợp vào trường browsers. @babel/preset-env tích hợp với browserslist, một cấu hình nguồn mở được chia sẻ giữa nhiều công cụ để nhắm đến các trình duyệt. Danh sách đầy đủ các truy vấn tương thích có trong tài liệu về browserslist. Một lựa chọn khác là sử dụng tệp .browserslistrc để liệt kê các môi trường mà bạn muốn nhắm đến.

Giá trị ">0.25%" cho Babel biết rằng chỉ bao gồm những biến đổi cần thiết để hỗ trợ các trình duyệt chiếm hơn 0,25% mức sử dụng trên toàn cầu. Điều này đảm bảo gói của bạn không chứa mã được chuyển đổi không cần thiết cho những trình duyệt mà chỉ một tỷ lệ rất nhỏ người dùng sử dụng.

Trong hầu hết các trường hợp, đây là một phương pháp tốt hơn so với việc sử dụng cấu hình sau:

  "targets": "last 2 versions"

Giá trị "last 2 versions" sẽ chuyển đổi mã của bạn cho 2 phiên bản gần đây nhất của mọi trình duyệt, nghĩa là bạn sẽ được hỗ trợ cho các trình duyệt không còn được dùng nữa, chẳng hạn như Internet Explorer. Điều này có thể làm tăng kích thước gói một cách không cần thiết nếu bạn không muốn người dùng sử dụng các trình duyệt này để truy cập vào ứng dụng của bạn.

Cuối cùng, bạn nên chọn tổ hợp truy vấn phù hợp để chỉ nhắm đến những trình duyệt phù hợp với nhu cầu của mình.

Bật các bản sửa lỗi mới

@babel/preset-env nhóm nhiều tính năng cú pháp JavaScript thành các tập hợp, bật và tắt các tính năng đó dựa trên trình duyệt mục tiêu được chỉ định. Mặc dù cách này hoạt động hiệu quả, nhưng toàn bộ tập hợp các tính năng cú pháp sẽ được chuyển đổi khi một trình duyệt mục tiêu có lỗi chỉ với một tính năng duy nhất. Điều này thường dẫn đến việc có nhiều mã được chuyển đổi hơn mức cần thiết.

Ban đầu được phát triển dưới dạng một chế độ cài đặt sẵn riêng biệt, lựa chọn bugfixes trong @babel/preset-env giải quyết vấn đề này bằng cách chuyển đổi cú pháp hiện đại bị hỏng trong một số trình duyệt thành cú pháp tương đương gần nhất không bị hỏng trong các trình duyệt đó. Kết quả là mã hiện đại gần như giống hệt nhau với một vài tinh chỉnh nhỏ về cú pháp để đảm bảo khả năng tương thích trong tất cả các trình duyệt mục tiêu. Để sử dụng chế độ tối ưu hoá này, hãy đảm bảo bạn đã cài đặt @babel/preset-env 7.10 trở lên, sau đó đặt thuộc tính bugfixes thành true:

{
 "presets": [
   [
     "@babel/preset-env",
     {
       "bugfixes": true
     }
   ]
 ]
}

Trong Babel 8, lựa chọn bugfixes sẽ được bật theo mặc định.

Sử dụng <script type="module">

Các mô-đun JavaScript hoặc mô-đun ES là một tính năng tương đối mới được hỗ trợ trong tất cả các trình duyệt chính. Bạn có thể dùng các mô-đun để tạo tập lệnh có thể nhập và xuất từ các mô-đun khác, nhưng bạn cũng có thể dùng các mô-đun này với @babel/preset-env để chỉ nhắm đến những trình duyệt hỗ trợ các mô-đun này.

Thay vì truy vấn các phiên bản trình duyệt hoặc thị phần cụ thể, hãy cân nhắc việc chỉ định "esmodules" : true trong trường targets của tệp .babelrc.

{
   "presets":[
      [
         "@babel/preset-env",
         {
            "targets":{
               "esmodules": true
            }
         }
      ]
   ]
}

Nhiều tính năng ECMAScript mới hơn được biên dịch bằng Babel đã được hỗ trợ trong các môi trường hỗ trợ mô-đun JavaScript. Vì vậy, bằng cách này, bạn sẽ đơn giản hoá quy trình đảm bảo rằng chỉ mã được chuyển đổi mới được dùng cho những trình duyệt thực sự cần mã đó.

Trình duyệt hỗ trợ các mô-đun sẽ bỏ qua tập lệnh có thuộc tính nomodule. Ngược lại, những trình duyệt không hỗ trợ các mô-đun sẽ bỏ qua các phần tử tập lệnh có type="module". Điều này có nghĩa là bạn có thể thêm một mô-đun cũng như một bản dự phòng đã biên dịch.

Lý tưởng nhất là hai tập lệnh phiên bản của một ứng dụng được đưa vào như sau:

<script type="module" src="main.mjs"></script>
<script nomodule src="compiled.js" defer></script>

Các trình duyệt hỗ trợ mô-đun sẽ tìm nạp và thực thi main.mjs, đồng thời bỏ qua compiled.js. Các trình duyệt không hỗ trợ mô-đun sẽ làm ngược lại.

Nếu sử dụng webpack, bạn có thể đặt các mục tiêu khác nhau trong cấu hình cho 2 phiên bản riêng biệt của ứng dụng:

  • Một phiên bản chỉ dành cho những trình duyệt hỗ trợ các mô-đun.
  • Một phiên bản có chứa tập lệnh đã biên dịch hoạt động trong mọi trình duyệt cũ. Điều này có kích thước tệp lớn hơn, vì quá trình chuyển đổi cần hỗ trợ nhiều trình duyệt hơn.

Xin cảm ơn Connor Clark và Jason Miller vì đã đánh giá.