Web nâng cao (5) - JavaScript cho React (4)

Bài trước: Web nâng cao (4) - JavaScript cho React (3)

-----

1.1       JavaScript cho React (4)

1.1.1       Babel biên dịch JavaScript

Để máy tính có thể thực thi các chương trình, nó cần phải chuyển đổi ngôn ngữ lập trình sang dạng mã máy, khi đó CPU sẽ thực thi mã máy để thực hiện các công việc. Muốn chuyển từ ngôn ngữ lập trình cấp cao sang mã máy cần có quá trình dịch ngôn ngữ, gồm quá trình thông dịch hoặc quá trình biên dịch, hoặc kết hợp cả hai quá trình này.

Thông dịch (interpret) là quá trình dịch từ ngôn ngữ nguồn sang ngôn ngữ đích, quá trình dịch được thực hiện trực tiếp khi thực thi chương trình. Máy tính sẽ đọc từng lệnh của ngôn ngữ nguồn và dịch trực tiếp sang ngôn ngữ đích.

Biên dịch (compile) cũng là quá trình dịch từ ngôn ngữ nguồn sang ngôn ngữ đích, tuy nhiên quá trình dịch được thực hiện trước khi thực thi chương trình. Máy tính sẽ dịch một chuỗi các câu lệnh của ngôn ngữ nguồn thành một chương trình tương đương nhưng ở dạng ngôn ngữ đích.

