What is Webpacker?
The goal of Webpack, or any front-end build system, is to allow you to write your front-end code in a way that is convenient for developers and then package that code in a way that is convenient for browsers.
As of Rails 6, Rails started to bundle and wrap Webpack inside the Rails applications. This is done through Webpacker.
Webpacker related files
The Webpacker installation process calls the yarn package manager, then creates a package.json file with a basic set of packages listed, and uses Yarn to install these dependencies.
Along with that the following local files are created by Webpacker:
|Webpacker Configuration||config/webpacker.yml||Configure the Webpacker gem|
|PostCSS Configuration||postcss.config.js||Configuration for the PostCSS CSS Post-Processor|
|Browserlist||.browserslistrc||Browserlist manages target browsers configuration|
This is how that directory would look like:
1 . 2 ├── channels 3 │ ├── consumer.js 4 │ └── index.js 5 ├── packs 6 │ └── application.js 7 ├── src 8 └── stylesheets 9 └── application.scss
The channels directory is generated by Action Cable component of Rails. It's not that significant for us at the moment.
The stylesheets and src directories are usually created by us, manually.
The packs directory
Webpack will create a separate dependency graph for each entry point, so a large number of packs will increase compilation overhead.
Within source files, import statements are resolved relative to the file doing the import, so import Bar from "./foo" finds a foo.js file in the same directory as the current file, while import Bar from "../src/foo" finds a file in a sibling directory named src.
Difference between Webpacker and Sprockets
In particular, code can be added to Sprockets via a Ruby gem.
For transitioning from Sprockets to Webpacker, we can make use of the following tools to achieve tasks:
|Link to an image||image_url||image_pack_tag|
|Link to an asset||asset_url||asset_pack_tag|
|Require a script||//= require||import or require|
Using CSS with Webpacker
Out of the box, Webpacker supports CSS and SCSS using the PostCSS processor.
This tells Webpack to include your CSS file in the download.
To actually load it in the page, include <%= stylesheet_pack_tag "application" %> in the view, where the application is the same pack name that you were using.
Significance of stylesheet pack tag
We had replaced the stylesheet_link_tag with stylesheet_pack_tag in the application initialization chapter.
The reason is that in production environment, webpacker by default sets extract_css to true.
The way we tell Webpack which files to load is by using import or require statements. This includes CSS files, images, and everything else.
When we do import '../stylesheets/application.scss', we're telling Webpack to include application.scss in the build.
How that file compilation is handled will depend upon how our loaders (css-loader, sass-loader, file-loader, etc) are configured.
When we do <%= stylesheet_pack_tag 'application' %>, that's a run-time inclusion from Rails, that has nothing to do with whether Webpack has built the stylesheets or not.
All that line is doing is saying "if you have a pack named application-*.css, include it here".
If Webpack doesn't build a separate pack of CSS, then this statement won't have anything to load, because no stylesheets were compiled.
Handling Webpacker config for each environment
Webpacker has three environments by default development, test, and production.
You can add additional environment configurations in the webpacker.yml file and set different defaults for each environment.
Webpacker will also load the file config/webpack/<environment>.js for additional environment setup.
Webpacker during deployment
Webpacker adds a webpacker:compile task to the assets:precompile rake task, so that any existing deploy pipeline that was using assets:precompile would work.
The compile task will compile the packs and place them in public/packs.
There might be times when we have to debug issues with asset compilation as it's done in production.
We can run the following command to simulate such a compilation locally:
1SECRET_KEY_BASE=`cat config/master.key.sample` RAILS_ENV=production RAILS_SERVE_STATIC_FILES=off bundle exec rails assets:precompile
Webpacker module and version issues
Node.js v16.4.2 doesn’t support lower versions of the node-sass package. We need at least node-sass version 6.xx.
But sometimes older @rails/webpacker package comes bundled with lower versions of node-sass.
Another issue is that the npm webpacker module's version is incremented very slowly and is very prone to breaking changes once released.
That's why we stick onto a specific Webpacker version in our application.
While creating the new Rails application if the @rails/webpacker package installed is not version 5.4.0 then please update the version manually to @email@example.com.
You can check default installed Webpacker version by running:
1yarn why @rails/webpacker
Downside of not running Webpack development server during development
This can be noticed when conditionally rendering CSS with respect to the React component's state using the classnames library. In such a case, Webpack will boot from scratch and re-compile. It can make reloading the page extremely slow. For this reason it is recommended to use a development server during development.
Advantages of running Webpack development server during development
Thus reloading after each change will be really slow and time consuming if you are not running Webpack development server. The reason is that by default Webpacker, tries to compile assets from scratch with each request.
Reloading manually before the development server has finished re-compiling, will only reload the same old assets. After compilation is done the browser window running your application will automatically try to fetch the latest assets.
Another benefit of running a Webpack development server along with the Rails server is that it makes catching errors specific to the backend and frontend easier.
When we don't run a Webpack development server, any errors regarding compilation of static assets are logged to the standard Rails log. This is really hard to debug since it's only a single terminal window showing all the errors.
Whereas, upon running a Webpack development server, all compilation errors or changes in static assets are reflected in only the terminal running the webpack-dev-server.
This will make debugging easier since the errors specific to the frontend side will be logged in the terminal running Webpack development server and the errors specific to Rails side will be logged in the terminal running Rails server.