/webpacker

Use Webpack to manage app-like JavaScript modules in Rails

Primary LanguageRubyMIT LicenseMIT

Webpacker

travis-ci status node.js Gem

Webpacker makes it easy to use the JavaScript pre-processor and bundler webpack 3.x.x+ to manage application-like JavaScript in Rails. It coexists with the asset pipeline, as the primary purpose for webpack is app-like JavaScript, not images, CSS, or even JavaScript Sprinkles (that all continues to live in app/assets).

However, it is possible to use Webpacker for CSS, images and fonts assets as well, in which case you may not even need the asset pipeline. This is mostly relevant when exclusively using component-based JavaScript frameworks.

Table of Contents

Prerequisites

  • Ruby 2.2+
  • Rails 4.2+
  • Node.js 6.0.0+
  • Yarn 0.25.2+

Features

  • webpack 3.x.x
  • ES6 with babel
  • Automatic code splitting using multiple entry points
  • Stylesheets - Sass and CSS
  • Images and fonts
  • PostCSS - Auto-Prefixer
  • Asset compression, source-maps, and minification
  • CDN support
  • React, Angular, Elm and Vue support out-of-the-box
  • Rails view helpers
  • Extensible and configurable

Installation

You can either add Webpacker during setup of a new Rails 5.1+ application using new --webpack option:

# Available Rails 5.1+
rails new myapp --webpack

Or add it to your Gemfile:

# Gemfile
gem 'webpacker', '~> 3.0'

# OR if you prefer to use master
gem 'webpacker', git: 'https://github.com/rails/webpacker.git'

and finally, run following to install Webpacker:

bundle
bundle exec rails webpacker:install

# OR (on rails version < 5.0)
bundle exec rake webpacker:install

Usage

Once installed you can start writing modern ES6-flavored JavaScript app today:

app/javascript:
  ├── packs:
  │   # only webpack entry files here
  │   └── application.js
  └── src:
  │   └── application.css
  └── images:
      └── logo.svg

You can then link the JavaScript pack in Rails view using javascript_pack_tag helper. If you have styles imported in your pack file, you can link using stylesheet_pack_tag:

<%= javascript_pack_tag 'application' %>
<%= stylesheet_pack_tag 'application' %>

If you want to link a static asset for <link rel="prefetch"> or <img /> tag, you can use asset_pack_path helper:

<link rel="prefetch" href="<%= asset_pack_path 'application.css' %>" />
<img src="<%= asset_pack_path 'images/logo.svg' %>" />

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.

Development

Webpacker ships with two binstubs: ./bin/webpack and ./bin/webpack-dev-server. Both are thin wrappers around the standard webpack.js and webpack-dev-server.js executable to ensure that the right configuration file and environment variables are loaded depending on your environment.

In development, Webpacker compiles on demand rather than upfront by default. This happens when you refer to any of the pack assets using the Webpacker helper methods. That means you don't have to run any separate process. Compilation errors are logged to the standard Rails log.

If you want to use live code reloading, or you have enough JavaScript that on-demand compilation is too slow, you'll need to run ./bin/webpack-dev-server or ruby ./bin/webpack-dev-server if on windows, in a separate terminal from bundle exec rails s. This process will watch for changes in the app/javascript/packs/*.js files and automatically reload the browser to match.

# webpack dev server
./bin/webpack-dev-server

# watcher
./bin/webpack --colors --progress

# standalone build
./bin/webpack

Once you start this development server, Webpacker will automatically start proxying all webpack asset requests to this server. When you stop the server, it'll revert to on-demand compilation again.

You can use environment variables as options supported by webpack-dev-server in the form WEBPACKER_DEV_SERVER_<OPTION>. Please note that these environment variables will always take precedence over the ones already set in the configuration file, and that the same environment variables must be available to the rails server process.

WEBPACKER_DEV_SERVER_HOST=example.com WEBPACKER_DEV_SERVER_INLINE=true WEBPACKER_DEV_SERVER_HOT=false ./bin/webpack-dev-server

By default, webpack dev server listens on localhost in development for security but if you want your app to be available over local LAN IP or VM instance like vagrant you can set the host when running ./bin/webpack-dev-server binstub:

WEBPACKER_DEV_SERVER_HOST=0.0.0.0 ./bin/webpack-dev-server

Note: You need to allow webpack-dev-server host as allowed origin for connect-src if you are running your application in a restrict CSP environment like Rails 5.2+. This can be done in Rails 5.2+ for development environment in the CSP initializer config/initializers/content_security_policy.rb with a snippet like this:

  p.connect_src :self, :https, 'http://localhost:3035', 'ws://localhost:3035' if Rails.env.development?

Note: Don't forget to prefix ruby when running these binstubs on windows

webpack configuration

See docs/webpack for modifying webpack configuration and loaders.

Upgrading

You can run following commands to upgrade Webpacker to the latest stable version, this involves upgrading the gem and related npm modules:

bundle update webpacker
yarn upgrade @rails/webpacker --latest
yarn upgrade webpack-dev-server --latest

Yarn Integrity

By default in development, webpacker runs a yarn integrity check to ensure that all local npm packages are up-to-date. This is similar to what bundler does currently in Rails, but for JavaScript packages. If your system is out of date, then Rails will not initialize and you will be asked to upgrade your local npm packages by running yarn install.

To turn off this option, you will need to override the default by adding a new config options to your Rails development environment configuration file (config/environment/development.rb):

config.webpacker.check_yarn_integrity = false

You may also turn on this option by adding the config option to any Rails environment configuration file:

config.webpacker.check_yarn_integrity = true