Trong trường hợp dịch xuôi, ngôn ngữ nguồn thường là ngôn ngữ cấp cao (ví dụ C#, PHP, JavaScript); ngôn ngữ đích có thể là ngôn ngữ cấp thấp hơn (dạng mã đối tượng, mã máy), ngôn ngữ cấp cao khác hoặc ngôn ngữ trung gian.

Bạn có thể chia ngôn ngữ lập trình thành các nhóm, như ngôn ngữ lập trình kiểu thông dịch, hay ngôn ngữ lập trình kiểu biên dịch. Tuy nhiên, việc phân chia này không thực sự rõ ràng, vì thực tế nhiều ngôn ngữ lập trình được thiết kế để chạy theo kiểu vừa thông dịch vừa biên dịch, tùy thuộc vào giai đoạn khác nhau của quá trình chuyển đổi và thực thi mã nguồn. Các ngôn ngữ lập trình hiện đại cũng được triển khai trên các nền tảng cho phép tùy chọn cả hai hình thức thông dịch và biên dịch.

Như vậy, việc xác định một ngôn ngữ thuộc kiểu thông dịch hay biên dịch cũng không quá quan trọng. Điều quan trọng là bạn cần phải hiểu rõ các bước, các thành phần đã tham gia vào quá trình chuyển đổi từ ngôn ngữ lập trình sang dạng mã máy.

JavaScript vốn là ngôn ngữ kiểu thông dịch, vậy tại sao lại có chuyện biên dịch mã JavaScript? Lý do là cộng đồng lập trình JavaScript thường xuyên đưa ra các đặc tả, các kĩ thuật lập trình mới. Trước đây, để có thể sử dụng các đặc tả mới, lập trình viên phải chờ đợi một thời gian rất lâu (có thể tính bằng năm) để các trình duyệt bổ sung các đặc tả mới này.

Tuy nhiên, hiện nay các lập trình viên đã có thể nhanh chóng sử dụng các đặc tả mới của JavaScript nhờ có quá trình biên dịch mã nguồn bằng công cụ Babel.

Babel sẽ thực hiện chuyển đổi hay biên dịch mã JavaScript viết theo các đặc tả mới sang mã JavaScript chuẩn, đảm bảo tính tương thích cao, nghĩa là mọi trình duyệt đều có thể hiểu và thực thi được.

Babel không thực hiện biên dịch JavaScript sang dạng mã nhị phân để CPU có thể thực thi, mà nó chỉ chuyển đổi cú pháp của mã JavaScript.

Như vậy, với sự có mặt của Babel, trong các dự án viết bằng JavaScript sẽ cho phép có các tập tin hoặc đoạn mã nguồn mà trình duyệt không thể thực thi trực tiếp nếu nó chưa được biên dịch.

Xem hình minh họa về quá trình biên dịch của Babel,


Quá trình biên dịch của Babel gồm 3 bước:

– Babel nhận mã nguồn (source code), sau đó thực hiện phân tích mã nguồn thành cấu trúc dữ liệu dạng cây, gọi là cây cú pháp trừu tượng (AST – Abstract Syntax Tree)

– Babel tiếp tục chuyển đổi AST sang dạng tương thích với trình duyệt (modified AST)

– Cuối cùng, Babel sẽ chuyển đổi “AST tương thích với trình duyệt” sang dạng “mã nguồn chuẩn” (code generation)

Ví dụ, xem hàm cộng hai số, viết bằng arrow function,

const add = (x = 5, y = 10) => console.log(x + y);

Sau khi Babel biên dịch đoạn mã trên, nó sẽ sinh ra đoạn mã sau,

     "use strict";

 

     var add = function add() {

          var x = arguments.length <=0 || arguments[0=== undefined ? 5 : arguments[0];

          var y = arguments.lenght <= 0 || arguments[1=== undefined ? 10 : arguments[1];

          return console.log(x + y);

     }

Babel đã thêm từ khóa “use strict” vào đoạn mã, thông báo là đoạn mã được viết và thực thi ở chế độ “nghiêm ngặt”. Babel sẽ chuyển mã nguồn JavaScript sang cú pháp “chuẩn” để nhiều trình duyệt khác nhau có thể hiểu và thực thi được.

Các tên gọi khác của chương trình dịch trong JavaScript: source-to-source translator, source-to-source compiler (S2S compiler), transcompiler, or transpiler.

Quá trình biên dịch JavaScript thường được thực hiện tự động bằng các công cụ như Webpack hoặc Parcel.

1.1.2       Sử dụng Babel tại trình duyệt

Bạn có thể sử dụng Babel trên trình duyệt hoặc trong nền tảng Nodejs. Phần này sẽ hướng dẫn cách sử dụng Babel trên trình duyệt.

Ý tưởng:

– Nhúng thư viện Babel vào trang web

– Khi viết mã nguồn, thuộc tính type trong thẻ <script> được khai báo là text/babel hoặc text/jsx (thay vì text/javascript)

– Khi nhận thấy có đoạn mã nguồn viết theo ES6, Babel sẽ tự động dịch qua mã “JavaScript chuẩn”

Cách thực hiện:

– Sử dụng thẻ <script> của HTML để lấy thư viện Babel từ trên mạng (từ hệ thống CDN)

<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>

– Khi viết mã nguồn, thuộc tính type trong thẻ <script> được khai báo là text/babel hoặc text/jsx (thay vì text/javascript)

 <script type="text/babel">

      const test = (x) => x * x;

      console.log("Ket qua " + test(3));

    </script>

Xem một ví dụ hoàn chỉnh.

[test.html]

<!DOCTYPE html>

<html>

  <head>

    <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>

  </head>

  <body>

    <script type="text/babel">

      const test = (x) => x * x;

      console.log("Ket qua " + test(3));

    </script>

  </body>

</html>

Bạn hãy mở trang test.html bằng trình duyệt, mở cửa sổ Developer tools > tab Console để xem kết quả thực thi; mở tab Elements để xem mã ES6 đã được Babel dịch sang “JavaScript chuẩn”.

Sử dụng Babel trên trình duyệt là hình thức chạy Babel một cách độc lập (standalone). Có một số lý do bạn nên sử dụng ở chế độ này. Ví dụ:

– Muốn sử dụng Babel một cách đơn giản, chỉ cần khai báo trong thẻ script của tài liệu HTML

– Cần biên dịch mã JavaScript tại trình duyệt, ví dụ các website chạy trực tiếp JavaScript như JSFiddle, JS Bin, Jsitor, REPL trên website của Babel.

– Các ứng dụng có nhúng trực tiếp JavaScript engine như V8, và muốn sử dụng Babel để biên dịch mã nguồn

– Các ứng dụng muốn sử dùng JavaScript như là một ngôn ngữ kịch bản cho các chứng năng mở rộng

– Các môi trường phải triển không có Nodejs (ReactJS.NET, ruby-babel-transpiler, php-babel-transpiler)

1.1.3       NPM và Babel

Cách thứ 2 để sử dụng Babel là dùng NPM. Trước khi có thể thực hành cài đặt và sử dụng Babel với NPM, bạn cần tìm hiểu một chút về NPM.

NPM (viết tắt của Node Package Manager) là chương trình quản lý thư viện (package manager) ngầm định trong môi trường Nodejs. NPM được tích hợp sẵn trong gói cài đặt Nodejs, vì vậy khi cài đặt Nodejs là có luôn NPM.

NPM do Issac Z. Schlueter tạo ra năm 2010, viết bằng ngôn ngữ JavaScript. Bên cạnh NPM, cũng có rất nhiều các phần mềm quản lý thư viện khác như Yarn của Facebook, Composer của PHP, Maven của Java.

Để dễ dàng tìm hiểu về NPM và Babel, chúng ta sẽ vừa thực hành vừa tìm hiểu về các kiến thức liên quan.

– Sau khi cài đặt Nodejs, hoặc trong máy đã có sẵn Nodejs, bạn mở cửa sổ dòng lệnh, gõ lệnh npm –v để xem phiên bản, nếu có thông tin về phiên bản là máy bạn đã được cài đặt NPM.

C:\Users\Maxsys>npm -v

6.14.15

NPM gồm 3 thành phần:

– Một là kho chứa các dự án, hay các gói (module, thư viện, framework) mã nguồn mở cho nền tảng Nodejs. Kho chứa được để trên Internet tại địa chỉ https://www.npmjs.com/, lập trình viên có thể tải về, sử dụng để phát triển các dự án.

– Hai là tập lệnh (command line - npm) để tương tác với kho chứa (https://www.npmjs.com/); quản lý các gói, thư viện và các phụ thuộc (dependency) .

– Ba là hệ thống danh bạ (registry), giúp tìm kiếm các gói dựa vào tên và phiên bản

Bảng sau liệt kê một số lệnh của NPM:

Tên lệnh

Chức năng

npm –v

Xem phiên bản của NPM đang được cài đặt trên máy tính của bạn

npm update npm –g

npm install –g npm@latest

Cập nhật phiên bản mới nhất cho NPM trên máy tính của bạn

npm init

Khởi tạo một dự án Nodejs

npm install <tên-gói><các-tham-số>

Cài đặt một package

npm ls --depth=0

Liệt kê các thành phần phụ thuộc đã được cài đặt cục bộ, trong một dự án.

Ví dụ :

E:\testBabel>npm ls --depth=0

Sử dụng Babel với NPM

Sử dụng công cụ dòng lệnh bất kỳ (ví dụ CMD, PowerShell, Git Bash) để thực hiện:

– Mở cửa sổ dòng lệnh, dùng lệnh mkdir (make directory) để tạo thư mục có tên bất kỳ (ví dụ testBabel)

E:\>mkdir testBabel

– Dùng lệnh cd (change directory) để di chuyển vào thư mục testBabel

E:\>cd testBabel

– Sử dụng lệnh npm –init để chuyển thư mục testBabel từ một thư mục bình thường trở thành một package, giúp NPM có thể hiểu và làm việc được với testBabel. Quá trình này thực tế sẽ tạo ra tập tin package.json để NPM ghi lại thông tin, tham chiếu và thực hiện các thao tác về sau. Có thể thêm tham số “y” (yes) cho lệnh npm –init để trả lời tự động cho các câu hỏi xác nhận trong quá trình tạo tập tin package.json.

E:\testBabel>npm init -y

Wrote to E:\testBabel\package.json:

{

  "name": "testbabel",

  "version": "1.0.0",

  "description": "",

  "main": "index.js",

  "scripts": {

    "test": "echo \"Error: no test specified\" && exit 1"

  },

  "keywords": [],

  "author": "",

  "license": "ISC"

}

Bạn nên mở tập tin package.json vừa được NPM tạo trong thư mục testBabel để xem qua một số khai báo bên trong.

– Cài đặt công cụ Babel CLI để có thể sử dụng Babel ở chế độ dòng lệnh, thiết lập Babel CLI như là một thành phần phụ thuộc của ứng dụng (dependency). Dependency được hiểu là một mô-đun, thư viện hay một thành phần sẽ được sử dụng trong ứng dụng. Vậy có thể hiểu Babel CLI là thành phần mà ứng dụng testBabel cần sử dụng, và NPM là công cụ để quản lý các thành phần phụ thuộc này. Dùng lệnh npm install <tên gói> <tham số> để tải và cài đặt Babel CLI.

E:\testBabel>npm install babel-cli --save-dev

Trong Nodejs, các thành phần phụ thuộc được chia thành 2 loại: loại được sử dụng trong quá trình phát triển ứng dụng được gọi là devDependencies, và loại được sử dụng trong quá trình chạy ứng dụng được gọi là dependencies.

Tham số --save-dev để đánh dấu Babel-CLI là thành phần phụ thuộc, chỉ được sử dụng trong quá trình phát triển ứng dụng testBabel.

Nếu thực thi thành công, lệnh trên sẽ tạo ra thư mục node_modules để chứa các thành phần phụ thuộc, tạo thêm tập tin package-lock.json, cập nhật dòng tin sau vào tập tin package.json,

"devDependencies": {

    "babel-cli": "^6.26.0"

  }

– Để kiểm tra việc cài đặt Babel-CLI được hay chưa? sử dụng lệnh npm ls –depth=0:

E:\testBabel>npm ls --depth=0

testbabel@1.0.0 E:\testBabel

`-- babel-cli@6.26.0

– Chạy thử lệnh babel --version

E:\testBabel>node_modules\.bin\babel --version

6.26.0 (babel-core 6.26.3)

– Thêm lệnh build vào tập tin package.json

"scripts": {

    "test": "echo \"Error: no test specified\" && exit 1",

    "build": "babel src -d dist"

  },

Lệnh build ở trên sẽ thực thi babel, lấy tập tin nguồn tại thư mục src, biên dịch và lưu tập tin kết quả vào thư mục dist.

– Trước khi sử dụng được Babel để biên dịch mã JavaScript, cần phải cài đặt thêm rất nhiều các plugin khác, nếu làm thủ công thì khá mất thời gian và phức tạp. Vì vậy người ta thực hiện gom sẵn các plugin cần thiết vào một bộ, được gọi là các preset. Với Babel, preset này có tên là babel-preset-env. Bạn sẽ cài đặt babel-preset-env bằng lệnh sau:

E:\testBabel>npm install babel-preset-env --save-dev

– Trong thư mục gốc của dự án, tạo tập tin .babelrc để chứa các thông tin thiết lập cho Babel, preset và plugin. Thêm nội dung sau cho tập tin .babelrc

[E:\testBabel\.babelrc]

{

    "presets" : ["env"]

}

– Trong thư mục gốc của dự án, tạo thư mục chứa tập tin nguồn (src) và thư mục chứa tập tin kết quả (dist)

E:\testBabel>mkdir src dist

– Trong thư mục chứa tập tin nguồn, tạo tập tin mã nguồn viết bằng ES6, ví dụ:

[E:\testBabel\src\testBabel.js]

const test = (x) => x * x;

 

console.log("Ket qua: " + test(4));

– Chạy lệnh build để thực hiện quá trình biên dịch

E:\testBabel>npm run build

 

> testbabel@1.0.0 build

> babel src -d dist

 

src\testBabel.js -> dist\testBabel.js

– Mở tập tin kết quả

[E:\testBabel\dist\testBabel.js]

"use strict";

 

var test = function test(x) {

  return x * x;

};

 

console.log("Ket qua: " + test(4));

1.1.4       Xem và đọc thêm

– Dùng các từ khóa sau tìm kiếm trên mạng để đọc thêm: babel trong javascript, babel-standalone, NPM

– Run Babel on browser: https://babeljs.io/docs/en/babel-standalone

– NPM: https://docs.npmjs.com/about-npm

 – [1] Alex Banks, Eve Porcello, Learning React – Mordern Patterns for Developing React Apps, O’Reilly Media, 2020, p17 – p18

1.1.5       Bài tập và thực hành

Bài tập 1. Viết lại các đoạn mã trong phần lý thuyết để chạy và kiểm tra lại kết quả.

Bài tập 2. Cài đặt và sử dụng Babel trên trình duyệt

Bài tập 3. Cài đặt và sử dụng Babel trong Nodejs

1.1.6       Câu hỏi ôn tập

Câu 1. Trong quá trình biên dịch của Babel, AST là viết tắt của cụm từ nào?

A. Abstract Semantic Tree

B. Abstract Syntax Tree

C. Absolute Syntax Tree

D. Abstract System Tree

Câu 2. Trong môi trường làm việc với Nodejs, NPM là viết tắt của các từ nào?

A. Node Package Manager

B. Node Package Management

C. Node Program Manager

D. Node Process Management

Câu 3. Trong môi trường làm việc của NPM, nội dung bên trong tập tin package.json được viết theo định dạng nào?

A. Bất kỳ định dạng nào cũng được

B. Text

C. JSON

D. CSV

Câu 4. Trong môi trường làm việc của NPM, dependency được hiểu là?

A. Thành phần phụ thuộc vào ứng dụng

B. Thành phần ứng dụng phụ thuộc vào

C. Công cụ dùng để biên dịch mã JavaScript

D. Công cụ dùng để thông dịch mã JavaScript

Câu 5. Trong lệnh npm install <tên gói> <tham số>, tham số --save-dev được sử dụng để làm gì?

A. Để đánh dấu thành phần phụ thuộc cần được bảo vệ an toàn

B. Để lưu phiên bản của ứng dụng

C. Để tạo bản sao cho ứng dụng

D. Để đánh dấu thành phần phụ thuộc chỉ được sử dụng trong quá trình phát triển ứng dụng

Đáp án: 1 (B), 2 (A), 3 (C), 4 (B), 5 (D)

-----

Cập nhật: 22/3/2022

-----

Bài tiếp: Web nâng cao (6) - JavaScript cho React (5)