JSBundling provides a flexible way of using different Javascript bundlers like esbuild, rollup.js or Webpack.
It strikes a great balance between the asset pipeline and webpacker.
jsbundling-rails
is a much more lightweight integration.
This gem provides installers to get us going with the bundler of our choice in Rails application,
and a convention to use app/assets/builds
to hold our bundled output as artifacts.
The idea behind jsbundling is that we still use Yarn
and the package.json
file,
but the built bundle goes into the asset pipeline download rather than being controlled by webpack.
Installation
We must already have node
and yarn
installed on our system.
We will also need npx
version 7.1.0
or later.
Then:
-
Add
jsbundling-rails
to Gemfile withgem 'jsbundling-rails'
-
Run
./bin/bundle install
-
Run
./bin/rails javascript:install:esbuild (or replace esbuild with rollup or webpack)
Or, in Rails 7+,
we can preconfigure our new application to use a specific bundler with rails new myapp -j [esbuild|rollup|webpack]
.
The installer creates an app/assets/build
directory,
appends that directory to the asset pipeline manifest at
app/assets/config/manifest.js
and .gitignore
it.
The jsbundling:install
command inserts a javascript_include_tag tag
in our application.html.erb
file.
This tag will include the new javascript entrypoint javascript/application.js
for our build script to be included in our application.
Watch Mode
Run the bundler in watch mode in a terminal with yarn build --watch
.
Start dev server with foreman start -f Procfile.dev
or run rails s
and yarn build --watch
separately.
We can also use ./bin/dev
,
which will start both the Rails server and the JS build watcher.
Whenever the bundler detects changes to any of the JavaScript files in our project,
it’ll bundle app/javascript/application.js
into app/assets/builds/application.js
.
Production
When we deploy our application to production,
the javascript:build
task attaches to the assets:precompile
task
to ensure that all our package dependencies from package.json
are installed via yarn,
and then runs yarn build to process all the entry points,
as it would in development.
The latter files are then picked up by the asset pipeline, digested,
and copied into public/assets
,
like any other asset pipeline file.
We can configure our bundler options in the build
script in package.json
or via the installer-generated rollup.config.js
for rollup.js
or webpack.config.json
for Webpack.
One fantastic thing about jsbundling-rails
is even if we decide to use Webpack instead of esbuild
we can easily swap it out, and unlike Webpacker it will use a raw webpack config file.
That was a great decision because I imagine people who want to go all-in with Webpack will want to use their existing configs.
Comparison with webpacker
If we’re already using webpacker
,
we may be wondering how it compares to jsbundling-rails
and whether we should migrate or stick with webpacker
.
Here are some considerations:
-
jsbundling-rails
is a much more lightweight integration.webpacker
is more involved and opinionated. -
jsbundling-rails
can be used with multiple bundlers (currentlyesbuild
,rollup
, andwebpack
are supported out of the box, but anything that can put a bundle intoapp/assets/builds
could be configured to work with it).webpacker
is built specifically to integrate with webpack. -
jsbundling-rails
doesn’t tie us to specific versions of the JavaScript packages we use for bundling, transpiling, etc.webpacker
releases are tied to a specific major version ofwebpack
,babel
, etc. This means we cannot freely upgrade those packages - we have to wait for a newwebpacker
major release that supports the newer versions, and upgrading to that newwebpacker
release requires upgrading to all of those new JavaScript package versions at once. -
jsbundling-rails
uses the standard configuration format for our bundler of choice.webpacker
has its configuration layer on top of webpack’s configuration, which requires us to do some translation when following guides/documentation written directly for webpack. -
jsbundling-rails
works with the standard actionview asset helpers.webpacker
provides the tag helpers that we need to use. -
webpacker
can be used as a complete replacement for sprockets, and in that setup, we can stop loading the sprockets/railtie in our application.jsbundling-rails
(as well as css-bundling-rails) works in conjunction with sprockets. -
webpacker
supports using a dev server for hot reloading.jsbundling-rails
hands-off static files to sprockets, so hot reloading is not supported (i.e., to load any JavaScript changes, we’ll need to do a local-state-clearing full page refresh). -
webpacker
delegates asset processing entirely to the external nodejs tooling.jsbundling-rails
still relies on sprockets to output the final public assets and create the associated manifest. When the webpack has full control over the result, it can integrate additional features like automatic code-splitting of statically imported shared dependencies, andwebpacker
can load each entry point’s dependent chunks for us. Withjsbundling-rails
, we’ll be able to manually split out lazy-loaded chunks by using dynamic import()s.
To know more about this feature checkout this PR.