Đây là phần 2 sau 2 tuần ăn nằm với ẻm webpack nó. Mình có rút ra được 1 số bài học và 1 số kinh nghiệm cũng như cách thức làm việc với nó. Ở bài viết này mình sẽ nói về những điều mà mình đúc kết được ra, hi vọng các bạn đọc có các phản hồi để mọi người cùng nhau học hỏi hơn. ( Đây cũng là bài viết được trích từ nhật ký học tập của mình sau bài viết thứ nhất trong cùng serie về webpack hơn 1 năm về trước)
Ok giờ mình sẽ bắt đầu đi vào bài viết chính luôn. Dươi đây là những phần mục mà mình sẽ đề cập tới trong bài viết:
- Cấu hình tổ chức webpack
- Làm việc với Loader
- Làm việc với Plugin
- Các kinh nghiệm khi làm việc với webpack
Để dễ hiểu hơn mình khuyên các bạn nên clone project sample dưới đây của mình để tiện theo dõi cũng như có cái nhìn trực quan hơn về các chức năng mình đề cập ở bai viết dưới đây.
1. Các cách thức tổ chức webpack để chạy trên nhiều môi trường khác nhau
- Khi làm việc với webpack mình phát hiện các tiền bối đi trước sử dụng webpack và viết chúng triển khai trên các môi trường theo 3 hình thức khác nhau
- Cách 1: Tổ chức webpack dưới 1 file duy nhất là file webpack.config.js: tại thiết lập này, toàn bộ thông tin bundle mình sẽ viết hết trong 1 file duy nhất (webpack.config.js) này mình phải cấu hình đặt biến môi trường thích hợp và sử dụng biến đó để thiết lập mỗi khi setup môi trường
- Cách 2. Tổ chức webpack dưới node API: nghe thì có vẻ ghê thực ra nó chỉ là config lại webpack dưới dạng nhiều file javascript tương ứng cho từng môi trường thay vì bạn phải config toàn bộ trong 1 file webpack.config.js. Xem thêm tại đây.
Chú ý: Bài viết hôm trước của mình chỉ là 1 cách nhỏ bố trí cũng theo cách 2 này, nhưng cách 2 này thực ra nó làm chi tiết và tởm lợm nhiều file hơn ấy. Bạn có thể xem link ở cách2 mà mình đề cập trên hoặc không thì clone repo create-react-app về và xem cách viết và tổ chức webpack của họ thật là quá bá đạo luôn :D.
2. Làm việc với Loader
- Hôm nọ mình đã đề cập chi tiết về cách tổ chức cũng như chi tiết cho các thuộc tính define trong loader rồi vậy lên ở bài viết này mình sẽ chỉ giới thiệu các module loader phổ biến mà mình thấy mọi người hay sử dụng như dưới đây:
- Danh sách các loader:
- file-loader: để nạp và bundle các tập tin, định dạng chỉ định trước, khi sử dụng css hoặc javascript có gọi tơi các hình ảnh, tập tin các file định dạng liên quan thì file-loader sẽ có nhiệm vụ parse (phân tích) và bundle coppy nó vào trong ouput config ở webpack
- url-loader: giống file-loader có điều url-loader giúp mã hóa các file ảnh (png, jpeg, svg, gif ...) thành chuỗi base64 => chỉ lên áp dụng với các file dữ liệu nhỏ ), thiết lập mã hóa nhỏ hơn kích thước limit chỉ định. Xem thêm tại : https://github.com/webpack/url-loader . Khi kích thước lớn hơn nó sẽ hoạt động giống như file-loader
- ora: Thư viện hiển thị tiến trình đang xử lý khi chạy webpack (có thể áp dụng nơi khác)
- eslint-loader: check syntax javascript. Chú ý phải cài các phụ thuộc npm i eslint –g, eslint-plugin-react, eslint-config-default, babel-eslint
- jshint-loader: tương tự eslint-loader để check syntax javascript: rất mạnh khuyến khích lên dùng,,
- image-webpack-loader: sử dụng để nén ảnh, thường đi kèm css-loader và style-loader
- css-loader, style-loader, less-loader, sass-loader: bộ nạp thư viện của css. Chú ý. Nếu nạp nhiều loader thì style-loader phải viết nạp trước css-loader (cssloader để tạo ra chuôi css 1 là nhúng vào file bundle javascript 2 là tách ra 1 file riêng, còn style-loader có nhiệm vụ lấy chuỗi css optimize đó gắn vào file html thông qua thẻ <style>)
- extract-text-webpack-plugin: Sử dụng tách file css ra riêng
- resolve-url-loader: giải quyết cho việc nạp các url-relative, thường đi kèm style-loader và url-loader
- postcss-loader: sử dụng để autoprefix (tự động fix css phù hợp với các trình duyệt), thường đi kèm với phụ thuộc css-loader và style-loader, ngoài ra postcss-loader còn làm được rất nhiều thức khác
- babel-loader: tranfer code từ es6, jsx (react) sang es5. Các phụ thuộc đi kèm bao gồm: babel-core, babel-preset-es2015, babel-preset-stage-2
- strip-loader: hủy bỏ console.log trong toàn bộ code javascript bundle
- ng-annotate-loader: giúp sinh ra các chú thích phụ thuộc (dependency) cho mã angular, Điều này là cực kỳ hữu ích vì chỉ có như vậy khi minify mã angular code release sẽ không bị chết. Có thể sử dụng thay thế với ng-annotate-webpack-plugin.
- html-loader: bộ loader nhận diện các thẻ img bên trong file html từ đó lấy link này kết hợp với url-loader và file-loader sẽ tiến hành load ảnh vào hệ thống bundle
- raw-loader: bộ loader giúp load file html dưới dạng javascript, hữu ích khi làm việc với angular 2 nó giúp must code của các đoạn mã html vào javascript
Cách sử dụng loader:
Chú ý: Khi làm việc với query parameter, nếu ta sử dụng 1 loader thì không sao, nếu sử dụng với nhiều loader thì sẽ bị chết, lý do là trên webpack vesion <2.0 không thể sử dụng được với cách query mà phải sử dụng query parameter như ở ví dụ trên cùng, (nếu sử dụng >2.0 thì sẽ chạy được)
3. Làm việc với Plugin
Danh sách các plugin mà mình đã sử dụng và làm việc
- Default plugin webpack: là các plugin mặc định mà webpack đã hỗ trợ ta mặc định, chỉ cần cài webpack là có thể sử dụng, dưới đây là 1 số plugin phổ hay dùng mặc định của weback.
- BannerPlugin: Gắn tiêu đề banner cho file mã xuất ra.
- NoErrorsPlugins : Nếu có lỗi thì chỉ xuất ra file html.
- Optimize.UglifyPlugin: Sử dụng nén javascript, html theo nhiều lựa chọn (xem chi tiết tại trang chủ webpack).
- ProvidePlugin: Defind vào các phụ thuộc thư viện javascript để sử dụng trong mã js, các defind này sẽ mặc định được đính kèm vào file mã js mà ta có sử dụng các thư viện này
- CommonChunkPlugin: đây là plugin mặc định đi theo webpack sử dụng phổ biến nhất: Sử dụng phân chia nhánh, tạo ra file mã chung cho các file định nghĩa đầu vào, ...
- HotModuleReplacementPlugin: plugin này chỉ được sử dụng trên môi trường development, giúp tạo ra server riêng tự động reload khi có bất kỳ thay đổi nào từ các file hệ client của project, giúp việc phát triển trực quan hơn... mặc định khi sử dụng. Xem chi tiết thêm tại: https://webpack.github.io/docs/webpack-dev-server.html
- Plugin từ thư viện cài thêm.
- html-webpack-plugin: là 1 trong module bên thứ 3 phổ biến nhất, sử dụng để coppy html, minify html theo nhiều định chuẩn, nạp các file javascript theo các nhánh định trước(chunk) vào file html.
- ng-annotate-webpack-plugin: chức năng giống với ng-annotate-loader đã giới thiệu ở trên.
4. Kinh nghiệm rút ra từ cách làm việc với webpack
- Sử dụng webpack.config.babel.js : để viết webpack với es6, hoặc sử dụng webpack > 2.0 cũng support es6
- Sử dụng lodash để merg và push các đối tượng khi config webpack
- Triển khai trên các môi trường
- Dev:
- Để source map, bỏ minify html, js, css... .
- Sử dụng url-loader với giá trị limit cao để đưa toàn bộ ảnh về base 64 tiện cho việc test.
- Không hủy bỏ console.log, comment đoạn mã
- Không đặt tên file dưới dạng hash (khó debug), không require <script> file với liên kết đính kèm hash
- Thiêt đặt bật chế độ check syntax js với eslint hoặc jshint
- Build (product):
- Bỏ source map
- Minify html, js, css
- Sử dụng url-loader với limit nhỏ hơn 10kb, sử dụng publicPath =”/” để ko bị chết ảnh khi set static file server nodejs
- Hủy bỏ comment, console.log (hủy với strip-loader hoặc drop-console trong UgilifyJsPlugin....)
- Hash toàn bộ tên file js, font, image. Ngoài ra hash thêm cả liên kết khi require <script> vào Html. Tiện cho việc client load lại file không cache thông qua tham số hash.
- Hủy toàn bộ các trùy trọn thông báo lỗi: (báo lỗi trên html, báo lỗi khi check cú pháp với eslint hoặc jshint, báo lỗi khi nén file)
- Thiết lập watch: false do trên môi trường này là môi trường hoàn chỉnh ta ko cần thiết lập theo dõi nữa, mà toàn bộ theo dõi, test sẽ được thiết lập trên môi trường test và dev.
- Test
- Để souremap: dễ debug.
- Minify html, js, css: nhờ có sourcemap ta sẽ ánh xạ được đoạn mã ko bị minify.
- Không hủy console.log và comment tiện cho debug.
- Không hash file.
- Thiết lập chế đọ check syntax với eslint hoặc jshint.
- Sử dụng thiêt lập watch: true để theo dõi và tự động bundle lại code mỗi khi thay đổi.
- Khi làm việc với webpack, ngay từ đầu ta hay xem sét kỹ lưỡng việc sử dụng các file script require vào hệ thống thông qua thẻ <script src=”......” ></script>. Nếu bạn sủ dụng CDN thì mình ko nói vấn đề gì, nếu bạn sử dụng các file require từ hệ thống thì webpack chính là 1 sự lý tưởng khi require các đoạn mã được bundle vào html.
- Với trường hợp này plugin bạn lên quan tâm và chú ý nhất là: CommonChunkPlugin, tại đây bạn phải thiết lập nhiều CommonChunkplugin để lấy ra các file chung nhất require cho hệ thống
- Các file font, css hay bootstrap.css lên được import vào file css custom của ta thông qua từ khóa @import
- @import "../../asset-static/libs/bootstrap/dist/css/bootstrap.min.css";
- @import '../css/style-main.css';
- Các file ảnh img được require từ hệ thống có thể thay thế relative link bằng cách viết require image element. Bác nào sử dụng react sẽ rất rõ cái khoản import image này :).
- Các file script thay thế cho CDN giờ đây hay sử dụng nó 1 cách hợp lý bằng cách import nó vào file main hay file app của bạn, tất cả các file import đó sau này sẽ được webpack bundle tất cả lại làm 1 file, giúp cho việc tối ưu và số request tốt hơn nhiều. (thử tưởng tượng bạn request trang chủ lên và gửi yêu cầu lấy file angular, angular-router, bootstap, jquery, angular-material, app, app.directive, app.controller ... và rất nhiều các file khác nữa đi) tất cả giờ đây được import vào 1 file chung hay có thể là 2,3 file (bằng cách chia nhánh CommonChunkPlugin). Số request rõ ràng là giảm đi vô cùng đáng kể, chưa tính tới dung lượng thu nhỏ đi làm cho việc tối ưu tốt hơn nhiều
Vậy là mình đã đề cập qua một vài exp cũng như thủ thuật nhỏ nhỏ mà mình đã tiếp cận với webpack vài tuần qua rồi. Hi vọng là nó có hữu ích khi các bạn mới bắt đầu làm quen với webpack. Các bạn cùng để lại góp ý để mọi người cùng học hỏi thêm nhé :D !.