執筆時点でWebpackerはRailsにてプロジェクトを開始すると、
app/javascript/packs/
以下のファイルを見にいきます。そして、このディレクトリ以下の認識できる全てのファイルをWebpackのentryとして吐き出します。
本記事ではこのディレクトリ構成を変え、さらにentryとなるファイルを1つにし、複数のファイルを吐き出さないように書き換えてみようと思います。
バージョン情報
- Webpacker 1.2
- Rails 5.1.0
新しいディレクトリ構成
新しい構成ではfrontend
以下にファイルを配置してみます。
frontend
├── entry
├── javascripts
└── stylesheets
Webpackのentryとするのはfrontend/entry/application.js
です。少し違和感のある構成ですが、現状のWebpackerが吐き出すファイルをあまり書き換えないようにするとこうすべきかと思います。
Webpackerの設定ファイルなどを書き換える
次に、Webpackerが生成した設定ファイルを書き換えていきます。
1. paths.yml
を修正する
config/webpack/paths.yml
を書き換えます。
default: &default
config: config/webpack
- entry: packs
+ entry: entry
output: public
manifest: manifest.json
node_modules: node_modules
- source: app/javascript
+ source: frontend
extensions:
- .coffee
- .js
- .jsx
- .ts
- .vue
- .sass
- .scss
- .css
- .png
- .svg
- .gif
- .jpeg
- .jpg
development:
<<: *default
test:
<<: *default
manifest: manifest-test.json
production:
<<: *default
2. shared.js
を書き換える
Webpackerの生成する設定ファイルは、config/webpack/shared.js
を共通ファイルとしてdevelopment環境やproduction環境によって設定を変えています。
今回はshared.js
を書き換えることによって、entryを単一のファイルだけにしてみます。
// Note: You must restart bin/webpack-dev-server for changes to take effect
/* eslint global-require: 0 */
/* eslint import/no-dynamic-require: 0 */
const webpack = require('webpack')
const { basename, dirname, join, relative, resolve } = require('path')
const { sync } = require('glob')
const ExtractTextPlugin = require('extract-text-webpack-plugin')
const ManifestPlugin = require('webpack-manifest-plugin')
const extname = require('path-complete-extname')
const { env, paths, publicPath, loadersDir } = require('./configuration.js')
const extensionGlob = `**/*{${paths.extensions.join(',')}}*`
-const packPaths = sync(join(paths.source, paths.entry, extensionGlob))
module.exports = {
+ entry: {
+ application: resolve(`${paths.source}/${paths.entry}/application.js`)
+ },
- entry: packPaths.reduce(
- (map, entry) => {
- const localMap = map
- const namespace = relative(join(paths.source, paths.entry), dirname(entry))
- localMap[join(namespace, basename(entry, extname(entry)))] = resolve(entry)
- return localMap
- }, {}
- ),
-
output: {
filename: '[name].js',
path: resolve(paths.output, paths.entry),
publicPath
},
module: {
rules: sync(join(loadersDir, '*.js')).map(loader => require(loader))
},
plugins: [
new webpack.EnvironmentPlugin(JSON.parse(JSON.stringify(env))),
new ExtractTextPlugin(env.NODE_ENV === 'production' ? '[name]-[hash].css' : '[name].css'),
new ManifestPlugin({ fileName: paths.manifest, publicPath, writeToFileEmit: true })
],
resolve: {
extensions: paths.extensions,
modules: [
resolve(paths.source),
resolve(paths.node_modules)
]
},
resolveLoader: {
modules: [paths.node_modules]
}
}
これでfrontend/entry/application.js
のみがentryとして読み込まれるようになりました。
3. .gitignore
を修正する
最後に、entryが変わったので.gitignore
を修正します。
# See https://help.github.com/articles/ignoring-files for more about ignoring files.
#
# If you find yourself ignoring temporary files generated by your text editor
# or operating system, you probably want to add a global ignore instead:
# git config --global core.excludesfile '~/.gitignore_global'
# Ignore bundler config.
/.bundle
# Ignore all logfiles and tempfiles.
/log/*
/tmp/*
!/log/.keep
!/tmp/.keep
/node_modules
/yarn-error.log
.byebug_history
+/public/entry
-/public/packs
/node_modules
vendor/bundle
動作確認
それでは動作確認をしてみましょう。以下のファイルを書き換えて表示を確認してみます。
frontend/javascripts/application.js
frontend/stylesheets/application.scss
/* eslint no-console:0 */
// This file is automatically compiled by Webpack, along with any other files
// present in this directory. You're encouraged to place your actual application logic in
// a relevant structure within app/javascript and only use these pack files to reference
// that code so it'll be compiled.
//
// To reference this file, add <%= javascript_pack_tag 'application' %> to the appropriate
// layout file, like app/views/layouts/application.html.erb
import 'stylesheets/application'
import 'javascripts/hello_react.jsx'
console.log('Hello World from Webpacker')
body {
background: red;
}
WebpackerではmoduleのResolvingの設定が書かれているので、相対パスなど気にしなくて良いです。
resolve: {
extensions: paths.extensions,
modules: [
resolve(paths.source),
resolve(paths.node_modules)
]
},
bin/webpack-dev-server
を実行すると、manifestファイルがpuclic/entry
以下に生成されていることが確認できるはずです。
{
"application.css": "http://localhost:8080/entry/application.css",
"application.css.map": "http://localhost:8080/entry/application.css.map",
"application.js": "http://localhost:8080/entry/application.js",
"application.js.map": "http://localhost:8080/entry/application.js.map"
}
あとはjavascript_pack_tag
でjsファイル、stylesheet_pack_tag
でcssファイルを読み込むだけです。
<%= javascript_pack_tag 'application' %>
<%= stylesheet_pack_tag 'application' %>
適当なページを開くと、多分赤くなっていると思います。
さいごに
Webpackerが出た当初と比べると、CSSの読み込みなどがいい感じになっているので、ちょっと書き換えるとより快適になる気がしました。
といっても、もちろん単一ファイルを読み込む設定はこれがベストではないと思うので、もっといい方法があれば教えてください