Integrations

Webpacker ships with basic out-of-the-box integration for React, Angular, Vue and Elm. You can see a list of available commands/tasks by running bundle exec rails webpacker:

React

To use Webpacker with React, create a new Rails 5.1+ app using --webpack=react option:

# Rails 5.1+
rails new myapp --webpack=react

(or run bundle exec rails webpacker:install:react in a existing Rails app already setup with Webpacker).

The installer will add all relevant dependencies using Yarn, any changes to the configuration files and an example React component to your project in app/javascript/packs so that you can experiment with React right away.

Angular with TypeScript

To use Webpacker with Angular, create a new Rails 5.1+ app using --webpack=angular option:

# Rails 5.1+
rails new myapp --webpack=angular

(or run bundle exec rails webpacker:install:angular on a Rails app already setup with Webpacker).

The installer will add TypeScript and Angular core libraries using Yarn plus any changes to the configuration files. An example component is written in TypeScript will also be added to your project in app/javascript so that you can experiment with Angular right away.

By default Angular uses a JIT compiler for development environment, this compiler is not compatible with restrictive CSP (Content Security Policy) environments like Rails 5.2+. You can use Angular AOT compiler in development with the @ngtools/webpack plugin.

Alternatively if you're using Rails 5.2+ you can enable unsafe-eval rule for development environment, this can be done in the config/initializers/content_security_policy.rb with the following configuration:

  if Rails.env.development?
    p.script_src :self, :https, :unsafe_eval
  else
    p.script_src :self, :https
  end

Vue

To use Webpacker with Vue, create a new Rails 5.1+ app using --webpack=vue option:

# Rails 5.1+
rails new myapp --webpack=vue

(or run bundle exec rails webpacker:install:vue on a Rails app already setup with Webpacker).

The installer will add Vue and required libraries using Yarn plus any changes to the configuration files. An example component will also be added to your project in app/javascript so that you can experiment Vue right away.

If you're using Rails 5.2+ you need to enable unsafe-eval rule for development environment, this can be done in the config/initializers/content_security_policy.rb with the following configuration:

  if Rails.env.development?
    p.script_src :self, :https, :unsafe_eval
  else
    p.script_src :self, :https
  end

You can read more about this in the Vue docs.

Elm

To use Webpacker with Elm, create a new Rails 5.1+ app using --webpack=elm option:

# Rails 5.1+
rails new myapp --webpack=elm

(or run bundle exec rails webpacker:install:elm on a Rails app already setup with Webpacker).

The Elm library and core packages will be added via Yarn and Elm itself. An example Main.elm app will also be added to your project in app/javascript so that you can experiment with Elm right away.

Coffeescript

To add Coffeescript support, run bundle exec rails webpacker:install:coffee on a Rails app already setup with Webpacker.

An example hello_coffee.coffee file will also be added to your project in app/javascript/packs so that you can experiment with Coffeescript right away.

Erb

To add Erb support in your JS templates, run bundle exec rails webpacker:install:erb on a Rails app already setup with Webpacker.

An example hello_erb.js.erb file will also be added to your project in app/javascript/packs so that you can experiment with Erb flavoured javascript right away.

Paths

By default, Webpacker ships with simple conventions for where the JavaScript app files and compiled webpack bundles will go in your Rails app, but all these options are configurable from config/webpacker.yml file.

The configuration for what webpack is supposed to compile by default rests on the convention that every file in app/javascript/packs/*(default) or whatever path you set for source_entry_path in the webpacker.yml configuration is turned into their own output files (or entry points, as webpack calls it). Therefore you don't want to put anything inside packs directory that you do not want to be an entry file. As a rule of thumb, put all files you want to link in your views inside "packs" directory and keep everything else under app/javascript.

Suppose you want to change the source directory from app/javascript to frontend and output to assets/packs. This is how you would do it:

# config/webpacker.yml
source_path: frontend
source_entry_path: packs
public_output_path: assets/packs # outputs to => public/assets/packs

Similarly you can also control and configure webpack-dev-server settings from config/webpacker.yml file:

# config/webpacker.yml
development:
  dev_server:
    host: localhost
    port: 3035

If you have hmr turned to true, then the stylesheet_pack_tag generates no output, as you will want to configure your styles to be inlined in your JavaScript for hot reloading. During production and testing, the stylesheet_pack_tag will create the appropriate HTML tags.

Resolved

If you are adding Webpacker to an existing app that has most of the assets inside app/assets or inside an engine and you want to share that with webpack modules then you can use resolved_paths option available in config/webpacker.yml, which lets you add additional paths webpack should lookup when resolving modules:

resolved_paths: ['app/assets']

You can then import them inside your modules like so:

// Note it's relative to parent directory i.e. app/assets
import 'stylesheets/main'
import 'images/rails.png'

Note: Please be careful when adding paths here otherwise it will make the compilation slow, consider adding specific paths instead of whole parent directory if you just need to reference one or two modules

Watched

By default, the lazy compilation is cached until a file is changed under tracked paths. You can configure the paths tracked by adding new paths to watched_paths array, much like Rails autoload_paths:

# config/initializers/webpacker.rb
# or config/application.rb
Webpacker::Compiler.watched_paths << 'bower_components'

Deployment

Webpacker hooks up a new webpacker:compile task to assets:precompile, which gets run whenever you run assets:precompile. If you are not using Sprockets webpacker:compile is automatically aliased to assets:precompile. Remember to set NODE_ENV environment variable to production during deployment or when running the rake task.

Docs

You can find more detailed guides under docs.

License

Webpacker is released under the MIT License.