Shakapacker
Official, actively maintained successor to rails/webpacker. Internal naming for shakapacker
will continue to use webpacker
where possible for v6. ShakaCode stands behind the long-term maintainence and development of this project for the Rails community.
- See V6 Upgrade for upgrading from v5 or prior v6 releases.
Webpacker makes it easy to use the JavaScript pre-processor and bundler Webpack v5+ to manage application-like JavaScript in Rails. It can coexist with the asset pipeline, leaving Webpack responsible solely for app-like JavaScript, or it can be used exclusively, making it also responsible for images, fonts, and CSS.
Check out 6.1.1+ for SWC and esbuild-loader support! They are faster than Babel!
See a comparison of webpacker with jsbundling-rails.
Discussion forum and Slack to discuss debugging and troubleshooting tips. Please open issues for bugs and feature requests:
ShakaCode offers support for upgrading from webpacker or using Shakapacker. If interested, contact justin@shakacode.com. ShakaCode is hiring passionate engineers that love open source.
- Prerequisites
- Features
- Installation
- Usage
- View Helpers
- Defer for
javascript_pack_tag
- Server-Side Rendering (SSR)
- Development
- Webpack Configuration
- Babel configuration
- SWC configuration
- esbuild loader configuration
- Integrations
- React
- Typescript
- CoffeeScript
- TypeScript
- CSS
- Postcss
- Sass
- Less
- Stylus
- Other frameworks
- Custom Rails environments
- Upgrading
- Compiler strategies
- Paths
- Additional paths
- Deployment
- Example Apps
- Troubleshooting
- Contributing
- License
Prerequisites
- Ruby 2.6+
- Rails 5.2+
- Node.js 12.13.0+ || 14+
- Yarn
Features
- Rails view helpers that fully support Webpack output, including HMR and code splitting.
- Convenient but not required webpack configuration. The only requirement is that your webpack configuration create a manifest.
- HMR with the webpack-dev-server, such as for hot-reloading React!
- Automatic code splitting using multiple entry points to optimize JavaScript downloads.
- Webpack v5+
- ES6 with babel, SWC, or Esbuild
- Asset compression, source-maps, and minification
- CDN support
- Extensible and configurable. For example, all major dependencies are specified as peers, so you can upgrade easily.
Optional support
Requires extra packages to be installed.
- React
- TypeScript
- Stylesheets - Sass, Less, Stylus and Css, PostCSS
- CoffeeScript
Installation
Rails v6+
With Rails v6+, skip JavaScript for a new app and follow below Manual Installation Steps to manually add the shakapacker
gem to your Gemfile.
rails new myapp --skip-javascript
Note, Rails 6 installs the older v5 version of webpacker unless you specify --skip-javascript
.
Add shakapacker
gem to your Gemfile
:
bundle add shakapacker --strict
Then running the following to install Webpacker:
./bin/bundle install
./bin/rails webpacker:install
When package.json
and/or yarn.lock
changes, such as when pulling down changes to your local environment in a team settings, be sure to keep your NPM packages up-to-date:
yarn
Note, in v6+, most JS packages are peer dependencies. Thus, the installer will add the packages:
yarn add @babel/core @babel/plugin-transform-runtime @babel/preset-env @babel/runtime babel-loader \
compression-webpack-plugin terser-webpack-plugin \
webpack webpack-assets-manifest webpack-cli webpack-merge webpack-sources webpack-dev-server
Previously, these "webpack" and "babel" packages were direct dependencies for webpacker
. By
making these peer dependencies, you have control over the versions used in your webpack and babel configs.
Note for Yarn v2 usage
If you are using Yarn v2 (berry), please note that PnP modules are not supported.
In order to use Shakapacker with Yarn v2, make sure you set nodeLinker: node-modules
in your .yarnrc.yml
file as per the Yarn docs to opt out of Plug'n'Play behaviour.
Concepts
At it's core, Shakapacker's essential functionality is to:
- Provide configuration by a single file used by both Rails view helpers and JavaScript webpack compilation code.
- Provide Rails view helpers, utilizing this configuration file, so that a webpage can load JavaScript, CSS, and other static assets compiled by webpack, supporting bundle splitting, fingerprinting, and HMR.
- Provide a community supported, default webpack compilation that generates the necessary bundles and manifest, using the same configuration file. This compilation can be extended for any needs.
Usage
Configuration and Code
You will need your file system to correspond to the setup of your webpacker.yml
file.
Suppose you have the following configuration:
webacker.yml
default: &default
source_path: app/javascript
source_entry_path: packs
public_root_path: public
public_output_path: packs
nested_entries: false
# And more
And that maps to a directory structure like this:
app/javascript:
└── packs: # sets up webpack entries
│ └── application.js # references ../src/my_component.js
│ └── application.css
└── src: # any directory name is fine. Referenced files need to be under source_path
│ └── my_component.js
└── stylesheets:
│ └── my_styles.css
└── images:
└── logo.svg
public/packs # webpack output
Webpack intelligently includes only necessary files. In this example, the file packs/application.js
would reference ../src/my_component.js
nested_entries
allows you to have webpack entry points nested in subdirectories. This defaults to false so you don't accidentally create entry points for an entire tree of files. In other words, with nested_entries: false
, you can have your entire source_path
used for your source (using the source_entry_path: /
) and you place files at the top level that you want as entry points. nested_entries: true
allows you to have entries that are in subdirectories. This is useful if you have entries that are generated, so you can have a generated
subdirectory and easily separate generated files from the rest of your codebase.
View Helpers
The Shakapacker view helpers generate the script and link tags to get the webpack output onto your views.
Be sure to consult the API documentation in the source code of helper.rb.
Note: In order for your styles or static assets files to be available in your view, you would need to link them in your "pack" or entry file. Otherwise, Webpack won't know to package up those files.
View Helpers javascript_pack_tag
and stylesheet_pack_tag
These view helpers take your webpacker.yml
configuration file, along with the resulting webpack compilation manifest.json
and generates the HTML to load the assets.
You can then link the JavaScript pack in Rails views using the javascript_pack_tag
helper. If you have styles imported in your pack file, you can link them by using stylesheet_pack_tag
:
<%= javascript_pack_tag 'application' %>
<%= stylesheet_pack_tag 'application' %>
The javascript_pack_tag
and stylesheet_pack_tag
helpers will include all the transpiled
packs with the chunks in your view, which creates html tags for all the chunks.
You can provide multiple packs and other attributes. Note, defer
defaults to showing.
<%= javascript_pack_tag 'calendar', 'map', 'data-turbolinks-track': 'reload' %>
The resulting HTML would look like:
<script src="/packs/vendor-16838bab065ae1e314.js" data-turbolinks-track="reload" defer></script>
<script src="/packs/calendar~runtime-16838bab065ae1e314.js" data-turbolinks-track="reload" defer></script>
<script src="/packs/calendar-1016838bab065ae1e314.js" data-turbolinks-track="reload" defer"></script>
<script src="/packs/map~runtime-16838bab065ae1e314.js" data-turbolinks-track="reload" defer></script>
<script src="/packs/map-16838bab065ae1e314.js" data-turbolinks-track="reload" defer></script>
In this output, both the calendar and map codes might refer to other common libraries. Those get placed something like the vendor bundle. The view helper removes any duplication.
Note, the default of "defer" for the javascript_pack_tag
. You can override that to false
. If you expose jquery globally with expose-loader,
by using import $ from "expose-loader?exposes=$,jQuery!jquery"
in your app/javascript/application.js
, pass the option defer: false
to your javascript_pack_tag
.
Important: Pass all your pack names as multiple arguments, not multiple calls, when using javascript_pack_tag
and the stylesheet_pack_tag
. Otherwise, you will get duplicated chunks on the page.
<%# DO %>
<%= javascript_pack_tag 'calendar', 'map' %>
<%# DON'T %>
<%= javascript_pack_tag 'calendar' %>
<%= javascript_pack_tag 'map' %>
While this also generally applies to stylesheet_pack_tag
, you may use multiple calls to stylesheet_pack_tag if, say, you require multiple