How to add esbuild to the rails asset pipeline

Posted . Visible to the public.

This are the steps I needed to do to add esbuild to an application that used the vanilla rails asset pipeline with sprockets before.

Preparations

  1. update Sprockets to version 4
  2. add a .nvmrc with your preferred node version (and install it)
  3. add gems jsbundling-rails and foreman to your Gemfile:
    gem 'jsbundling-rails'
    group :development, :test do
      gem 'foreman'
      # ...
    end
    
  4. bundle install
  5. run bin/rails javascript:install:esbuild in a console to prepare esbuild.
  6. run yarn install to install all packages so far
  7. add the plugins for esbuild you're going to need:
    yarn add esbuild-plugin-import-glob
    yarn add esbuild-sass-plugin
    
  8. create esbuild.config.js in the root folder of your project. A minimal config could look like this (kudos to Arne Hartherz):
    const railsEnv = process.env.RAILS_ENV || 'development'
    const optimize = railsEnv !== 'development'
    
    const path = require('path')
    const { default: importGlob } = require('esbuild-plugin-import-glob')
    const { sassPlugin } = require('esbuild-sass-plugin')
    
    require('esbuild')
      .build({
        entryPoints: [
          'application.js',
        ],
        bundle: true,
        outdir: path.join(process.cwd(), 'app/assets/builds'),
        absWorkingDir: path.join(process.cwd(), 'app/assets'),
        color: true,
        minify: optimize,
        sourcemap: true,
        plugins: [
          importGlob(),
          sassPlugin({ cache: true }),
        ],
      })
    
  9. Add error handling
  10. adapt your package.json to use your config file for the build command:
    "scripts": {
      "build": "node esbuild.config.js"
    }
    

Transform your existing build pipeline to use esbuild

  1. adapt your entryPoints for esbuild in esbuild.config.js. This will be your pack names. E.g.:
    require('esbuild')
      .build({
        entryPoints: [
          'frontend.js',
          'backend.js',
        ],
      // ... (more config)
    
  2. create files for your entry points and add import statements to import everything you need, e.g. frontend.js:
    import './frontend/stylesheets/base.sass'
    import './frontend/stylesheets/blocks/**/*.sass'
    
    import 'unpoly/unpoly.js'
    import 'unpoly/unpoly.css'
    
  3. run yarn build (or yarn build --watch) and resolve all errors.
    • You probably have to adapt at least your sass @import statements to use relative paths.
    • dart-sass has some differences compared to node-sass. If you run into problems that are not easy to resvole, you can switch to use node-sass with esbuild. See here Show archive.org snapshot - you have to downgrade esbuild-sass-plugin to 1.x for that, because 2.x does not support node-sass anymore.).
  4. add libraries, that were loaded via gem previously, to your package with yarn add (e.g. yarn add bootstrap@4.5.0). Note that esbuild might complain if there are references to fonts or images in a libraries' css, because it can't load them. Tell esbuild to ignore them by marking them as external in esbuild.config.js:
    external: ['*.ttf'],
    
    During the next steps you have to make sure that sprockets serves them correctly and rewrites the paths if necessary.

Prepare Sprockets to serve the assets bundled via esbuild

  1. remove entries for Rails.application.config.assets.precompile that are no longer necessary, because you now load those libraries through esbuild.
  2. adapt your app/assets/config/manifest.js file to include only the folders that sprockets needs to take care of, e.g.:
    //= link_tree ../builds/ 
    //= link_tree ../fonts/
    //= link_tree ../images/
    
    Also add library fonts or images there.
  3. Write your own Sprockets postprocessors if you have to rewrite paths to assets.
  4. run rails assets:clobber assets:precompile and resolve all errors.
    Check the generated CSS and JS files in the public folder if all paths were resolved correctly and also use the correct digest.
  5. when there are no errors any more, run rails assets:clobber to remove the precompiled assets again.
  6. adapt your stylesheet_link_tag and javascript_link_tag to match the new pack names.
  7. start the development server with the command bin/dev and check that everything works and looks good.

Finish

  1. remove gems from your Gemfile that are no longer necessary, e.g. sass-rails or uglifier
  2. run your test suite and make sure that all tests succeed.
  3. optional: Make your application show esbuild errors

Tipps for Troubleshooting

Try to check things one at a time. Does esbuild create your packages and move them to the destined folder (yarn build --watch)? If yes, does Sprockets move that file to the public folder (rake assets:precompile and rake assets:clobber)? Are the paths and digests correct?

Judith Roth
Last edit
Judith Roth
License
Source code in this card is licensed under the MIT License.
Posted by Judith Roth to makandra dev (2022-01-25 10:27)