こちらの、Webpacker 3.1対応版です。
ほとんど差分はないですが、上記の記事からの変更点としては
- webpacker 3系の設定ファイルの書き方に対応
- bootstrap v4.0.0-beta.2 に対応
- vue.jsを使った場合のwebpackのresolve.alias周りの設定
- 実際に開発を進めた後のディレクトリ構成の変遷
となってます。上の記事を既に見ている人は、その辺だけ見てもらう形でも問題無かなと思われます。
インストール
Gemfileにwebpackerを追加します。
gem "webpacker", "~> 3.0"
webpackerの設定を追加します。
$ bin/rails webpacker:install
上記コマンドでwebpacker(webpack)の設定とか諸々追加されます。ちょっと特徴的なのがwebpackでコンパイル対象となるディレクトリがapp/javascript/packs
以下のファイル全てがentryになるところでしょうか。
構成
私自身が普段基盤システムやDevOps系のことをやっててフロントエンド周りにそこまで詳しくないので、今回は一旦assets以下の構造をapp/javascript
以下に移行する形でやってみようと思います。
最後の方に、開発が進んでfrontendのスタンダードな構成に寄せていった奴も記載しておきました。
app/javascript
│
├── javascripts
│ ├── application.js
│ ├── ...
│
├── packs
│ └── application.js
│
└── stylesheets
├── application.scss
├── ...
packs/application.js
ではjavascripts/application.js
とstylesheets/application.scss
をimportするだけにして、それぞれをこれまでのsprocketsと同じように管理できるようにしてみます。
import '../javascripts/application';
import '../stylesheets/application';
app/javascript/javascripts
というディレクトリがだいぶアレな感じですが、webpackの設定を変えればいいだけなので一旦動作するところまではそのままでいっちゃいましょう。
起動設定
はじめに、簡単に動作確認できるようにforemanでwebpack-dev-serverを起動する設定をやっておきます。
group :development do
gem "foreman"
#...
end
web: bin/rails s
webpacker: bin/webpack-dev-server
$ bundle install
$ bundle binstubs foreman
これで、 bin/foreman start
で開発用のサーバーが立ち上がります。ただ、foreman経由で起動した場合にRailsのポートが5000になるので、http://localhost:5000 でアクセスしましょう。
Sass
まずはじめにsassをwebpacker管理に移行します。app/assets/stylesheets
ディレクトリ以下のファイルをまるっとapp/javascript/stylesheets
ディレクトリにコピーしちゃいましょう。
次に、webpackのsass-loaderはglobでのimport (@import "layout/*";
みたいな奴) に対応していないので、import-glob-loader
とその設定を追加します。
$ yarn add import-glob-loader
const { environment } = require('@rails/webpacker')
environment.loaders.get('sass').use.push('import-glob-loader')
これで、globでのimportの解決ができるようになります。
次に、app/views/layouts/application.html.haml
に以下の行を追記します。
-# = stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload'
= stylesheet_pack_tag 'application', media: 'all', 'data-turbolinks-track': 'reload'
後はwebpackerのデフォルト設定でsassやpostcssの設定が幾つか含まれているので、gem系のassetsやimage-urlなどのhelperを使ってなければ多分そのまま動きます。
sprokectsのsass helperを使っている場合には このへん を参考に泣きながら修正しましょう。
gemでfont-awesomeやbootstrapを使っている場合には若干の変更が必要です。基本的には対応するnpmパッケージをインストールしてパスを書き換えるだけなので、さくっとやっちゃいましょう。
font-awesome
yarnでパッケージを追加します。
$ yarn add font-awesome
次に、sassでのimportを以下に変更します。
@import "~font-awesome/scss/font-awesome";
ちなみに、gem "font-awesome"
を使ってる場合、fa_icon
などのhelperはそのまま使い続けても問題ないので無理に外す必要は無いです。
bootstrap
yarnでパッケージを追加します。
$ yarn add bootstrap
次に、sassでのimportを以下に変更します。
@import 'bootstrap/scss/bootstrap';
あるいは個別にカスタマイズしているのであれば、
/*!
* Bootstrap v4.0.0-beta (https://getbootstrap.com)
* Copyright 2011-2017 The Bootstrap Authors
* Copyright 2011-2017 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
*/
@import "~bootstrap/scss/functions";
@import "~bootstrap/scss/variables";
@import "~bootstrap/scss/mixins";
@import "~bootstrap/scss/print";
@import "~bootstrap/scss/reboot";
@import "~bootstrap/scss/type";
@import "~bootstrap/scss/images";
@import "~bootstrap/scss/code";
@import "~bootstrap/scss/grid";
@import "~bootstrap/scss/tables";
@import "~bootstrap/scss/forms";
@import "~bootstrap/scss/buttons";
@import "~bootstrap/scss/transitions";
@import "~bootstrap/scss/dropdown";
@import "~bootstrap/scss/button-group";
@import "~bootstrap/scss/input-group";
@import "~bootstrap/scss/custom-forms";
@import "~bootstrap/scss/nav";
@import "~bootstrap/scss/navbar";
@import "~bootstrap/scss/card";
@import "~bootstrap/scss/breadcrumb";
@import "~bootstrap/scss/pagination";
@import "~bootstrap/scss/badge";
@import "~bootstrap/scss/jumbotron";
@import "~bootstrap/scss/alert";
@import "~bootstrap/scss/progress";
@import "~bootstrap/scss/media";
@import "~bootstrap/scss/list-group";
@import "~bootstrap/scss/close";
@import "~bootstrap/scss/modal";
@import "~bootstrap/scss/tooltip";
@import "~bootstrap/scss/popover";
@import "~bootstrap/scss/carousel";
@import "~bootstrap/scss/utilities";
その他のパッケージも同じようなノリで書き換えちゃっていきましょう。
javascript (coffeescript)
javascriptの場合はsprocketsのrequireをes6 styleのimportに書き換える必要があるので、ちょっとづつ移行していきます。coffee-loaderはデフォルトで含まれていないので追加後に、先ずは.coffeeのままコピーしても問題無いです。
$ yarn add coffeescript
// TODO
import './xxxxx.coffee';
import './yyyyy.coffee';
// ...
gem系のassetsに関しても同じようにnpmから同様のバージョンを追加していきます。
bootstrap (+ jQuery)
yarnでパッケージを追加します。
$ yarn add bootstrap # sassの時に追加してたら要らないです
$ yarn add jquery
次に、jsのimportを追加します。
import 'bootstrap';
jQueryに関しては、$
とjQuery
がグローバルにエクスポートされている必要があるので、webpackの設定の方を変更します。
const { environment } = require('@rails/webpacker')
const webpack = require('webpack')
environment.loaders.get('sass').use.push('import-glob-loader')
environment.plugins.set(
'Provide',
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery',
jquery: 'jquery',
})
)
module.exports = environment
Vue.js
私はVueを使っているのですが、vue-cliの import XX from '@/components';
のように @
でパスを解決できるのが結構便利なのでその辺も追加しちゃいましょう。
// ...
// vue-cliっぽく書きたいですよね
environment.config.merge({
resolve: {
alias: {
'@': 'javascripts',
vue: 'vue/dist/vue.js',
}
}
})
// ...
rails-ujs + turbolinks
ただ、以下のライブラリは一旦gemそのままで使うことにしたため、こちらはsprocketsと併用しています。
//= require rails-ujs
//= require turbolinks
どちらもnpmにパッケージがあるので移行すること自体は問題ないですが、rails-ujs
に関してはRailsのバージョン変更の際の考慮漏れになりそうだったのと、turbolinksはredirect_to
に幾つかの処理を追加するような感じになっていたので今回はそのままにすることにしました。ただ、これもそのうち全部移行するかもしれません。
最後に、app/views/layouts/application.html.haml
に以下の行を追記します。
= javascript_include_tag 'application', 'data-turbolinks-track': 'reload'
= javascript_pack_tag 'application', media: 'all', 'data-turbolinks-track': 'reload'
現在の構成
前の記事を書いてから結構開発が進み、vue.jsを使っているということもあってvue-cliによせて今現在はこんな感じになってます。
app/frontend
│
├── packs
│ └── application.js
│
└── src
├── assets
│ ├── images
│ └── stylesheets
├── components
│ └── ...
├── initializers
│ └── ...
├── lib
│ └── ...
├── main.js
├── mixins
│ └── ...
└── store
└── ...
# Note: You must restart bin/webpack-dev-server for changes to take effect
default: &default
source_path: app/frontend
source_entry_path: packs
public_output_path: assets/packs
cache_path: tmp/cache/webpacker
# Additional paths webpack should lookup modules
# ['app/assets', 'engine/foo/app/assets']
resolved_paths: []
# Reload manifest.json on all requests so we reload latest compiled packs
cache_manifest: false
extensions:
- .coffee
- .erb
- .js
- .jsx
- .ts
- .vue
- .sass
- .scss
- .css
- .png
- .svg
- .gif
- .jpeg
- .jpg
development:
<<: *default
compile: true
# Reference: https://webpack.js.org/configuration/dev-server/
dev_server:
https: false
host: localhost
port: 3035
public: localhost:3035
hmr: false
# Inline should be set to true if using HMR
inline: true
overlay: true
compress: true
disable_host_check: true
use_local_ip: false
quiet: false
headers:
'Access-Control-Allow-Origin': '*'
watch_options:
ignored: /node_modules/
test:
<<: *default
compile: true
# Compile test packs to a separate directory
public_output_path: packs-test
production:
<<: *default
# Production depends on precompilation of packs prior to booting for performance.
compile: false
# Cache manifest.json for performance
cache_manifest: true
終わり
前の記事とあまり変わらないですが、webpackerの設定周りは出力されるファイルがガラッと変わっているのでその辺りで結構修正が必要なので頑張ってください