Skip to content

Latest commit

 

History

History
312 lines (238 loc) · 8.34 KB

switch_from_webpacker.md

File metadata and controls

312 lines (238 loc) · 8.34 KB

Switch from Webpacker 5 to jsbundling-rails with webpack

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:

  1. HMR
  2. Code splitting

If you rely on these features or you have a complicated webpack setup, consider using shakapacker.

1. Setup jsbundling-rails

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

Move your webpack configuration

If you would like to minimize the diff between Webpacker and jsbundling-rails:

  1. Move ./webpack.config.js into ./config/webpack/
  2. Change the config path in package.json
- "build": "webpack --config ./webpack.config.js"
+ "build": "webpack --config ./config/webpack/webpack.config.js"
  1. Change the output path in webpack.config.js
- path: path.resolve(__dirname, "app/assets/builds"),
+ path: path.resolve(__dirname, '..', '..', 'app/assets/builds')

2. Remove Webpacker

  1. 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
  1. 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?
  1. Remove Webpacker gem
# Remove from your Gemfile
- gem 'webpacker'
  1. Run ./bin/bundle install

3. Install dependencies

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

Optional: Babel

Babel is used to transpile source code to earlier versions of JavaScript.

  1. Install packages
# From the CLI, add babel presets
yarn add @babel/core @babel/preset-env babel-loader
  1. Configure Babel
// In package.json, add
+ "babel": {
+   "presets": ["@babel/preset-env"]
+ }
  1. Use the loader in webpack
// in webpack.config.js, add
module.exports = {
  module: {
    rules: [
+       {
+         test: /\.(js)$/,
+         exclude: /node_modules/,
+         use: ['babel-loader'],
+       },
    ],
  },
};

Example: Babel + React + TypeScript

You can use Babel to transpile front-end frameworks and TypeScript. This example setup uses React with TypeScript.

  1. Install packages
# From the CLI, add babel presets
yarn add @babel/core @babel/preset-env @babel/preset-react @babel/preset-typescript
  1. Configure Babel
// In package.json, add
+ "babel": {
+   "presets": [
+     "@babel/preset-env",
+     "@babel/preset-react",
+     "@babel/preset-typescript"
+   ]
+ }
  1. Configure webpack
// in webpack.config.js, add
module.exports = {
  module: {
    rules: [
+       {
+         test: /\.(js|jsx|ts|tsx|)$/,
+         exclude: /node_modules/,
+         use: ['babel-loader'],
+       },
    ],
  },
};

Optional: CSS + SASS

With the right loaders, webpack can handle CSS files. This setup only uses jsbundling-rails, excluding cssbundling-rails from handling files.

  1. 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
  1. 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(),
  ],
};

Optional: Fonts, Images, SVG

With the right loaders, webpack can handle other files. This setup may vary on your use, but will look something like this:

  1. Install packages
yarn add file-loader
  1. 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',
+       },
    ],
  },
};

Optional: Use webpack to chunk assets so that it works with Sprockets

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,
  }
}

4. Test your build

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.

5. Replace Webpacker pack tags

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!

Optional: Add support for development environment

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',
+  }
}