Giải thích về Javascript thời hiện đại cho khủng long
Bài đăng này đã không được cập nhật trong 6 năm
Đây là bài dịch, bài gốc mời các bạn xem ở đây: https://medium.com/the-node-js-collection/modern-javascript-explained-for-dinosaurs-f695e9747b70
Thời nay, việc học Javascript sẽ rất là khoai nếu như bạn không theo dõi từ đầu sự bùng nổ và phát triển của JS trong những năm gần đây. Hệ sinh thái của JS hiện vẫn đang tiếp tục phát triển và thay đổi một cách chóng mặt, khiến cho việc hiểu và và chọn đúng công cụ cho vấn đề cần giải quyết trở nên thực sự khó khăn. Tôi đã bắt đầu lập trình từ năm 1998 nhưng chỉ mới học Javascript một cách nghiêm túc kể từ năm 2014. Vào thời điểm đó tôi nhớ mình đã tiếp cận Browserify và nhìn chằm chằm vào định nghĩa của nó như sau:
Browserify giúp cho bạn `require('modules')` trong trình duyệt bằng cách đóng gói toàn bộ dependencies của bạn.
Thú thực là tôi không hiểu bất cứ từ nào trong câu văn trên, và cũng hoàn toàn không hiểu được công dụng của Browserify sẽ giúp tôi thế nào trong việc lập trình JS.
Do đó, bài viết này ra đời với mục tiêu là cung cấp cho người đọc một bối cảnh lịch sử về các công cụ JS đã tiến hoá như thế nào đến thời điểm năm 2017. Chúng ta sẽ bắt đầu bằng việc xây dựng một website ví dụ giống như những con khủng long - ko có tool gì cả, chỉ dùng HTML thuần và Javascript. Sau đó chúng ta sẽ lần lượt điểm qua và áp dụng dần các công cụ để biết được vấn đề mà chúng sẽ giải quyết được là gì. Với bối cảnh lịch sử này, bạn sẽ có khả năng học tập và đáp ứng tốt hơn với sự thay đổi của Javascript ở thời điểm hiện tại và trong cả tương lai nữa. Hãy cùng bắt đầu nào!
Sử dụng Javascript theo cách "cổ điển"
Hãy bắt đầu với một website theo phong cách "cổ điển" chỉ với HTML và Javascript, bao gồm cả việc download và link các file một cách thủ công. Đây là một file index.html đơn giản sử dụng một file Javascript:
<!-- index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>JavaScript Example</title>
<script src="index.js"></script>
</head>
<body>
<h1>Hello from HTML!</h1>
</body>
</html>
Đoạn <script src="index.js"></script>
sẽ trỏ đến một file JS riêng biệt nằm trong cùng 1 thư mục có tên là index.js.
// index.js
console.log("Hello from JavaScript!");
Và đây là tất cả những gì bạn cần để làm ra một trang web! Giờ hãy xem nếu bạn muốn thêm một thư viện được viết bởi người khác ví dụ như là moment.js (một thư viện có thể giúp bạn format giá trị ngày tháng theo cách con người thường đọc). Lấy ví dụ, bạn có thể sử dụng hàm moment
như sau:
moment().startOf('day').fromNow(); // 20 hours ago
Nhưng việc này chỉ có thể thực hiện được nếu bạn đã thêm file moment.js
vào trong website của mình! Trong trang chủ của moment.js bạn sẽ thấy hướng dẫn như sau:
Hmm, có vẻ có hơi nhiều thứ trong phần Install ở bên tay phải. Nhưng tạm thời chúng ta cứ bỏ qua nó đã - chúng ta có thể thêm moment.js
vào website của chúng ta bằng cách download file moment.min.j
vào cùng một thư mục với file index.html
và chỉnh sửa như sau:
<!-- index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Example</title>
<link rel="stylesheet" href="index.css">
<script src="moment.min.js"></script>
<script src="index.js"></script>
</head>
<body>
<h1>Hello from HTML!</h1>
</body>
</html>
Để ý rằng file moment.min.js
được load trước file index.js
, có nghĩa là chúng ta có thể sử dụng hàm moment
ở trong file index.js
như thế này:
// index.js
console.log("Hello from JavaScript!");
console.log(moment().startOf('day').fromNow());
Và đso là cách chúng ta đã sử dụng để làm trang web với các thư viện Javascript! Phần tốt ở đây là nó rất đủ dễ để có thể hiểu. Phần không tốt là nó sẽ trở lên rất phiền phức để tìm và download các phiên bản mới của thư viện JS mỗi khi chúng được update.
Sử dụng một bộ quản lý package Javascript (npm)
Bắt đầu vào khoảng năm 2010, một vài bộ quản lý package JS khá cạnh tranh đã được nhiều người biết đến, với mục đích giúp lập trình viên thuận tiện hơn trong việc tải và nâng cấp các thư viện từ một repository tập trung. Bower được cho rằng là công cụ phổ biến nhất vào năm 2013, nhưng sau đó đã bị npm soán ngôi vào năm 2015. (Một công cụ khác cũng đáng được nhắc tới, được ra đời vào năm 2016, đó là yarn, đã thu hút rất nhiều sự chú ý dưới danh nghĩa là ứng viên thay thế cho interface của npm, nhưng vẫn dùng các package npm ở bên trong).
Lưu ý rằng npm ban đầu là một chương trình quản lý các package được tạo ra chuyên cho node.js, một bộ biên dịch và chạy JavaScript dùng cho phía server, chứ không phải là bên phía frontend. Vì thế việc sử dụng một thư viện như npm cho việc quản lý các Javascript libraries ở phía frontend nghe có vẻ hơi kì cục.
Lưu ý: Sử dụng các chương trình quản lý package sẽ bao gồm cả việc sử dụng dòng lệnh, là thứ mà trong quá khứ chưa từng là kĩ năng cần thiết đối với một frontend developer. Nếu chưa quen với việc sử dụng dòng lệnh, bạn có thể đọc [tutorial này](https://www.learnenough.com/command-line-tutorial) để có một cái nhìn tổng quan trước khi bắt đầu. Bất kể việc bạn cảm thấy tốt hơn hay tệ hơn, thì việc biết cách sử dụng command line là một thành phần quan trọng của Javascript thời nay (đồng thời cũng mở rộng cánh cửa sang các mảng khác của việc phát triển phần mềm)
Hãy cùng xem cách sử dụng npm để cài đặt thư viện moment.js
một cách tự động thay vì download thủ công. Nếu như bạn đã cài đặt node.js
, thì bạn cũng đã cài đặt đồng thời npm
, và vì thế bạn có thể di chuyển đến thư mục có chứa file index.html
và nhập dòng sau:
$ npm init
Sau khi trả lời vài câu hỏi (các option mặc định khá ổn, bạn có thể ấn Enter để chọn giá trị mặc định), câu lệnh trên sẽ tạo ra một file có tên là package.json
. Đây là một file cấu hình được npm sử dụng để lưu tất cả thông tin dự án. Với các giá trị mặc đinh, file package.json
sẽ trông như thế này:
{
"name": "your-project-name",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC"
}
Để cài đặt moment.js
, chúng ta có thể sử dụng hướng dẫn cài đặt từ trang chủ bằng cách nhập dòng lệnh sau:
$ npm install moment --save
Câu lệnh này sẽ làm 2 việc - đầu tiên, nó download tất cả code từ package của moment.js vào một thư mục có tên là node_modules
. Tiếp theo, nó sẽ cập nhật file package.json
để thêm thư viện moment.js
và theo dõi sự cập nhật của thư viện đó dưới vai trò một dependency của dự án hiện tại.
{
"name": "modern-javascript-example",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"moment": "^2.19.1"
}
}
Việc này sẽ giúp ích khi chia sẻ dự án với người khác - thay vì chia sẻ thư mục node_modules
(có thể trở nên rất nặng), bạn chỉ cần chia sẻ file package.json
và những lập trình viên khác có thể cài đặt các packages này một cách tự động thông qua câu lệnh npm install
.
Và giờ chúng ta không cần phải download file moment.js
thủ công nữa, mà có thể tự động download và cập nhật chúng thông qua npm. Nhìn vào bên trong thư mục node_modules
, chúng ta có thể thấy file moment.min.js
nằm trong thư mục node_modules/moment/min
. Điều này có nghĩa là chúng ta có thể link đến file moment.min.js
đã được download trong file index.html
như sau:
<!-- index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>JavaScript Example</title>
<script src="node_modules/moment/min/moment.min.js"></script>
<script src="index.js"></script>
</head>
<body>
<h1>Hello from HTML!</h1>
</body>
</html>
Điều tốt ở đây là chúng ta có thể sử dụng npm để download và update các packages cần thiết thông qua dòng lệnh. Điều không ổn ở đây là chúng ta phải đào sâu vào thư mục node_modules
để tìm kiếm vị trí của từng package và thêm chúng một cách thủ công vào file HTML. Việc này khá là bất tiện, và vì thế tiếp theo chúng ta sẽ tìm cách để tự động hoá quá trình đó luôn.
Sử dụng công cụ đóng gói (bundle) các module Javascript (webpack)
Rất nhiều ngôn ngữ lập trình cung cấp một cách để import code từ một file này sang file khác. Javascript ban đầu không được design để có tính năng năng này, vì JS được tạo ra với mục đích chỉ chạy trên trình duyệt, mà không có quyền truy cập đến các file hệ thống nằm trên máy tính của người sử dụng (vì lý do bảo mật). Vì thế trong một thời gian dài, tổ chức code Javascript đã từng được thực hiện bằng cách load từng file một vào các biến chia sẻ toàn cục (globally).
Và các ở trên thực ra cũng là cách mà chúng ta đang sử dụng với ví dụ về moment.js - toàn bộ file moment.min.js
được load vào trong file HTML, được định nghĩa bởi một biến global có tên là moment
, và có thể dùng được ở bất cứ file nào được load sau khi file moment.min.js
được load (kể cả có hay không cần truy cập đến).
Vào năm 2009, một dự án có tên là CommonJS đã được bắt đầu với mục đích là định nghĩa ra một hệ sinh thái cho Javascript mà không phụ thuộc vào trình duyệt web. Một kết quả khá to lớn của dự án là đã đưa ra được định nghĩa đặc tả về modules, cho phép Javascript được import và export code giữa các file giống như các ngôn ngữ lập trình khác, mà không cần thiết phải sử dụng biến toàn cục. Và node.js là implementation phần modules của CommonJS nổi tiếng nhất.
Như đã mô tả ở trên, node.js là một trình biên dịch và thực thi Javascript được thiết kế để có thể chạy ở trên server. Thay vì phải load toàn bộ file moment.min.js
với thẻ script, chúng ta có thể load nó trực tiếp trong code JS giống như dưới đây:
// index.js
var moment = require('moment');
console.log("Hello from JavaScript!");
console.log(moment().startOf('day').fromNow());
Một lần nữa, đây là cách mà module được load ở trong node.js, và nó đã hoạt động khá tốt kể từ khi node.js được sử dụng dưới dạng ngôn ngữ phía server với khả năng truy cập đến các file hệ thống trên máy tính. Node.js cũng biết vị trí đường dẫn của từng module npm, vì thế thay vì phải viết require('./node_modules/moment/min/moment.min.js)
, bạn chỉ cần viết đơn giản là require('moment')
- khá ngọt.
Điều này rất tuyệt với node.js, nhưng nếu bạn thử đoạn code ở trên trong trình duyệt, bạn sẽ bắt gặp một lỗi với mô tả require
chưa được định nghĩa. Trình duyệt không được truy cập đến file hệ thống, nên việc load module theo cách này sẽ rất là rắc rối - các file phải được load động, bằng cách đồng bộ (sẽ làm chậm quá trình thực thi) hoặc bất đồng bộ (có thể có vấn đề về thời điểm load).
Và đây là lúc mà module bundler (bộ đóng gói module) phát huy tác dụng. Javascript module bundler là một công cụ giúp bạn thoát khỏi vấn đề ở trên với một bước build (có quyền truy cập đến file hệ thống) và tạo ra kết quả cuối cùng tương thích với browser (không cần truy cập đến file hệ thống). Trong trường hợp này, công cụ chúng ta sẽ sử dụng sẽ phải tìm tất cả các dòng lệnh require
(là syntax ko khả thi trong Javascript) và thay thế chúng bởi nội dung của từng file được require. Kết quả cuối cùng là một file Javascript được đóng gói (mà ko có dòng lệnh require
nào).
Công cụ module bundler phổ biến nhất đã từng là Browserify, được ra mắt vào năm 2011 và là tiên phong trong việc sử dụng câu lệnh require
của node.js ở phía frontend(mà về bản chất là thứ khiến việc sử dụng npm khả thi và trở thành lựa chọn cho việc quản lý các package phía frontend). Tuy nhiên đến khoảng năm 2015, webpack đã vươn lên và cuối cùng trở thành công cụ module bundler phổ biến nhất (trong đó ảnh hưởng phần lớn đến từ sự phổ biến của framework frontend có tên là React, mà đã khai thác được rất nhiều tính năng và lợi thế của webpack).
Hãy cùng xem cách cách webpack được sử dụng để làm cho dòng lệnh require('moment')
ở phía trên hoạt động được ở trong trình duyệt. Đầu tiên chúng ta cần cài đặt webpack vào trong dự án. Webpack bản thân nó là một package npm, vì thế chúng ta có thể cài đặt từ dòng lệnh như sau:
$ npm install webpack --save-dev
Lưu ý tham số --save-dev
- khi thêm tham số này sẽ lưu webpack dưới dạng một dependency cho việc phát triển, có nghĩa là chúng ta chỉ cần nó cho môi trường phát triển chứ không cần trong môi trường sản phẩm. Bạn có thể thấy câu lệnh được chạy sẽ được phản ánh vào file package.json
như sau:
{
"name": "modern-javascript-example",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"moment": "^2.19.1"
},
"devDependencies": {
"webpack": "^3.7.1"
}
}
Giờ chúng ta đã có webpack dưới dạng một package trong thư mục node_modules
. Chúng ta có thể sử dụng webpack từ dòng lệnh như sau:
$ ./node_modules/.bin/webpack index.js bundle.js
Câu lệnh này sẽ chạy công cụ webpack đã được cài đặt trong thư mục node_modules
, bắt đầu với file index.js
, tìm bất cứ dòng lệnh require
nào và thay thế chúng với các đoạn code tương ứng và tạo ra một file output có tên là bundle.js
. Điều này có nghĩa là chúng ta sẽ không còn sử dụng file index.js
trong trình duyệt nữa, vì nó chứa các câu lệnh require
không thực thi được. Thay vào đó chúng ta sẽ sử dụng file bundle.js
trong file index.html
như dưới đây:
<!-- index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>JavaScript Example</title>
<script src="bundle.js"></script>
</head>
<body>
<h1>Hello from HTML!</h1>
</body>
</html>
Nếu bạn mở trình duyệt, bạn sẽ thấy mọi thứ hoạt động như lúc trước!
Lưu ý rằng chúng ta sẽ cần phải chạy dòng lệnh webpack mỗi khi chúng ta thay đổi file index.js
. Việc này khá là phiền phức, và sẽ trở nên phiền hơn nữa khi chúng ta sử dụng các chức năng nâng cao của webpack (như là [tạo ra file source map] để giúp debug các đoạn code nguyên bản từ các đoạn code đã được biến đổi). Webpack có thể đọc các tuỳ chọn từ file config nằm trong thư mục gốc của dự án với tên là webpack.config.js
, trong TH của chúng ta sẽ có nội dung như sau:
// webpack.config.js
module.exports = {
entry: './index.js',
output: {
filename: 'bundle.js'
}
};
Giờ mỗi khi thay đổi file index.js
, chúng ta có thể chạy câu lệnh sau:
$ ./node_modules/.bin/webpack
Chúng ta không cần thiết phải chỉ rõ các file index.js
hay bundle.js
nữa, vì webpack đã load các giá trị đó trong file webpack.config.js
. Việc chạy lệnh đã trở nên đơn giản hơn, nhưng vẫn khá là mệt mỏi khi chúng ta phải tự chạy câu lệnh này mỗi khi có code thay đổi - chúng ta sẽ làm quá trình này mượt hơn một chút.
Nói một cách tổng thể, mặc dù có thể không tác động nhiều, nhưng sẽ có một vài lợi ích đáng kể khi tuân theo workflow này. Chúng ta sẽ không cần phải load các đoạn script bên ngoài thông qua biến toàn cục. Bất kì thư viện Javascript nào sẽ được thêm vào thông qua câu lệnh require
trong JS, thay vì sử dụng tag <script>
trong thẻ HTML. Chỉ có một file Javascript bundle cũng thường khiến cho performance trở nên tốt hơn. Và giờ chúng ta đã thêm một bước build, chúng ta có thể sử dụng thêm một vài tính năng mạnh mẽ trong quá trình phát triển.
Các chức năng biến đổi code sang ngôn ngữ mới (babel)
Biển đổi (transpiling) code có nghĩa là thay đổi code từ một ngôn ngữ sang một ngôn ngữ khác tương tự.. Đây là một thành phần quan trọng trong việc phát triển phía frontend - từ khi trình duyệt thường chậm chạp trong việc thêm mới các tính năng, và các ngôn ngữ mới được tạo ra với các chức năng thử nghiệm mà có thể biến đổi về các ngôn ngữ tương thích với trình duyệt.
Với CSS, chúng ta có vài cái tên tiêu biểu như là Sass, Less, và Stylus. Với Javascript, trình biến đổi code đã từng phổ biến nhất trong một khoảng thời gian đã từng là CoffeeScript (được phát hành vào khoảng năm 2010), trong khi babel và TypeScript là những ngôn ngữ được dùng thường xuyên trong thời gian gần đây. CoffeeScript là một ngôn ngữ tập trung vào việc cải thiện Javascript bằng cách thay đổi ngôn ngữ một cách đáng kể - các dấu ngoặc trở thành ko bắt buộc, các khoảng trắng có ý nghĩa,... Babel không phải là một ngôn ngữ mới nhưng là một trình biến đổi có tác dụng biến đổi các đoạn code Javascript ở thế hệ mới nhất với các chức năng chưa khả thi ở tất cả các trình duyệt (ES2015 và các phiên bản mới hơn) thành các đoạn code Javascript cũ hơn và tương thích với trình duyệt (ES5). Typescript là một ngôn ngữ khá độc lập và khác so với thế hệ Javascript kế tiếp, nhưng cũng có thêm phần tuỳ chọn kiểu dữ liệu tĩnh. Rất nhiều người chọn babel vì nó gần nhất với ngôn ngữ Javascript thuần tuý.
Dưới đây là một ví dụ sử dụng babel với bước build thông qua webpack. Đầu tiên chúng ta cài đặt babel (là một package npm) thông qua câu lệnh:
$ npm install babel-core babel-preset-env babel-loader --save-dev
Ở đây chúng ta đang cài 3 package riêng biệt cho development dependency - babel-core
là thành phần chính của babel, babel-preset-env
là các preset dùng để định nghĩa chức năng mới nào của Javascript được biến đổi, và babel-loader
là package được dùng để cho phép babel hoạt động với webpack. Chúng ta có thể cấu hình webpack để sử dụng babel-loader
bằng cách edit file webpack.config.js
như sau:
// webpack.config.js
module.exports = {
entry: './index.js',
output: {
filename: 'bundle.js'
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['env']
}
}
}
]
}
};
Cú pháp trong file này có thể khiến chúng ta bối rối (rất may là chúng ta sẽ không phải chỉnh sửa những thứ này thường xuyên). Về cơ bản là chúng ta đang nói với webpack để tìm kiếm bất kì file nào có đuôi là .js (ngoại trừ các file nằm trong thư mực node_modules
) và sử dụng babel để biến đổi code thông qua babel-loader
với bộ preset trong babel-preset-env
. Bạn có thể đọc thêm về các cú pháp cấu hình webpack ở đây.
Giờ sau khi mọi thứ đã được cài đặt, chúng ta có thể bắt đầu viết các code theo style ES2015 trong Javascript code! Đây là một ví dụ áp dụng ES2015 template string trong file index.js
:
// index.js
var moment = require('moment');
console.log("Hello from JavaScript!");
console.log(moment().startOf('day').fromNow());
var name = "Bob", time = "today";
console.log(`Hello ${name}, how are you ${time}?`);
Chúng ta cũng có thể sử dụng câu lệnh import của ES2015 thay câu lệnh require
để load các modules, và câu lệnh này rất hay được sử dụng trong code của các package npm hiện nay:
// index.js
import moment from 'moment';
console.log("Hello from JavaScript!");
console.log(moment().startOf('day').fromNow());
var name = "Bob", time = "today";
console.log(`Hello ${name}, how are you ${time}?`);
Trong ví dụ này, câu lệnh import
không khác gì nhiều so với câu lệnh require
, nhưng import
có sự linh hoạt cao hơn trong rất nhiều trường hợp nâng cao. Bởi vì chúng ta đã thay đổi file index.js
, chúng ta cần phải chạy câu lệnh webpack một lần nữa:
$ ./node_modules/.bin/webpack
Giờ bạn có thể tải lại trang index.html
trong trình duyệt. Vào thời điểm bài viết này ra đời, hầu hết các trình duyệt hiện đều đã hỗ trợ toàn bộ chức năng của ES2015, vì thế khó có thể thấy tác dụng thực sự của babel. Nếu muốn, chúng ta có thể test ở một số trình duyệt cũ hơn như là IE9, hoặc có thể tìm kiếm trong file bundle.js
để xem đoạn code đã được biến đổi:
// bundle.js
// ...
console.log('Hello ' + name + ', how are you ' + time + '?');
// ...
Ở đây bạn có thể thấy babel đã biến đổi các đoạn code của phần template string trong ES2015 sang các đoạn code Javascript thông thường với các cú pháp nối string bằng dấu + để đảm bảo tính tương thích với trình duyệt. Mặc dù ví dụ cụ thể này có vẻ không thú vị lắm, nhưng khả năng biến đổi code là một tính năng thực sự mạnh mẽ. Có một vài tính năng thú vị đã được đưa vào JavaScript như là async/await, mà bạn có thể lập tức sử dụng để viết code một cách tốt hơn. Và trong khi việc biến đổi code trông có vẻ phiền phức và mệt mỏi, nhưng nó đã tạo ra sự thay đổi rất đáng để đến JS trong một vài năm gần đây, vì mọi người đã có thể test được những chức năng của ngày may ngay từ hôm nay.
Chúng ta gần như đã điểm qua mọi tính nhưng, nhưng vẫn có một vài điểm chưa được trau chuốt lắm trong workflow của chúng ta. Nói về vấn đề performance, chúng ta có thể làm nhẹ/nén file bundle, mà có thể dễ dàng thực hiện thông qua bước build. Chúng ta cũng cần phải chạy lại lệnh webpack mỗi khi chúng ta thay đổi file JavaScript. Và tiếp theo đây sẽ là một số tool hỗ trợ giải quyết những công việc trên một cách tự động.
Sử dụng một bộ chạy task - task runner (dùng npm scripts)
Giờ sau khi đã sáng tạo ra một bước build để làm việc với Javascript module, thì việc sử dụng một bộ chạy task, với mục đích tự động hoá các thành phần trong quá trình build. Đối với việc phát triển frontend, các tasks sẽ bao gồm các việc làm gọn code, tối ưu hình ảnh, chạy test, ...
Vào năm 2013, Grunt đã từng là một công cụ phổ biến nhất cho việc chạy task, theo sau ngay đó là Gulp. Cả hai đều phụ thuộc vào các plugins bao ngoài các công cụ command line. Ngày nay sự lựa chọn phổ biến nhất có vẻ là sử dụng khả năng tương thích với script được xây dựng trong chính npm, không sử dụng plugins nhưng thay vào đó hoạt động với các công cụ command line khác một cách trực tiếp.
Hãy cùng viết một vài script npm để giúp cho việc sử dụng webpack dễ hơn. Việc này bao gồm vài thay đổi đơn giản trong file package.json
giống như dưới đây:
{
"name": "modern-javascript-example",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack --progress -p",
"watch": "webpack --progress --watch"
},
"author": "",
"license": "ISC",
"dependencies": {
"moment": "^2.19.1"
},
"devDependencies": {
"babel-core": "^6.26.0",
"babel-loader": "^7.1.2",
"babel-preset-env": "^1.6.1",
"webpack": "^3.7.1"
}
}
Ở đây chúng ta có 2 đoạn script mới tên là build
và watch
. Để chạy đoạn script buid, bạn có thể nhập dòng lệnh sau:
$ npm run build
Việc này sẽ chạy webpack (sử dụng cấu hình từ file webpack.config.js
chúng ta đã tạo ra trước đó) với tuỳ chọn --progress
để hiển thị phần trăm quá trình và option -p
để tối thiểu hoá code cho môi trường sản phẩm. Để chạy câu lệnh watch
:
$ npm run watch
Câu lệnh này sử dụng tuỳ chọn --watch
để tự động chạy lại webpack mỗi khi có bất kì thay đổi nào ở file Javascript, là một chức năng rất tuyệt cho development.
Lưu ý rằng các scripts trong file package.json
có thể chạy webpack mà không cần phải chỉ định rõ đường dẫn ./node_modules/.bin/webpack
, vì node.js có thể nhận biết được ví trí của từng npm module. Việc này khá là ngon! Chúng ta có thể khiến nó ngon hơn nữa bằng cách cài đặt một tool có tên là webpack-dev-server
, sẽ cung cấp một web server đơn giản hỗ trợ live-reloading. Để cài đặt tool đó như là một development dependency, hãy nhập câu lệnh sau :
$ npm install webpack-dev-server --save-dev
Và sau đó thêm một đoạn script npm vào file package.json
:
{
"name": "modern-javascript-example",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack --progress -p",
"watch": "webpack --progress --watch",
"server": "webpack-dev-server --open"
},
"author": "",
"license": "ISC",
"dependencies": {
"moment": "^2.19.1"
},
"devDependencies": {
"babel-core": "^6.26.0",
"babel-loader": "^7.1.2",
"babel-preset-env": "^1.6.1",
"webpack": "^3.7.1"
}
}
Và giờ chúng ta có thể khởi động server phát triển với câu lệnh:
$ npm run server
Việc này sẽ tự động mở một website chứa file index.html
trong trình duyệt của bạn với đường dẫn là localhost:8080
(giá trị mặc định). Bất kì thời điểm nào bạn thay đổi code JavaScript trong file index.js
, webpack-dev-server sẽ tự build lại file Javscript đã bundle và refresh lại trình duyệt một cách tự động. Đây là một chức năng sẽ giúp bạn tiết kiệm rất nhiều thời gian, vì nó cho phép chúng ta có thể tập trung vào code thay vì phải liên tục thay đổi giữa trình duyệt và code để xem những sự thay đổi mới.
Những điều tôi trình bày ở trên chỉ là những thứ thô sơ bề mặt, còn rất nhiều tuỳ chọn với webpack và webpack-dev-server (mà bạn có thể tham khảo thêm ở đây). Bạn có thể tự tạo cho mình những đoạn script npm để chạy các công việc khác, như là conver từ SCSS về CSS, nén ảnh, chạy test - bất kì thứ gì hỗ trợ command line tool. Đồng thời cũng có rất nhiều tuỳ chọn nâng cao cùng với vài mẹo nho nhỏ hay ho với script về npm, mà bạn có thể tham khảo ở bài talk dưới đây của Kate Hudson
Tổng kết
Trên đây là tổng quan về Javascript thời nay. Chúng ta đã đi từ thuần HTML và JS đến sử dụng một bộ quản lý package để tự động download các package cuả những bên thứ 3, dùng một công cụ bundle cho module để tạo ra một file script duy nhất, một bộ biến đổi để sử dụng các chức năng JS mới nhất, và một công cụ chạy task để tự hoá nhiều thành phần trong quá trình build. Đương nhiên là có rất nhiều thứ ở đây, đặc biệt là đối với người mới bắt đầu. Phát triển web đã từng là điểm bắt đầu rất tuyệt vời cho người mới học lập trình bởi nó rất dễ dàng để hiểu và phát triển; tuy nhiên ngày nay nó có thể trở nên khá là oải, đặc biệt trong tình trạng các công cụ thay đổi một cách chóng mặt hiện nay.
Tuy nhiên mọi việc ko hẳn tệ đến mức như vậy. Nhiều thứ đang trở nên ổn định dần, đặc biệt với sự thích nghi của hệ sinh thái node trong việc hỗ trợ phát triển phía frontend. Việc sử dụng npm như một công cụ quản lý package, các câu lệnh require
hoặc import
cho modules, và các đoạn script npm để chạy task đã trở nên rất tốt và gần như là mặc định. Đây có thể nói là một workflow khá là đơn giản và mạnh mẽ khi so với thời điểm 1 hoặc 2 năm trước đó!
Một điều nữa cũng khiến các lập trình viên cảm thấy dễ thở hơn, đó là việc các framework thời nay đã có thêm các công cụ để làm cho quá trình phát triển trở nên dễ dàng hơn. Ember có ember-cli, là công cụ lấy cảm hứng phần lớn từ angular-cli của Angular, React thì có create-react-app, Vue thì có vue-cli,... Tất cả các công cụ sẽ giúp bạn khởi tạo một project với mọi thứ bạn cần - tất cả mọi thứ, để bạn có thể lập tức bắt tay vào viết code. Tuy nhiên các công cụ đó ko phải là phép thuật, nó chỉ đơn giản lại quá trình cài đặt dưới một tiêu chuẩn ổn định và theo phong cách chung. Cũng có những thời điểm bạn muốn thêm vào một vài tuỳ chỉnh với webpack, babel... nên việc hiểu được công dụng và khả năng của từng thành phần là rất quan trọng (đã được nói đến trong bài viết này).
Javascript thời nay rất có thể trở nên bối rối khi phải làm việc cùng bởi sự thay đổi và tiến hoá chóng mặt của nó. Nhưng cùng với đó, vào nhưng thời điểm giống như lúc xây dựng lại cái bánh xe, sự phát triển nhanh chóng của Javascript đã thúc đẩy sự tiến bộ và cho ra đời những điều rất tuyệt vời như là hot reloading, linting (phân tích, tối ưu code) thời gian thực, debug code qua nhiều thời điểm - giống như du hành thời gian. Đây là thời gian rất thú vị để trở thành một lập trình viên, và tôi hy vọng những thông tin này có thể giúp bạn như một lộ trình trên con đường sự nghiệp của mình.
All rights reserved