Skip to content

Instantly share code, notes, and snippets.

@pioz
Created August 29, 2019 14:48
Show Gist options
  • Save pioz/805d0887ebfdde6322c4db4b46b0120f to your computer and use it in GitHub Desktop.
Save pioz/805d0887ebfdde6322c4db4b46b0120f to your computer and use it in GitHub Desktop.
Using webpacker inside a Rails engine

Using in Rails engines

If the application UI consists of multiple frontend application, you'd probably like to isolate their building too (e.g. if you use different frameworks/versions). Hence we needed our webpack(-er) to be isolated too: separate package.json, dev server, compilation process.

You can do this by adding another Webpacker instance to your application.

This guide describes how to do that using Rails engines.

Step 1: create Rails engine.

First, you create a Rails engine (say, MyEngine). See the official Rails guide.

Step 2: install Webpacker within the engine.

There is no built-in tasks to install Webpacker within the engine, thus you have to add all the require files manually (you can copy them from the main app):

  • Add config/webpacker.yml and config/webpack/*.js files
  • Add bin/webpack and bin/webpack-dev-server files
  • Add package.json with required deps.

Step 3: configure Webpacker instance.

  • File lib/my_engine.rb
module MyEngine
  ROOT_PATH = Pathname.new(File.join(__dir__, '..'))

  class << self
    def webpacker
      @webpacker ||= ::Webpacker::Instance.new(
        root_path: ROOT_PATH,
        config_path: ROOT_PATH.join('config/webpacker.yml')
      )
    end
  end
end

Step 4: Configure dev server proxy.

  • File lib/my_engine/engine.rb
module MyEngine
  class Engine < ::Rails::Engine
    initializer 'webpacker.proxy' do |app|
      insert_middleware = MyEngine.webpacker.config.dev_server.present? rescue nil
      next unless insert_middleware

      app.middleware.insert_before(
        0, Webpacker::DevServerProxy, # 'Webpacker::DevServerProxy' if Rails version < 5
        ssl_verify_none: true,
        webpacker: MyEngine.webpacker
      )

      app.middleware.insert_before(
        0, Rack::Static,
        urls: ['/my-engine-packs'], root: MyEngine::Engine.root.join('public').to_s
      )
    end
  end
end

Set public_output_path to my-engine-packs in engine's webpacker.yml:

# my_engine/config/webpacker.yml
default: &default
  # ...
  # use a different sub-folder name
  public_output_path: my-engine-packs
  # ...

If you have multiple webpackers, you would probably want to run multiple dev servers at a time, and hence be able to configure their setting through env vars (e.g. within a docker-compose.yml file):

# webpacker.yml
# ...
development:
  # ...
  dev_server:
    env_prefix: 'MY_ENGINE_WEBPACKER_DEV_SERVER'
    # ...

Step 5: configure helper.

  • File app/helpers/my_engine/application_helper.rb
require 'webpacker/helper'

module MyEngine
  module ApplicationHelper
    include ::Webpacker::Helper

    def current_webpacker_instance
      MyEngine.webpacker
    end
  end
end

Now you can use stylesheet_pack_tag and javascript_pack_tag from within your engine.

Step 6: rake tasks.

Add Rake task to compile assets in production (rails my_engine:webpacker:compile)

  • File lib/tasks/my_engine_tasks.rake
namespace :my_engine do
  namespace :webpacker do
    desc 'Install deps with yarn'
    task :yarn_install do
      Dir.chdir(File.join(__dir__, '..', '..')) do
        system "yarn install --no-progress --production"
      end
    end

    desc "Compile JavaScript packs using webpack for production with digests"
    task compile: [:yarn_install, :environment] do
      Webpacker.with_node_env("production") do
          if MyEngine.webpacker.commands.compile
            # Successful compilation!
          else
            # Failed compilation
            exit!
          end
      end
    end
  end
end
  • At the end of engine's Rakefile add the line load 'lib/tasks/my_engine_tasks.rake'

Step 7: compile assets.

Compile engine assets with

RAILS_ENV=production rails my_engine:webpacker:compile

You should find compile assets under the directory my_engine/public/my-engine-packs/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment