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)