webpack + jQuery
自分用メモ
webpackはモジュールバンドラー
エントリーポイントに設定したjsファイルを中心に、各モジュールのjsファイルを纏めてbundle
- モジュール管理できるため機能ごとに開発ができ保守性が上がる
- 複数のjsファイル(cssや画像も)を一つのファイルにbundleできるためリクエスト数減少とパフォーマンス向上
※ ファイルサイズの増大によるパフォーマンス低下もありうる - 依存関係の解消
CSSをインラインのstyleではなく、CSSファイルとして出力
1. webpack使用の下準備
1.1. webpackでの基本的なパッケージのインストール
$ npm init -y
$ npm i -S jquery
$ npm i -D webpack webpack-cli
$ npm i -D terser-webpack-plugin optimize-css-assets-webpack-plugin mini-css-extract-plugin
$ npm i -D node-sass css-loader sass-loader style-loader postcss-loader
$ npm i -D babel-loader @babel/core @babel/polyfill @babel/preset-env
$ npm i -D autoprefixer
# 分割したcssの読み込みをリロードしない(brouser-sinc代用)
$ npm i -D webpack-dev-server
# gulp使うとき
$ npm i -D gulp gulp-eslint gulp-notify gulp-plumber
1.2. package.jsonの編集
package.json
{
"name": "webpack_test",
"version": "1.0.0",
"description": "",
- "main": "index.js",
"scripts": {
- "test": "echo \"Error: no test specified\" && exit 1",
// sassも監視対象
+ "build:dev": "webpack --mode development --watch",
+ "build": "webpack --mode production",
// dev-serverだけだとjsの監視はされるが、バンドルはされない
// 保存すると自動リロードがかかるため更新はされるが、監視よりも遅いため二回目リロード時にバンドルが反映される
+ "start": "webpack --mode development --watch & webpack-dev-server",
},
"scripts": {
},
+ "private": true,
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"jquery": "^3.4.1"
},
"devDependencies": {
"@babel/core": "^7.4.5",
"@babel/polyfill": "^7.4.4",
"@babel/preset-env": "^7.4.5",
"autoprefixer": "^9.6.0",
"babel-loader": "^8.0.6",
"css-loader": "^3.0.0",
"mini-css-extract-plugin": "^0.7.0",
"node-sass": "^4.12.0",
"optimize-css-assets-webpack-plugin": "^5.0.3",
"postcss-loader": "^3.0.0",
"sass-loader": "^7.1.0",
"style-loader": "^0.23.1",
"terser-webpack-plugin": "^1.3.0",
"webpack": "^4.35.2",
"webpack-cli": "^3.3.5",
"webpack-dev-server": "^3.7.2"
}
}
1.2. webpack.config.jsの作成
webpackをインストールしたらwebpack.config.js
を手動で作成
webpack.config.js
// 開発or本番モードの選択(development、production、noneのいずれか設定必須)
// development: 開発時のファイル出力のモード(最適化より時間短縮,エラー表示などを優先)
// production: 本番時のファイル出力のモード(最適化されて出力される)
const MODE = "development";
// ソースマップの利用有無(productionのときはソースマップを利用しない)
const enabledSourceMap = MODE === "development";
// ファイル出力時の絶対パス指定に使用
const path = require('path');
// プラグイン
// js最適化
const TerserPlugin = require('terser-webpack-plugin');
// css最適化
const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin');
// css抽出
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
// jQueryで使用
const webpack = require('webpack');
module.exports = {
// エントリーポイント(メインのjsファイル)
entry: './src/js/app.js',
// ファイルの出力設定
output: {
// 出力先(絶対パスでの指定必須)
path: path.resolve(__dirname, 'dist/js'),
// 出力ファイル名
filename: "bundle.js"
},
mode: MODE,
// ソースマップ有効
devtool: 'source-map',
// ローダーの設定
module: {
rules: [
{
// ローダーの対象 // 拡張子 .js の場合
test: /\.js$/,
// ローダーの処理対象から外すディレクトリ
exclude: /node_modules/,
use: [
{
// Babel を利用する
loader: "babel-loader",
// Babel のオプションを指定する
options: {
presets: [
// プリセットを指定することで、ES2019 を ES5 に変換
"@babel/preset-env"
]
}
}
]
},
{
// ローダーの対象 // 拡張子 .scss の場合
test: /\.scss/,
// Sassファイルの読み込みとコンパイル
use: [
// linkタグに出力する機能
"style-loader",
{
loader: MiniCssExtractPlugin.loader,
options: {
// css出力先を指定
publicPath: path.resolve(__dirname, 'dist/css'),
// developmentのときのみ有効
hmr: process.env.NODE_ENV === 'development',
},
},
// CSSをバンドルするための機能
{
loader: "css-loader",
options: {
// CSS内のurl()メソッドの取り込みを禁止する
// 画像ファイルをbase64でエンコードするとかでは無い限り、必要なし
url: false,
// ソースマップの利用有無
sourceMap: enabledSourceMap,
// Sass+PostCSSの場合は2を指定
// 0 => no loaders (default);
// 1 => postcss-loader;
// 2 => postcss-loader, sass-loader
importLoaders: 2
}
},
// PostCSS(Autoprefixer)のための設定
// ベンダープレフィックスを追加するためのPostCSS用プラグイン
{
loader: "postcss-loader",
options: {
// PostCSS側でもソースマップを有効にする
sourceMap: enabledSourceMap,
plugins: [
// Autoprefixerを有効化
require("autoprefixer")({
grid: true
})
]
}
},
// Sassをバンドルするための機能
{
loader: "sass-loader",
options: {
// ソースマップの利用有無
sourceMap: enabledSourceMap
}
}
]
}
]
},
// mode:puroductionでビルドした場合のファイル圧縮
optimization: {
minimizer: production
? []
: [
// jsファイルの最適化
new TerserPlugin({
// すべてのコメント削除
extractComments: 'all',
// console.logの出力除去
terserOptions: {
compress: { drop_console: true }
},
}),
// 抽出したcssファイルの最適化
new OptimizeCssAssetsPlugin({})
]
},
// js, css, html更新時自動的にブラウザをリロード
devServer: {
// サーバーの起点ディレクトリ
// contentBase: "dist",
// バンドルされるファイルの監視 // パスがサーバー起点と異なる場合に設定
publicPath: '/dist/js/',
//コンテンツの変更監視をする
watchContentBase: true,
// 実行時(サーバー起動時)ブラウザ自動起動
open: true,
// 自動で指定したページを開く
openPage: "index.html",
// 同一network内からのアクセス可能に
host: "0.0.0.0"
},
plugins: [
// 抽出したCSSファイル最適化
new OptimizeCssAssetsPlugin({
assetNameRegExp: /\.optimize\.css$/g,
cssProcessor: require('cssnano'),
cssProcessorPluginOptions: {
preset: ['default', { discardComments: { removeAll: true } }],
},
canPrint: true
}),
// ビルドされたjsファイルからstyleの部分を抽出してcssファイルで出力
// jsファイルからcssの内容消える
// v3でのextract-text-pluginのようなもの
new MiniCssExtractPlugin({
// 出力先ファイル名 // prefix は output.path
filename: "../css/[name].css",
chunkFilename: "[id].css"
}),
new webpack.ProvidePlugin({
$: 'jquery'
})
]
};
2. webpackの処理対象となるjsファイルの書き方
エントリーポイントとなるjsファイルをapp.js
モジュールファイルをmodule1.js
とすると次のように書く
app.js
import "../scss/style.scss";
import jQuery from 'jquery';
import "@babel/polyfill";
import { モジュールから呼び出す関数 } from './modules/module1';
module.js
// 関数を定義
index.html
<!DOCTYPE html>
<html lang="ja" dir="ltr">
<head>
<meta charset="utf-8">
<title>webpack_sample</title>
<link rel="stylesheet" href="./dist/css/main.css">
</head>
<body>
//
<script src="./dist/js/bundle.js"></script>
</body>
</html>
3. webpack実行
実行コマンド
package.json
のscripts
で設定した名称で実行
$ npm run build:dev # バンドル(開発用)実行
$ npm run build # バンドル(本番用)実行
$ npm run start # バンドルと監視スタート