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.
First, you create a Rails engine (say, MyEngine). See the official Rails guide.
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.ymlandconfig/webpack/*.jsfiles - Add
bin/webpackandbin/webpack-dev-serverfiles - Add
package.jsonwith required deps.
- 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- 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
endSet 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'
# ...- 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
endNow you can use stylesheet_pack_tag and javascript_pack_tag from within your engine.
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'
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/