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 offical 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.
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
endmodule MyEngine
class Engine < ::Rails::Engine
initializer "webpacker.proxy" do |app|
insert_middleware = begin
MyEngine.webpacker.config.dev_server.present?
rescue
nil
end
next unless insert_middleware
app.middleware.insert_before(
0, Webpacker::DevServerProxy, # "Webpacker::DevServerProxy" if Rails version < 5
ssl_verify_none: true,
webpacker: MyEngine.webpacker
)
end
end
endIf 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"
# ...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 (rake my_engine:webpacker:compile)
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
endThere are two approaches on serving compiled assets.
You can serve engine's assets using the main app's static files server which serves files from public/ folder.
For that you must configure your engine's webpacker to put compiled assets to the app's public/ folder:
# my_engine/config/webpacker.yml
default: &default
# ...
# public_root_path could be used to override the path to `public/` folder
# (relative to the engine root)
public_root_path: ../public
# use a different sub-folder name
public_output_path: my-engine-packsTo serve static assets from the engine's public/ folder you must add a middleware and point it to your engine's webpacker output path:
# application.rb
config.middleware.use(
"Rack::Static",
urls: ["/my-engine-packs"], root: "my_engine/public"
)NOTE: in the example above we assume that your public_output_path is set to my-engine-packs in your engine's webpacker.yml.