Webpack
mini-css-extract-pluginを使ってCSSを書き出す
ローダー設定時の注意事項
ローダーは記述順の後ろから前に実行される。
1: sass-loaderでSassをCSSにコンパイル
2: css-loaderでCSSの依存関係を解決
3: mini-css-extract-plugin.loaderでCSSファイルの書き出し
の順番で処理をする場合、記載は下記の通り。
{
test: /\.(sc|c|sa)ss$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader',
'sass-loader',
]
}
画像の適切な置き場所
画像ファイルの置き場所下記2箇所のうち、どこに画像をおくべきかの判断軸を調査した。
- public配下直置き
- public/bundles配下
CSSから呼び出すか否か
public/bundles配下にあるとうことはfile-loaderで画像をモジュールとして扱うように処理をしているという前提がある。
画像ファイルをモジュールとみなすことで、CSS内で画像ファイルを読み込むことができる。
💡CSSから読み込みたい画像ファイル(アイコンなど)はビルドに含める
キャッシュさせたいか否か
public配下においた画像はブラウザによってキャッシュされる。
一方、バンドルに組み込むと同じ名前で違う画像に差し替えた場合でもフィンガープリントが変更されて画像ファイル名に挿入されるので、ブラウザでキャッシュされない。
これにより画像を変更したのにユーザーがキャッシュをクリアしない限り古い画像が表示され続けるという問題を回避できる。
ファイル名にフィンガープリントが入る
public配下は画像のファイル名はそのまま
💡変更が予想されない画像に関してはpublic配下に置いてしまう
devtool
トランスパイル後と前のコードの内容を紐付けしてデバッグしやするための設定。
エラー発生箇所がコードのどこなのかを調べられるようになる。
開発環境でのみ必要なので環境ごとの設定ファイルに記載する。
@webpack.dev.js
module.exports = merge(common, {
mode: 'development',
devtool: 'source-map',
})
@webpack.prod.js
module.exports = merge(common, {
mode: 'production',
devtool: 'none',
})
参考
devtoolでsource-map
を指定してビルドするとoutputフォルダ配下に出力ファイルと同じファイル名で拡張子が.js.mapのファイルが生成される。
"index.js": "/bundles/js/index-fb9d53dd6dee1cacfe01.js",
"index.js.map": "/bundles/js/index-fb9d53dd6dee1cacfe01.js.map"
index.js.map方がソースコードとの対応付けを定義したSourceMap。
Webpackの設定を環境に応じてわける方法
デフォルトの落とし穴
⚠️webpackの設定ファイルはwebpack.config.jsだが、これがなくてもwebpackコマンドは実行できる。
その場合、エントリーポイントは ./src
、アウトプットは./dist
となっている。
デフォルト値を確認するには公式のこのページを参照する。
※webpack.config.jsがなくてもwebpackが実行できてしまうため、webpackの設定ファイルをいじっていて内容が反映されていない時、そもそも設定ファイルの置き場所が間違っていないかも確認しよう
※いきなり環境に応じて設定ファイルを作成した時、設定ファイルが読み込まれてないとデフォルトの値でwebpackが実行できてしまうので設定ファイルが読み込まれているかの確認は別途必要
webpack-merge
webpack-mergeを使う
例) @webpack.dev.js
const { merge } = require('webpack-merge')
const common = require('./common.js')
process.env.NODE_ENV = 'development'
module.exports = merge(common, {
mode: 'development',
// 上書きしたい設定
})
公式では共通のものと環境ごとの設定ファイルを下記のようなファイル名で作成すると記載がある。
|- webpack.common.js
|- webpack.dev.js
|- webpack.prod.js
webpackディレクトリを作成して下記のようにしてもOK
|- /webpack
|- common.js
|- development.js
|- production.js
こちらの方が個人的には好き
webpack.config.js以外を設定ファイルとして読み込ませる場合は--config
オプションでファイルを指定する。
"scripts": {
"dev": "webpack --config webpack/develop.js",
"build": "webpack --config webpack/production.js"
},
ビルドエラー: TyepScript emitted no output for ...images.d.ts.
原因
declareファイルがビルド対象のディレクトリ配下にあったため
解消
|- /app
|-javascript
|- entries
|- types
entryファイルをapp/javascript
配下 -> app/javascript/entries
配下に変更
Webpack + Vue のプロジェクトを作成するログ
必要なパッケージを取得
$ yarn init
$ yarn add -D webpack webpack/cli @webpack-cli/init ebpack-dev-server
❓webpack/cli
と @webpack-cli/init
の違い
設定ファイル作成
$ npx webpack-cli init
対話形式に答えるとwebpack.config.jp
がルート直下に作成される。
この時Yeomanの設定ファイルである .yo-rc.json
も作成される。
❓Yeomanとは
一旦削除して問題ないので削除
webpack-dev-serverを設定
$ yarn add -D webpack-dev-server
@package.json
"scripts": {
"start:dev": "webpack serve --open"
},
@webpack.config.js
devServer: {
contentBase: path.join(__dirname, 'dist'),
compress: true,
port: 8000
},
index.htmlを表示させる
アウトプットディレクトリ直下にindex.htmlを作成
@webpack.config.js
devServer: {
openPage: "index.html", <= 追加
}
=> yarn run start:dev
実行で http://localhost:8000/index.html
が開きHtmlの内容が表示されている
Vueのコンポーネントを呼び出す
1: Vueのパッケージを取得
$ yarn add vue
2: index.htmlで読み込むjsファイルにVueのインスタンスを記述
@index.js
import Vue from "vue";
new Vue({
el: '#app',
data: {
message: 'Hello Vue!'
}
})
@index.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>Webpack Playground</title>
</head>
<body>
<h1>Webpack Playground</h1>
<div id="app">
{{ message }}
</div>
<script src="./index.js"></script>
</body>
</html>
3: resolve.aliasを設定
`webpack.config.js
resolve: {
alias: {
'vue$': 'vue/dist/vue.esm.js',
}
},
💡resolve.alias
import、もしくはrequireで指定するファイル(ライブラリ)名のエイリアスを作成するための設定
4: vue-loaderを設定する
$ yarn add -D vue-loader vue-template-compiler
最初vue-loader
のみインストールしてビルドしたところ下記エラーが出たためvue-template-compiler
も追加した。
vue-template-compiler must be installed as a peer dependency, or a compatible compiler implementation must be passed via options
Vueのテンプレート機能をプリコンパイルするために必要な様子。
@webpack.config.js
const { VueLoaderPlugin } = require('vue-loader');
plugins: [
new VueLoaderPlugin()
],
module: {
rules: [{
test: /\.vue$/,
loader: 'vue-loader'
},
vue-loaderを使うためにはpluginとして追加してあげる必要がある。
さらにルールに拡張子が .vue
のファイルに対してloaderを適用するように追記する。
TypeScriptに対応させる
1: TypeScriptのパッケージを取得
$ yarn add typescript ts-loader
2:ts-loaderの設定を追加
moduleのrulesにts-loaderを追加。
Vueファイルでtsを使用したい場合はappendTsSuffixTo
が必要。
module: {
rules: [{
test: /\.vue$/,
loader: 'vue-loader'
}, {
test: /\.ts$/,
use: [
{
loader: 'ts-loader',
options: {
// .vueファイルをtsとして監視するように追加
appendTsSuffixTo: [/\.vue$/],
}
}
]
},
3: tsconfig.jsonの設定
下記コマンドを使うと compilerOptions
についてのコメントが記載されたファイルが生成される。
$ /node_modules/.bin/tsc --init
// npxがあれば
$ npx typescript --init
生成されたtsの設定ファイルに追記。
TypeScriptを採用する対象ファイルをinclude
に記載する。
exclude
にnode_modules
も。
"include": [
"src/**/*.ts",
"src/**/*.vue",
],
"exclude": [
"node_modules"
]
このままだと下記のようなエラーが出力される。
ERROR
TS18003: No inputs were found in config file 'tsconfig.json'. Specified 'include' paths were '["src/**/*.ts","src/**/*.vue"]' and 'exclude' paths were '["node_modules"]'.
これを回避するためには vue.d.ts
という型定義ファイルを作成してincludes配下に設置する必要がある。
/* eslint-disable */
declare module '*.vue' {
import type { DefineComponent } from 'vue'
const component: DefineComponent<{}, {}, any>
export default component
}
この型定義ファイルがないとVueをimportできず、tsの対象ファイルが1つもないということでエラーになってしまう。
これでvueファイルのscriptのlang属性にtsと書いてもコンパイルが通るようになっている。
※ TSに対応させるためにはVue.component または Vue.extend でコンポーネントを定義する。
参考