Khi tôi tìm hiểu về React.js, tôi thấy họ có dùng webpack để “bundle” các module. Trong các bài giới thiệu về Reactjs trước tôi có dùng Browserify để “bundle” các module của Node.js thấy đơn giản và cũng khá hay. Tôi có qua trang tài liệu của webpack-doc để thử tìm hiểu thì thấy hơi khó nhai nên tôi quyết định viết blog để có thể tìm hiểu sâu hơn cũng như có thể chia sẽ với những ai muốn tìm hiểu về nó.
Webpack là gì
Ngay tại trang document:
http://webpack.github.io/docs/what-is-webpack.html
webpack is a module bundler.
webpack takes modules with dependencies and generates static assets representing those modules.
Tôi nghĩ cách hiểu nhanh nhất về nó là ta phải “đụng tay đụng chân” với nó thôi.
Hướng tìm hiểu
- Bundle các file JS thành 1 file JS.
- Bundle ra các file JS chính từ nhiều file JS
- Chia file JS và load khi cần
- Nhúng HTML vào trong file JS
- Nhúng CSS vào trong file JS
- Nhúng file hình Base64 vào trong file JS
1. Bundle các file JS thành 1 file JS
Chuẩn bị:
./
|_app.js
|_sub.js
|_dist
|_index.html
app.js
var sub = require('./sub.js');
sub("Hello world");
sub.js
module.exports = function(msg){
alert(msg);
}
index.html
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>Webpack Tutorial Demo</title>
</head>
<body>
<script src="bundle.js"></script>
</body>
</html>
Nếu bạn lười thực hiện các bước trên, các bạn có thể clone từ github repo demo của tôi:
https://github.com/phungnc/webpack-tut/tree/master/demo01
Bundle command:
webpack app.js dist/bundle.js
Sau đó chạy file index.html
thì nó sẽ hiển thị message “Hello world”.
Bundle command trên có cú pháp như khi sử dụng Browserify (browserify app.js > dist/bundle.js). Tuy nhiên khác với Browserify, Webpack có thể config việc bundle đó trong file: webpack.config.js. Hãy tạo file webpack.config.js đồng cấp với file app.js
module.exports = {
entry: {
app: './app.js'
},
output: {
path: __dirname + '/dist',
filename: 'bundle.js'
}
}
Sau đó chỉ cần bạn chạy lệnh
webpack
Thì nó cũng tạo ra file bundle.js giống như trước.
2. Bundle ra các file JS chính từ nhiều file JS
Source code demo:
https://github.com/phungnc/webpack-tut/tree/master/demo02
webpack.config.js
module.exports = {
entry: {
app: './app.js',
list: './list.js',
item: './item.js',
},
output: {
path: __dirname + '/dist',
filename: '[name].js'
}
}
Run webpack
command, hãy xem output in ra:
Hash: 42caea66a4d1045d2c6c
Version: webpack 1.12.2
Time: 68ms
Asset Size Chunks Chunk Names
app.js 1.56 kB 0 [emitted] app
item.js 1.56 kB 1 [emitted] item
list.js 1.56 kB 2 [emitted] list
[0] ./app.js 43 bytes {0} [built]
[0] ./item.js 43 bytes {1} [built]
[0] ./list.js 44 bytes {2} [built]
[1] ./sub.js 47 bytes {0} {1} {2} [built]
Nó built ra các file trong thư mục dist các file app.js,list.js, item.js tương ứng đã được config trong file webpack.config.js. Khả năng có thể build ra nhiều file js cũng là điểm thú vị của webpack.
Nhưng mà, nếu ta xem trong các file app.js, list.js hay item.js thì có phần source code cả 3 file đều trùng nhau:
/******/ (function(modules) { // webpackBootstrap
/******/ // The module cache
/******/ var installedModules = {};
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/ // Check if module is in cache
/******/ if(installedModules[moduleId])
/******/ return installedModules[moduleId].exports;
/******/ // Create a new module (and put it into the cache)
/******/ var module = installedModules[moduleId] = {
/******/ exports: {},
/******/ id: moduleId,
/******/ loaded: false
/******/ };
/******/ // Execute the module function
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/ // Flag the module as loaded
/******/ module.loaded = true;
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/ // expose the modules object (__webpack_modules__)
/******/ __webpack_require__.m = modules;
/******/ // expose the module cache
/******/ __webpack_require__.c = installedModules;
/******/ // __webpack_public_path__
/******/ __webpack_require__.p = "";
/******/ // Load entry module and return exports
/******/ return __webpack_require__(0);
/******/ })
/************************************************************************/
Để giải quyết vấn đề này ta có thể sử dụng plugin:
webpack.config.js
var webpack = require('webpack');
module.exports = {
entry: {
app: './app.js',
list: './list.js',
item: './item.js',
},
output: {
path: __dirname + '/dist',
filename: '[name].js'
},
plugins: [
new webpack.optimize.CommonsChunkPlugin('app','app.js')
]
}
Chạy lại command
webpack
Bây giờ bạn thử check lại trong các file dist/list.js
và dist/item.js
xem. Phần source code giống nhau bây giờ chỉ còn lại ở file dist/app.js
.
3. Chia file JS, chỉ load khi cần thiết.
Nếu bạn nào đã từng dùng qua requirejs rồi thì sẽ dễ dàng hiểu phần này hơn.
Ta có thể gọi chức năng này là module loader, tức là ta có thể load một module khi nào cần thiết. Khác với việc tạo một file bundle bao gồm tất tần tật các module JS vào, với webpack ta có thể cấu hình để chỉ load module cần thiết khi cần thiết thôi. Việc này có lợi cực kỳ khi hệ thống ngày càng lớn, khi đó nếu chỉ dùng 1 file bundle thì việc load ban đầu sẽ trở nên chậm chạp làm giảm performance của app, ngược lại việc load module một cách bất đồng bộ sẽ giúp tăng performance của app.
Ta sẽ demo bằng cách là trong file app.js sẽ load module sub.js sau 3 giây.
Source code:
https://github.com/phungnc/webpack-tut/tree/master/demo04
app.js
window.setTimeout(function() {
require.ensure([],function(sub) {
var sub = require('./sub');
sub('App');
});
},3000);
Run WebPack command
webpack
Hãy thử mở file index.html, sau khi mở lên, 3 giây sau thì nó sẽ alert “App”. Bạn có thể dùng Chrome Develop Tool để xem tiến trình load này.
4. Nhúng file HTML vào trong file JS
Bằng việc sử dụng module html-loader, ta có thể load file HTML vào trong file JS.
Trước hết ta phải install html-loader
Source code:
https://github.com/phungnc/webpack-tut/tree/master/demo04
npm install html-loader --save-dev
Sau đó trong webpack.config.js file:
module.exports = {
entry: {
app: './app.js'
},
output: {
path: __dirname + '/dist',
filename: 'bundle.js'
},
module: {
loaders: [
{ test: /\.html$/, loader: 'html-loader' },
]
}
}
Thêm phần load module html-loader.
Về phần source code, chuẩn bị file HTML có nội dung nào đó như là:
container.html
<div id="container">
<section>
<h2>Web pack is Cool</h2>
<p>webpack is a module bundler.</p>
<p>webpack takes modules with dependencies and generates static assets representing those modules.</p>
</section>
</div>
app.js
var container = require('./container.html');
document.body.innerHTML = container;
Và run WebPack command:
webpack
Với việc nhúng HTML từ bên ngoài vào trong JS, thì chúng ta sẽ dễ nghĩ đến hướng chia cấu trúc trang web thành các template, component. Phần này có lẽ tôi sẽ giới thiệu trong các bài viết sau.
5. Nhúng file CSS vào trong file JS
Tương tự như việc load file HTML vào trong file JS, ta cũng có thể sử dụng các module style-loader và css-loader để nhúng CSS vào trong file JS.
Source code:
https://github.com/phungnc/webpack-tut/tree/master/demo05
npm install style-loader css-loader --save-dev
css-loader: tạo chuỗi css và nhúng vào trong file JS.
style-loader: ghi style vào trong tag
webpack.config.js
module.exports = {
entry: {
app: './app.js'
},
output: {
path: __dirname + '/dist',
filename: 'bundle.js'
},
module: {
loaders: [
{ test: /\.html$/, loader: 'html-loader' },
{ test: /\.css$/, loaders: ['style-loader', 'css-loader']},
]
}
}
Sau đó bạn có thể chuẩn bị tùy ý style mà bạn thích trong file style.css như là:
style.css
#container {
width: 800px;
margin: 0 auto;
}
section {
text-align: center;
}
Gọi css vào trong file app.js
require('./style.css');
var container = require('./container.html');
document.body.innerHTML = container;
Run webpack
webpack
6. Nhúng file image dạng base64 vào trong file JS
Sau cùng, chúng ta thử nhúng file hình vào trong file JS. Ta sử dụng url-loader
npm install url-loader --save-dev
Cũng tương tự như những phần trên, cho nên tôi sẽ không giới thiệu lại, các bạn có thể tham khảo source code bên dưới:
Source code
https://github.com/phungnc/webpack-tut/tree/master/demo06