最近フロントエンド開発する際、必ずバックエンドとは別途に
エコシステムを導入していて、その中で依存関係解決のために
webpackを採用しています。
ただ、使いたいモジュール在り来でwebpackを採用しただけで、
細かいオプション等を理解できていなかったのでまとめることにしました。
きっかけになったのはElectronでアプリ開発したとき、
今まで使ってたテンプレだけだと動かなかったので。
書いてみてわかったのが、ほとんど公式のドキュメントの一部を
まとめただけになっちゃったかも。
webpackはそもそも何をしてくれるものなのか
依存関係にあるアセットやモジュールをバンドルして出力してくれるもの。
説明をわかりやすく、とりあえずJavaScriptのみで書きますが
CSS(Sassなど含む)や画像ファイルとかもバンドルできます。
CommonJSで書いたものを、ブラウザで動くようにしてくれる、と
とりあえずざっくりそういうもの。
(後述するloaderによってCommonJS以外にも対応可能)
webpack理解の基本
上記の参考リンクにもあるように、以下の4つのコアとなるコンセプトが存在します。
後ほど、それぞれを掘り下げたいと思います。
ここではざっくりと。
1. Entry
バンドルしたいアプリケーションやソースコードのエントリポイントを指定する。
(Javaでいうpublic static void main(String[] args)
みたいな)
Entryは単一(String)でも複数(Object)でも指定することができます。
単一エントリ
1 2 3 4 |
const config = { entry: './path/to/entry/entry.js' } |
複数エントリ
1 2 3 4 5 6 7 |
const config = { entry: { page1: './path/to/entry/page1.js', page2: './path/to/entry/page2.js' } } |
2. Output
Entryで指定したエントリポイントからグラフを作成し、依存関係を解決し、バンドルした
ソースコードをどこに出力するか、を指定する。
最低限必要な項目は2項目でfilename
とpath
1 2 3 4 5 6 7 |
const config = { output: { filename: 'bundle.js', path: '/home/proj/public/assets' } }; |
複数のエントリポイントがあった場合はこれだと全部bundle.js
に
なってしまうので、それに対応できるようにします。
1 2 3 4 5 6 7 8 9 10 11 |
{ entry: { app: './src/app.js', search: './src/search.js' }, output: { filename: '[name].js', path: __dirname + '/dist' } } |
filename
に[name]
とあるように、特別な値(この例ではオブジェクトのキー)
を代入させることができます。
利用できる値はこちらで確認できます。
3. Loaders
さきほど、CSSやHTML、画像ファイルもアセットとしてバンドルできると書きましたが、
Webpack単体ではJavascriptしかバンドルできません。
そこで、loaderという、専用のライブラリを用いることで、jsだけでなく、関連ファイルを
バンドルできるようにします。
ここではどのファイル
にどのloader
を使用するか、を指定できます。
※CommonJSのみを、ブラウザで実行するだけであれば設定不要です。
ReactのJSX
やVueの.vue
、stylusのコンパイルなども可能です。
例えばCommonJSじゃなくてTypeScriptで書きたいとか、React使ってるなら
JSX使う、とか、そういうときに設定が必要になります。
必要なライブラリを予めインストールしておきましょう。
TypeScriptであれば以下。
1 2 |
$ npm install --save-dev ts-loader |
そのあと設定ファイルに
1 2 3 4 5 6 7 8 |
module.exports = { module: { rules: [ { test: /\.ts$/, use: 'ts-loader' } ] } } |
ここで注意なのが、上記の書き方はWebpack2.x以上のものになります。
古いバージョンに対応した書き方はドキュメントを参照してください
(使ってるのが1.x系だったのを気づかず、この書き方で設定していて、動かずはまった)
と書けばOKです。
.ts
で終わるファイルに対してはts-loader
を利用して
バンドルを行う、という内容になってます。
その他、import
時に指定したり、コマンドラインからも指定する
方法もありますが、ここでは省略します。
(参考リンクに書いてあります)
loaderによっては項目が異なるので、掘り下げませんが、option
という
オブジェクトを渡すことで細かい設定も可能です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
module.exports = { module: { rules: [ { test: /\.ts$/, use: 'ts-loader', option: { //設定いろいろここに書く } } ] } } |
PluginによってLoaderの機能を拡張することも可能みたいです。
4. Plugins
Loaderはファイルの変換を行うものでしたが、Pluginsは、それ以外のWebpackのプラグイン
を指します。(Loaderを拡張するものも、ここに含まれます。)
例えば簡易Webサーバを立ち上げたり、ホットリロードに対応したり、ですね。
今回はここは、あんまり深く書かないかも。
よく見かけるけど雰囲気で使ってる設定項目
ここが本題。自分でスクラッチでも細かく設定できるように、今まで「なにこれ」
ってなってきたものをまとめる。
1. module.rules.(exclude|include)の設定
その名前の通り、loaderがエントリポイントから依存関係を解決する際に
ロード対象を含む(include)か除外(exclude)するディレクトリを指定する
オプション。
babel-loaderのREADMEにある
サンプルだとnode_modules
とbower_components
がexcludeに指定されていますね。
2. sourcemapも一緒に出力したい
一行追加するだけ!かんたん!
1 2 3 4 |
module.exports = { devtool: 'source-map', } |
Webpack devtool この辺が設定可能みたい。
3. minifyしたい
webpackが標準でminifyのプラグインを提供してくれています
plugins
に以下の設定を追加するだけ。
1 2 3 4 5 6 7 8 9 10 |
var webpack = require('webpack') module.exports = { /* 設定いろいろ書く */ plugins: [ new webpack.optimize.UglifyJsPlugin() ] } |
4. 静的ファイル(例えば画像とかHTMLとか)のリンクをいい感じにしたい
outputs.publicPath
の設定をすることで、リンク先を解決して変換してくれます。
1 2 3 4 5 6 7 8 |
module.exports = { output: { path: __dirname + '/assets/', filename: '[name].bundle.js', publicPath: "/files/" } } |
こんな感じで設定されてる前提で、例えば下記のHTMLをimport
したとします。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title></title> </head> <body> <div class=""> <img src="./hoge.png" alt=""> </div> </body> </html> |
そうすると、Webpackでバンドルされた後は、img
タグのsrc
は
/files/hoge.png
と変換されて出力されます。
5. VueのProduction環境でのビルドをしたい
これも公式にある通りに設定するだけで上手くいきます。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
var webpack = require('webpack') module.exports = { // ... plugins: [ // ... new webpack.DefinePlugin({ 'process.env': { NODE_ENV: '"production"' } }) ] } |
他にもネタたくさんありそうだから、追記していこうかな。
とりあえずここで公開