Masatoshi Nishiguchi

Rails - what to do after installing webpacker

This is my note on how I should set up webpacker.

My Goals

general

js

scss

Dependencies

package.json

{
  "name": "jwt_app",
  "private": true,
  "dependencies": {
    "@babel/preset-react": "^7.0.0",
    "@rails/actioncable": "^6.0.0-alpha",
    "@rails/activestorage": "^6.0.0-alpha",
    "@rails/ujs": "^6.0.0-alpha",
    "@rails/webpacker": "^4.0.2",
    "babel-plugin-transform-react-remove-prop-types": "^0.4.24",
    "bootstrap": "^4.3.1",
    "izitoast": "^1.4.0",
    "jquery": "^3.4.0",
    "prop-types": "^15.7.2",
    "react": "^16.8.6",
    "react-dom": "^16.8.6",
    "react-router-dom": "^5.0.0",
    "react_ujs": "^2.5.0",
    "reactstrap": "^8.0.0",
    "turbolinks": "^5.2.0",
    "webpack-merge": "^4.2.1"
  },
  "version": "0.1.0",
  "devDependencies": {
    "webpack-dev-server": "^3.3.1"
  }
}

Set up webpacker load path

config/webpacker.yml

  resolved_paths: ['app/assets']

Set up outputs in app/views/layouts/application.slim

Add javascript_pack_tag and stylesheet_pack_tag to a layout file

doctype html
html
  head
    /...

    / from asset pipeline
    = stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload'

    / from webpacker
    = stylesheet_pack_tag 'application', media: 'all', 'data-turbolinks-track': 'reload'
    = javascript_pack_tag 'application', 'data-turbolinks-track': 'reload'

    /...

Set up app/assets

$ tree app/assets/
app/assets/
├── config
│   └── manifest.js
├── images
└── stylesheets
    ├── application.scss       # global scss
    └── shared                 # scss shared with webpacker
        └── variables.scss

app/assets/stylesheets/application.scss

@import './shared/variables';

// third-party styles from node_modules
@import 'bootstrap/scss/bootstrap.scss';
@import 'izitoast/dist/css/iziToast';

app/assets/config/manifest.js

//= link_tree ../images
//= link_directory ../stylesheets .css

Set up app/javascript

$ tree app/javascript -I node_modules -L 3
app/javascript
├── channels
│   ├── consumer.js
│   └── index.js
├── components                 # react components
│   ├── ReactApp
│   │   ├── ...
│   │   ├── TopNav.jsx
│   │   └── TopNav.module.scss # *.module.scss extension for activation css modules
│   └── ReactApp.js
├── packs                      # entry points for webpack
│   ├── application.js
│   └── server_rendering.js    # See react-rails docs
└── src                        # custom javascript imported into application.js
    └── index.js

app/javascript/packs/application.js

// Rails scripts
require('@rails/ujs').start();
require('turbolinks').start();
require('@rails/activestorage').start();
require('channels');

// Our custom scripts
require('../src/index.js');

// Support component names relative to this directory:
const componentRequireContext = require.context('components', true);
const ReactRailsUJS = require('react_ujs');

ReactRailsUJS.useContext(componentRequireContext);

app/javascript/src/index.js

// Initialize rails
require('@rails/ujs').start();
require('turbolinks').start();
require('@rails/activestorage').start();
require('channels');

// Initialize react-rails
const componentRequireContext = require.context('components', true);
const ReactRailsUJS = require('react_ujs');
ReactRailsUJS.useContext(componentRequireContext);

// Initialize our js
require('../src/index.js');

// senity check
console.log('Webpacker initialized');

CSS modules

// app/javascript/components/ReactApp/TopNav.module.scss

@import 'stylesheets/shared/variables';

.navbar {
  background-color: $app-theme-color;
}
// app/javascript/components/ReactApp/TopNav.js

//...
import css from './TopNav.module';

const TopNav = () => {
  return (
    <Navbar dark expand="md" className={css.navbar}>

Start app

# run webback server
bin/webpack-dev-server
# run rails server
bin/rails s