独学の内容をまとめたものです。誤りがございましたら、ご連絡いただけると幸いです。
リンク
- webpackとBabelの基本を理解する(1) ―webpack編―
- webpackとBabelの基本を理解する(2) ―Babel編―
- webpackとBabelの基本を理解する(3) ―webpackとBabel編―(本記事)
- webpackとBabelの基本を理解する(4) ―React編―
- webpackとBabelの基本を理解する(5) ―Sass編―
概要
この記事の概要
- 目的
- フロントエンドの環境構築に利用されるツールへの理解を深める
- 本記事のゴール
- webpackにBabelオプションを追加する方法を知る
- 対象者
- WEBフロント担当者
- HTML,CSS,JavaScript(es2015含む)の基本的な構文を理解している人
- npmの利用方法を理解している人
- 環境・バージョン
- Windows10
- Node.js(推奨版) 10.15.01
- npm 6.4.1
- webpack 4.29.6
- webpack-cli 3.2.3
- babel-core 7.3.4
- babel-cli 7.2.3
- preset-env 7.3.4
webpackのLoader
webpackは、基本的にimport(require)文を頼りに、芋づる式にJSまたはJSONファイルをまとめていくツールです。
JS以外のファイル(例えばCSS)なども対象としたい場合や、まとめる前にコードをコンパイルする必要がある場合、元のソースをwebpackがバンドル可能な状態に変換するために、Loaderを利用します。
Loaderの指定方法
webpack.config.js
にmodule.rules
を追加します。rules
に記述する基本の設定は二つです。
- test: どのタイプのファイルを変換対象とするかを文字列または正規表現で指定します。
- use: どのloaderを使用するかを指定します。
これについては、公式サイトのコンセプト説明が分かりやすかったです。Loaders
module.exports = {
output: {
filename: 'my-first-webpack.bundle.js'
},
module: {
rules: [
{ test: /\.txt$/, use: 'raw-loader' }
]
}
};
"Hey webpack compiler, when you come across a path that resolves to a '.txt' file inside of a require()/import statement, use the raw-loader to transform it before you add it to the bundle."
やあ!webpackコンパイラ、君がimportかrequire文で'.txt'に該当するファイルに遭遇したら、バンドる前に
raw-loader
を使ってそのファイルを変換してくれないかな。
配列を使って、loaderを複数指定することも可能です。この場合、末尾のloaderから順に適用されます。
module: {
rules: [
{
test: /\.txt$/,
use: ['raw-loader', 'a-loader', 'c-loader']
}
]
}
exclude
node_modulesフォルダ内のファイル群など、loaderの対象外としたい場合は、rules
にexclude
を追加します。
options
loaderに設定情報を持たせたい場合は、use
の項目をloader
とoptions
に分けて記述します。
module.exports = {
module: {
rules: [
{
test: /\.txt$/,
exclude: /node_modules/, //対象外ディレクトリ
use: [
{
loader: 'raw-loader', //loader名
options: {...} //設定情報
},
'a-loader',
'c-loader'
]
}
]
}
};
babel-loader
インストール
バンドる前にバベるには、babel-loaderを利用します。
$ npm install babel-loader --save-dev
もちろんBabel本体も必須なので、まだの方はこちら
$ npm install babel-loader @babel/core @babel/preset-env --save-dev
設定
webpack.config.js
に、設定値を追加します。options
の記述方法は基本的に.babelrc
と同様です。プリセットの名前を記述するだけの設定ならば、webpack.config.js
のoptions
に集約でき、.babelrc
は不要になります。
module.exports = {
/* 略 */
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader', //loader名
options: { //Babelの設定
presets: ['@babel/preset-env']
}
}
}
]
}
};
実行
下記の様に、es2015以降の構文をふんだんに盛り込んだファイルを準備します。
sample/
├ src/
│ ├ component/
│ │ └ test.js
│ └ index.js
└ dist/
/**
* /src/component/test.js
*/
const test = ({ foo, bar, ...others }) => {
console.log(others);
}
export { test };
/**
* /src/index.js
*/
import { test } from './component/test';
const keyName = 'hei';
let params = {
foo: 'foooooo',
bar: 'baaaaa',
baz: 'zzzzzz',
[keyName]: 'moimoi'
};
test(params);
webpack.config.jsはこんな感じ
module.exports = {
mode: 'development',
devtool: 'inline-source-map',
entry: './src/index.js',
output: {
path: __dirname + '/dist',
filename: 'sample.js'
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env']
}
}
}
]
}
};
webpackを実行します。
$ npx webpack
出力された/dist/sample.js
では、es5の構文に変換されていることが確認できます。
/* 略 */
"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export (binding) */ __webpack_require__.d(...);
function _objectWithoutProperties(source, excluded) {...}
function _objectWithoutPropertiesLoose(source, excluded) {...}
var test = function test(_ref) {
var foo = _ref.foo,
bar = _ref.bar,
others = _objectWithoutProperties(_ref, ["foo", "bar"]);
console.log(others);
};
/* 略 */
設定ファイルの統合とpolyfillの設定
上記では、polyfillの設定をしていないので、例えばPromiseなどの新機能は変換されません。しかし、下記設定ではエラーが発生しました。
/**
* webpack.config.js
*/
use: {
loader: 'babel-loader',
options: {
presets: [
[
'@babel/preset-env', {
'useBuiltIns': 'usage' // useBuiltInsオプションを追加
}
]
]
}
}
/**
* /src/component/test.js
*/
const test = ({ foo, bar, ...others }) => {
console.log(foo, bar);
// polyfillが必要
new Promise((resolve, rejects) => {
setTimeout(() => {
resolve(others);
}, 2000);
}).then(data => {
console.log(data);
})
}
export { test };
# エラーの一部
ERROR in ./src/component/test.js
Module not found: Error: Can't resolve 'core-js/modules/es6.array.index-of' in 'C:\sample\src\component'
@ ./src/component/test.js 1:0-44
@ ./src/index.js
polyfillのモジュールをnode_module
ではなく、元ファイルがあるフォルダを起点に探している??同じ内容で.babelrc
またはpackage.json
で設定した場合は、無事コンパイルされます。
語学力が低いのでちゃんと読めているか不安ですが、こちらのやり取りを見る限りwebpack.config.js
だけでは不十分なようです。
@babel/preset-env doesn't seem to work in combination with babel-loader and .browserlistrc
じゃあ、webpack.config.jsではPresetsの指定はいらないんじゃないかと思って、use:'babel-loader'
だけにするとまたエラーになります。Presetsの指定自体は必要です。
- webpack.config.jsでは、Presetsの名前の列挙のみする。
- package.jsonで、Presetsの設定を行う。
この2点で無事にPolyfillを利用できるようになりました。
なお、このエラーは@babel/preset-env
のuseBuiltIns
オプションで遭遇したものです。他のPresetsでも発生しているわけではありません。2019年2月現在「useBuiltIns:'usage'」の項目には「experimental(実験的)」とあります。(将来的には解決するかも?)
// webpack.config.js
module.exports = {
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env']
}
}
}
]
}
}
// package.json
{
"babel": {
"presets": [
[
"@babel/preset-env", {
"useBuiltIns": "usage"
}
]
]
}
}
いやいや、あなたの設定方法がそもそも間違っているんだよとか、こうするとうまくいくよ的な情報がございましたら、コメントいただけると幸いです。