101
76

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

webpackとBabelの基本を理解する(3) ―webpackとBabel編―

Last updated at Posted at 2019-03-03

独学の内容をまとめたものです。誤りがございましたら、ご連絡いただけると幸いです。

リンク

  1. webpackとBabelの基本を理解する(1) ―webpack編―
  2. webpackとBabelの基本を理解する(2) ―Babel編―
  3. webpackとBabelの基本を理解する(3) ―webpackとBabel編―(本記事)
  4. webpackとBabelの基本を理解する(4) ―React編―
  5. 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.jsmodule.rulesを追加します。rulesに記述する基本の設定は二つです。

  1. test: どのタイプのファイルを変換対象とするかを文字列または正規表現で指定します。
  2. 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の対象外としたい場合は、rulesexcludeを追加します。

options
loaderに設定情報を持たせたい場合は、useの項目をloaderoptionsに分けて記述します。

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.jsoptionsに集約でき、.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

:thinking: 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-envuseBuiltInsオプションで遭遇したものです。他の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"
        }
      ]
    ]
  }
}

いやいや、あなたの設定方法がそもそも間違っているんだよとか、こうするとうまくいくよ的な情報がございましたら、コメントいただけると幸いです。

101
76
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
101
76

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?