Đầu kỷ nguyên internet, website đơn giản hơn và ít tương tác hơn. Với sự tiến bộ của công nghệ, thiết bị, và ngôn ngữ lập trình, chúng trở nên phức tạp hơn và bao gồm nhiều file, bao gồm asset như ảnh và CSS stylesheet.
Càng tương tác, càng nhiều JavaScript code bạn phải dùng. Để dùng code đó, bạn phải include tất cả file HTML dùng script tag. Cách tiếp cận này error-prone vì bạn phải nhớ include mọi file đơn lẻ và giữ đúng thứ tự, nếu không code có thể không chạy. Với Webpack tool, những vấn đề này biến mất. Webpacker là cầu nối giữa Webpack và Rails application.
Bài viết deep dive vào Webpacker và đưa ra giải thích chi tiết giúp bạn hiểu tool này hoạt động under the hood như thế nào. Để content có giá trị nhất, tôi quyết định chia thành các section sau:
- High-level overview — trước khi deep dive, tôi sẽ giải thích high-level overview của cả Webpack và Webpacker. Bạn có thể coi nó như preparation cho chủ đề nâng cao hơn.
- Structure explanation — vì chúng ta sẽ explore nhiều file, tốt nếu biết tại sao structure đặc biệt được dùng và nó phản ứng như thế nào cho mục đích chung.
- Anatomy explanation — phần này cover điều tra file quan trọng nhất của Webpack setup. Biết cách chúng hoạt động thiết yếu cho development hiệu quả và không rắc rối.
- Environment specific setup — phần cuối giải thích Webpacker hoạt động trong development và production environment như thế nào.
Sau khi đọc bài, bạn sẽ biết Webpack và Webpacker là gì và tại sao chúng ta cần chúng trong Rails app. Deep dive vào internal Webpacker sẽ giúp bạn hiểu tool kết nối với Webpack như thế nào và giao tiếp với Rails app như thế nào.
Trước Khi Deep Dive
Trước khi ra biển sâu, chúng ta cần chuẩn bị. High-level overview là cách tuyệt vời bắt đầu với bất kỳ công nghệ nào vì nó giúp hiểu mục đích tool và vấn đề nó giải quyết mà không cần deep vào internal.
Webpack
Tôi đã nhắc Webpack giúp organize JavaScript file code để tránh lỗi và cải thiện performance website. Nó organize code thành bundles.
Bundle là file nơi multiple module được đặt thông minh, tôn trọng dependency graph được tạo trước. Nhờ process này, chúng ta chắc chắn code sẽ chạy như kỳ vọng và trước khi invoke code của library cho trước, nó đã được loaded.
Webpack không phải tool duy nhất dùng mặc định trong Rails mới nhất. Khi project được generate, config file cho Babel và PostCSS cũng được tạo. PostCSS là tool transform CSS với JavaScript, và Babel là JavaScript compiler cho phép viết modern JavaScript mà không lo browser support.
Webpacker
Webpacker là tool integrate Webpack với Rails application. Nó làm cho việc cấu hình và phát triển JavaScript-like application dễ dàng và optimize cho production environment.
Source code có sẵn as a gem, và library đi kèm development server làm development app rất nhanh vì bạn không phải stop và start server để thấy thay đổi trong JavaScript files.
Deep Immersion (Sâu hơn)
Bây giờ bạn biết tại sao Webpack được tạo và Webpacker đóng vai trò gì trong Rails app, chúng ta có thể focus vào internal Webpacker để xem nó organize file, speed up development, và optimize file cho production như thế nào.
Webpacker có sẵn out-of-the-box trong Rails mới nhất. Trước khi tạo project mới, đảm bảo Node version >= 10.17.0 vì command webpacker:install sẽ tự động invoke với rails new command.
Cấu trúc File Webpacker
Sau khi install command chạy, các file sau được tạo:
config/webpacker.yml— file cấu hình chính chứa default config và config cho environment cụ thểconfig/webpacker/— thư mục nơi JavaScript config file cho environment cụ thể được tạobin/webpack— file executable invoke webpack để tạo bundlebin/webpack-dev-server— file executable start development server, reload webpack mỗi khi bạn thay đổi JavaScript files trong bundle
Anatomy của Configuration File
Main configuration file cho Webpacker nằm dưới config directory, tên webpacker.yml. Khác với Webpacker, config cho Webpack được lưu riêng cho mỗi environment dưới config/webpack directory.
Webpacker
Mặc định, config file chứa nhiều entry — default, và section cho mỗi environment nơi bạn có thể overwrite setting cụ thể. Hãy xem setting quan trọng nhất:
source_path— primary source của javascript files trong app. Mặc địnhapp/javascript, thường không cần thay đổi.source_entry_path— tên thư mục dưới source_path nơi bạn giữ pack files (entry points). Mặc định là packs directory.public_root_path— path đến thư mục trong app accessible từ browser. Trong Rails app điển hình, là public directorypublic_output_path— khi Webpacker compile file, nó sẽ đặt tất cả compiled file trong thư mục này dướipublic_root_path. Mặc định tên thư mục là packs, nhưng bạn có thể đặt tên gì.webpack_compile_output— nếu flag = true, output message hiển thị khi compile file. Hữu ích khi compile fail, bạn sẽ biết và hành động.
Worth mentioning: development section cũng chứa config cho dev server dùng compile file trong development environment không cần restart server.
Nếu muốn access config từ rails console hoặc code level, bạn có thể gọi Webpacker.manifest.config, sẽ return config class instance.
Webpack
Mỗi environment có config file riêng, nhưng trong mọi file, main environment file được import: config/webpack/environment.js. Trong environment config file, có chỗ load custom plugin modify default behavior Webpack. Chúng ta cũng có thể add custom rule compile file.
Anatomy của Pack File
Pack nằm dưới app/javascript/packs directory. Mỗi pack file được Webpacker coi là entry point khi compilation process bắt đầu.
Default Pack File
Khi generate Rails project mới, default pack file tên application.js được tạo với content:
import Rails from "@rails/ujs"; import Turbolinks from "turbolinks"; import * as ActiveStorage from "@rails/activestorage"; import "channels"; Rails.start(); Turbolinks.start(); ActiveStorage.start();
Như bạn thấy, bước đầu import library, sau đó gọi initialization method khi cần. Khi gọi import, system tìm node module hoặc local library. Với standard approach, bạn không phải explicitly initialize library vì nó initialized khi include trong page source với script tag.
Good Practices cho Pack File
Mặc dù bạn có thể đặt regular JavaScript code trong pack file và execute, không khuyến khích giữ JavaScript code trong pack file. Cách tốt nhất là giữ file sạch và chỉ import và initialize library ở đây, giữ logic khác ngoài packs directory.
Include Pack File trong Application
Pack file không tự động include trong website source. Giống asset pipeline case, chúng ta phải dùng special tag trong view:
<%= javascript_packs_with_chunks_tag 'application' %>
Method này hoạt động như thế nào? Under the hood, nó gọi Webpacker configuration hold data bạn đặt trong config/webpacker.yml. Nó tìm application.js file trong entry points directory, trong case chúng ta là app/javascript/packs. Bạn có thể verify bằng code:
Webpacker.manifest.config.source_entry_path
Khi entry được tìm thấy, Webpacker gọi method javascript_include_tag, helper từ ActionView library có sẵn trong Rails. Method chấp nhận một hoặc nhiều source và return script tag bạn apply thẳng vào view.
Development Server
Webpacker development server entry point là executable file trong bin folder tên webpack-dev-server. Quá trình chạy server gồm 5 bước:
- Setting environment — environment name cho Node và Rails được set. Khi environment không chỉ định, chương trình assume server chạy trong development environment.
- Loading configuration — file
config/webpacker.ymlđược load với setting cho environment set ở bước trước. - Validating command options — chương trình check xem chúng ta pass appropriate options cho server command. Ví dụ, nó throw error khi option
--httpscho nhưng không specify trongconfig/webpacker.yml. - Verifying port's availability — chương trình check port có available không. Nếu chương trình khác đang dùng, nó throw error báo bạn update webpack server config trong
config/webpacker.yml. - Executing webpack serve command — khi node_modules directory tồn tại, chương trình execute command trong directory, ngược lại execute với yarn. Chương trình pass config option cho command point đến file trong
config/webpack/directory.
Server đang chạy, và nó compile code on the fly, nên bạn không phải restart server để thấy thay đổi và check webpack có tạo bundle với code mới không.
Development server code khá đơn giản. Nó chỉ load config từ YAML config file và pass proper config ở JavaScript format trực tiếp cho command webpack serve. Bạn cũng có thể chạy thủ công, nhưng không phải lo command arguments với built-in command.
Compile File cho Production Environment
Giả sử bạn muốn deploy app dùng webpacker. Lúc đó, bạn chỉ cần invoke task assets:precompile vì Webpacker tự động hook task webpacker:compile vào nó.
Task webpacker:compile hoạt động under the hood như thế nào? Hãy đào sâu xem. Nó làm những điều sau:
- Wrap main call vào hai block đảm bảo
NODEenvironment được set và Webpacker logs output ra standard out. - Gọi Webpack và parse logs để xác định action thành công hay không.
Bây giờ bạn có thể visit public/packs/js directory để xem compiled file. Chúng nên được deploy lên server.
Tóm tắt
Chúng ta vừa học Webpacker hoạt động under the hood như thế nào. Bạn có thể coi nó như cầu nối giữa Webpack library và Rails application cho phép cấu hình Webpack với Ruby và dễ dàng dùng JavaScript code trong app.
Để tóm tắt bài, hãy nhớ lại main element của Webpacker:
- Configuration — đặt trong
config/webpacker.ymlcho phép point Webpacker đến directory giữ javascript files và packs - Pack — single entry point Webpacker bắt đầu compilation. Mọi library import và initialize trong file đó sẽ tự động compile.
- Development server — script đơn giản cho phép compile file on the fly, không phải restart server mỗi lần modify JavaScript files
- Compile task — rake task đơn giản invoke Webpack và compile file dưới public directory để deploy lên production server cho end-user
- View helper — helper cho phép include compiled file trong view
Với nhiều developer ít kinh nghiệm, Webpacker hơi magical, nhưng thực tế nó là library đơn giản giúp dùng Webpack theo Ruby way.
P.S. Nếu bạn muốn đọc bài Ruby Magic ngay khi ra mắt, hãy subscribe newsletter Ruby Magic và không bao giờ bỏ lỡ bài nào!