This guide provides step-by-step instructions to migration from Webpacker 5
to jsbundling-rails
with webpack 4
. For upgrading to Webpacker/Shakapacker v6 instead, follow this guide or for comparison between Webpacker and jsbundling-rails, see this.
Note, you will no longer have the following features of webpacker
if you migrate to jsbundling-rails
:
If you rely on these features or you have a complicated webpack setup, consider using shakapacker
.
First install jsbundling-rails
:
# Add to your Gemfile
+ gem 'jsbundling-rails'
# From the CLI, rebuild the bundle
./bin/bundle install
# From the CLI, create a baseline configuration
./bin/rails javascript:install:webpack
The installation script will:
- Add builds to the manifest
- Ignore builds from git
- Setup
foreman
for running multiple processes - Create
./webpack.config.js
- Add the build script to
package.json
If you would like to minimize the diff between Webpacker and jsbundling-rails:
- Move
./webpack.config.js
into./config/webpack/
- Change the config path in
package.json
- "build": "webpack --config ./webpack.config.js"
+ "build": "webpack --config ./config/webpack/webpack.config.js"
- Change the output path in
webpack.config.js
- path: path.resolve(__dirname, "app/assets/builds"),
+ path: path.resolve(__dirname, '..', '..', 'app/assets/builds')
- Delete the following files, ensuring that you've migrated any customizations you've done in them:
./bin/webpack
./bin/webpack-dev-server
./config/initializers/webpacker.rb
./config/webpacker.yml
./config/webpack/development.js
./config/webpack/environment.js
./config/webpack/production.js
./config/webpack/test.js
- Remove Webpacker configs
# Remove from your config/initializers/assets.rb
-# Add Yarn node_modules folder to the asset load path.
-Rails.application.config.assets.paths << Rails.root.join('node_modules')
# Remove from your config/initializers/content_security_policy.rb
-# # If you are using webpack-dev-server then specify webpack-dev-server host
-# policy.connect_src :self, :https, "http://localhost:3035", "ws://localhost:3035" if Rails.env.development?
- Remove Webpacker gem
# Remove from your Gemfile
- gem 'webpacker'
- Run
./bin/bundle install
Webpacker includes many dependencies by default while jsbundling-rails leaves it to you. If you're only handling JavaScript with no modifications you don't need to install additional packages. Treat the rest of this section ala-carte.
# From the CLI, remove Webpacker packages
yarn remove @rails/webpacker webpack-dev-server
Babel is used to transpile source code to earlier versions of JavaScript.
- Install packages
# From the CLI, add babel presets
yarn add @babel/core @babel/preset-env babel-loader
- Configure Babel
// In package.json, add
+ "babel": {
+ "presets": ["@babel/preset-env"]
+ }
- Use the loader in webpack
// in webpack.config.js, add
module.exports = {
module: {
rules: [
+ {
+ test: /\.(js)$/,
+ exclude: /node_modules/,
+ use: ['babel-loader'],
+ },
],
},
};
You can use Babel to transpile front-end frameworks and TypeScript. This example setup uses React with TypeScript.
- Install packages
# From the CLI, add babel presets
yarn add @babel/core @babel/preset-env @babel/preset-react @babel/preset-typescript
- Configure Babel
// In package.json, add
+ "babel": {
+ "presets": [
+ "@babel/preset-env",
+ "@babel/preset-react",
+ "@babel/preset-typescript"
+ ]
+ }
- Configure webpack
// in webpack.config.js, add
module.exports = {
module: {
rules: [
+ {
+ test: /\.(js|jsx|ts|tsx|)$/,
+ exclude: /node_modules/,
+ use: ['babel-loader'],
+ },
],
},
};
With the right loaders, webpack can handle CSS files. This setup only uses jsbundling-rails, excluding cssbundling-rails from handling files.
- Install packages
# From the CLI, add loaders, plugins, and node sass
yarn add css-loader sass sass-loader mini-css-extract-plugin webpack-remove-empty-scripts
- Configure webpack
// In webpack.config.js
// Extracts CSS into .css file
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
// Removes exported JavaScript files from CSS-only entries
// in this example, entry.custom will create a corresponding empty custom.js file
const RemoveEmptyScriptsPlugin = require('webpack-remove-empty-scripts');
module.exports = {
entry: {
// add your css or sass entries
application: [
'./app/assets/javascripts/application.js',
'./app/assets/stylesheets/application.scss',
],
custom: './app/assets/stylesheets/custom.scss',
},
module: {
rules: [
// Add CSS/SASS/SCSS rule with loaders
{
test: /\.(?:sa|sc|c)ss$/i,
use: [MiniCssExtractPlugin.loader, 'css-loader', 'sass-loader'],
},
],
},
resolve: {
// Add additional file types
extensions: ['.js', '.jsx', '.scss', '.css'],
},
plugins: [
// Include plugins
new RemoveEmptyScriptsPlugin(),
new MiniCssExtractPlugin(),
],
};
With the right loaders, webpack can handle other files. This setup may vary on your use, but will look something like this:
- Install packages
yarn add file-loader
- Configure webpack
// in webpack.config.js, add
module.exports = {
module: {
rules: [
+ {
+ test: /\.(png|jpe?g|gif|eot|woff2|woff|ttf|svg)$/i,
+ use: 'file-loader',
+ },
],
},
};
Sprockets was updated to detect that an asset has already been fingerprinted and won't fingerprint it again. This allows webpack to do code splitting while ensuring all assets have cache busting fingerprints and can be stored on a CDN. This config allows Sprockets to fingerprint the entrypoint file so that javascript_include_tag
can load that asset by name.
// in webpack.config.js, add
module.exports = {
output: {
filename: "[name].js",
chunkFilename: "[name]-[contenthash].digested.js",
sourceMapFilename: "[file]-[fullhash].map",
path: path.resolve(__dirname, '..', '..', 'app/assets/builds'),
hashFunction: "sha256",
hashDigestLength: 64,
}
}
Confirm you have a working webpack configuration. You can rebuild the bundle with:
yarn build --progress --color
If you have multiple entries, it's recommended to confirm one at a time, and finally the entire bundle.
Find + replace uses of Webpacker
's asset tags.
# Webpacker tag # Sprockets tag
javascript_pack_tag = javascript_include_tag
stylesheet_pack_tag = stylesheet_link_tag
Once the tags are replaced your app should be working same as before!
jsbundling-rails
ships with only production
mode. You can dramatically speed up build times during development by switching to mode: 'development'
.
// Make the following changes in webpack.config.js
+ const mode = process.env.NODE_ENV === 'development' ? 'development' : 'production';
module.exports = {
- mode: "production",
+ mode,
- devtool: "source-map",
…
+ optimization: {
+ moduleIds: 'deterministic',
+ }
}