██████████ のブログ

なんか技術的なメモ & ブクマ (no affiliate ads)

[草稿]JavaScript ビルド入門 Ver.1 (2018年 春)


フロントエンドエンジニア (赤ちゃん) が macOS 上でゼロから JavaScript + React を ↓ のスタックでビルドして Hello World できるようになるまでのお話

package manager: yarn
module bundler: webpack 4
task runner: npm scripts (yarn)

others: Babel, ESLint, pret tier, flow, jest, enzyme, ...


目次


これまでのあらすじ


最終的なディレクトリ構成

リポジトリルート
├─ src/ # loadersによる変換前のファイル置き場
├─ lib/ # loadersによる 変換後の/変換の必要がない ファイル置き場
├─ test/ # testファイル置き場
│
├─ package.json
├─ node_modules/.bin # 置き場 for packages locally installed with npm or yarn
│
├─ webpack.config.js
├─ webpack.config.js の output.path/ # ビルド後のアプリケーション置き場
:


パッケージマネージャー

まずは無限にパッケージマネージャーをインストールし続ける

homebrew:
macOS 上のパッケージ用
nodebrew:
Node.js そのもの用
npm:
Node.js 上のパッケージ用
CLI の開発が滞っているご様子
yarn:
https://yarnpkg.com/ja/
npm レジストリからモジュールを取得する Facebook ら製 CLI クライアント
package.json 互換
並行インストール
依存モジュールの ver. を固定 (デフォルト)


yarn をインストールする

npm をインストールし終えたら yarn をインストールする (ための下準備をする)
https://docs.npmjs.com/getting-started/fixing-npm-permissions

# Make a directory for global installations
mkdir ~/.npm-global

# Configure npm to use the new directory path
npm config set prefix '~/.npm-global'


copy and paste the below to your .bash_profile so that パスを通したりする

# npm のグローバルモジュールのパーミッションエラーを sudo で回避するのはセキュリティ上の懸念があるため
# npm のデフォルトディレクトリを自分の権限があるディレクトリに変えるプラクティスが npm 公式で推奨されている
# https://docs.npmjs.com/getting-started/fixing-npm-permissions
export PATH=$PATH:$HOME/.npm-global/bin
 
# ついでにローカルインストールする package のパスを通しておく ('.' はリポジトリルートを指す)
# (相対パスでパスを通すのでセキュリティ上の懸念から PATH の先頭ではなく末尾に追加するようにする)
export PATH=$PATH:./node_modules/.bin

注意: yarn で同様の設定をする場合は ↓ (デフォルトで $HOME 以下のディレクトリになっているっぽいけど)
https://yarnpkg.com/en/docs/cli/global


yarn をインストール

npm install --global yarn


package.json

リポジトリルートに移動して package.json を生成する

yarn init -y


フロントエンド開発における package.json の主な情報は,npm レジストリから何をどのような依存関係でインストールしたのか,npm runyarn run で実行できるスクリプトにはどのようなもがあるのか (scripts),の2点.

npm はそもそもが Node.js programs 用のパッケージマネージャーであって,package.json には npm レジストリでパッケージを配布するための情報が書かれている.フロントエンド界隈ではそれをフロントエンド開発に応用しているというだけのお話であって (npm 1.1.0-2 のときには既にそのように利用されていた模様),npm レジストリで配布するわけではないフロントエンド・アプリケーションには関係のない項目が package.json にはアホほどあり,それらは空欄でよい.... というのは npm のお話だけど,yarn も package.json を使うので事情は同じ.


上述のとおりフロントエンド開発において最も重要なのは,dependencies と devDependencies (依存関係),それと scripts の 3 項目.dependencies と devDependencies とはそれぞれ yarn add / npm install --saveyarn add --dev / npm install --save-dev とに対応しており,同コマンドでインストールしたものはそれぞれの項目に自動的に追記されていく.

参考: 依存関係の種類 | Yarn

scripts フィールド:
The "scripts" property is a dictionary containing script commands that are run at various times in the lifecycle of your package. The key is the lifecycle event, and the value is the command to run at that point.
パッケージの lifecycle (ビルド前後,アプリケーションの起動前後など) をフックして自分で書いたスクリプトを実行できる.

参考: scripts の各項目 https://docs.npmjs.com/misc/scripts


// package.json にて
"scripts": {
  "hoge": "echo 'hoge'"
}
 
// ターミナルにて
yarn run hoge
> hoge

すればすぐに分かるが npm scripts は "scripts" に登録したスクリプトを実行する.これが lifecycle をどのようにフックするのかは追々学ぶことになる (宿題).

参考: npm run 時にパラメータを渡す
Custom parameters can be passed to webpack by adding two dashes between the npm run build command and your parameters, e.g. npm run build -- --colors
https://webpack.js.org/guides/getting-started/#npm-scripts


package.json の各項目:
https://docs.npmjs.com/files/package.json https://yarnpkg.com/lang/en/docs/package-json/

参考: main フィールド
The main field is a module ID that is the primary entry point to your program. That is, if your package is named foo, and a user installs it, and then does require("foo"), then your main module's exports object will be returned.
This should be a module ID relative to the root of your package folder.
For most modules, it makes the most sense to have a main script and often not much else.


パッケージのインストール

とりあえず ↓ ここらへんのものを
https://github.com/mizchi/fe-base/blob/master/package.json

yarn add # OR npm install --save   something installed as dependencies

したり

yarn add --dev # OR npm install --save-dev   something installed as devDependencies

したりする

参考: 依存関係の種類 | Yarn

注意: 基本的に ↓ に書かれているようなの以外は npm install -gyarn global add しない (e.g. webpack 公式 says "Installing locally is what we recommend for most projects. This makes it easier to upgrade projects individually when breaking changes are introduced.")
https://qiita.com/about_hiroppy/items/c4fdf01194e9b32f5744

注意: 何をインストールするかは 付録 2. インストールするもの一覧 に追々まとめる

注意: yarn で何をインストールしたかの確認 (依存パッケージ除く) は yarn list --depth=0 でもうまくできないようなので package.json を直接見る


webpack.config.js

何を使ってどのようにモジュールを繋ぎ合わせるかは webpack が webpack.config.js を見たりエントリポイントから順々に遡って見ていったりして解決される

webpack の概要 (?) としては ↓ が分かりやすいかも
https://qiita.com/chuck0523/items/caacbf4137642cb175ec

webpack.config.js の概要としては ↓ が分かりやすいかも
https://webpack.js.org/concepts/

参考: 付録 3. モジュール


webpack.config.js の各項目の意味

mizchi さんのを https://webpack.js.org/configuration/ とかを見ながら一行ずつ解読していく


https://github.com/mizchi/fe-base/blob/master/webpack.config.js

const path = require('path')
const webpack = require('webpack')
const pkg = require('./package')
const DEV_PORT = process.env.PORT || 4444

module.exports = {
  entry: {
    app: [
      './src/index.js'
    ]
  },
  output: {
    filename: '[name].bundle.js',
    chunkFilename: '[name].bundle.js',
    path: __dirname + '/public',
    publicPath: '/'
  },
  devServer: {
    contentBase: 'public/',
    historyApiFallback: true,
    port: DEV_PORT
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        use: 'babel-loader',
        exclude: /node_modules/
      }
    ]
  },
  plugins: []
}


module.exports


npm レジストリで配布されているものはすべて Node.js 向けに書かれている (npm はそもそもが Node.js programs 用のパッケージマネージャーだし,現に module.exports (非ES) してるし).そして,module.exports のおかげで,

//a.js にて
module.exports = {foo: 'bar'}

//b.js にて (a.js と b.js は同じディレクトリにある)
const a = require(./a)
console.log(a.foo)

というようなことが本来 言語仕様にモジュールという概念がなかった JavaScript でもできるよ,というだけのお話 (だった.ES Modules の登場によって今後どうなっていくのだろう)
https://nodejs.org/api/modules.html#modules_the_module_object


entry
  entry: {
    app: [
      './src/index.js'
    ]
  },

エントリポイントを文字列などの型で指定する (この場合は Object と Array).なぜエントリポイントが複数個になりうるかは 【意訳】Webpackの混乱ポイント - Qiita が分かりやすい.

Simple rule: one entry point per HTML page. SPA: one entry point, MPA: multiple entry points. https://webpack.js.org/configuration/entry-context/#entry


output
  output: {
    filename: '[name].bundle.js',
    chunkFilename: '[name].bundle.js',
    path: __dirname + '/public',
    publicPath: '/'
  },
output.filename

This option determines the name of each output bundle. The bundle is written to the directory specified by the output.path option.

However, when creating multiple bundles via more than one entry point, code splitting, or various plugins, you should use one of the following substitutions to give each bundle a unique name...

Using entry name: filename: "[name].bundle.js"
https://webpack.js.org/configuration/output/#output-filename


output.chunkFilename

This option determines the name of non-entry chunk files. See output.filename option for details on the possible values.

Note that these filenames need to be generated at runtime to send the requests for chunks. Because of this, placeholders like [name] and [chunkhash] need to add a mapping from chunk id to placeholder value to the output bundle with the webpack runtime. This increases the size and may invalidate the bundle when placeholder value for any chunk changes.

By default [id].js is used or a value inferred from output.filename ([name] is replaced with [id] or [id]. is prepended). https://webpack.js.org/configuration/output/#output-chunkfilename


output.path
const path = require('path')

  output: {
    path: __dirname + '/public'
  }
const path = require('path')
Path | Node.js v9.10.1 Documentation
OS 間のディレクトリ構造の差異を吸収するモジュール
output.path にて path.join(__dirname, '/public') やら path.resolve(__dirname, "dist") やらするのに必要

webpack 公式 says "the target directory for all output files must be an absolute path (use the Node.js path module)"

__dirname
https://nodejs.org/api/modules.html#modules_dirname
The directory name of the current module. This is the same as the path.dirname() of the __filename.

この変数のスコープはグローバルではなくモジュール

output.path
リポジトリルート直下にあってビルド後のアプリケーションが格納されるディレクト


output.publicPath
  output: {
    publicPath: '/'
  },

The value of the option is prefixed to every URL created by the runtime or loaders. Because of this the value of this option ends with / in most cases.

Simple rule: The URL of your output.path from the view of the HTML page. https://webpack.js.org/configuration/output/#output-publicpath

publicPath を扱える loaders なら画像などのアセットが CDN にあるときでも「アセットを指す ローカルファイル内での相対パス」と URL (CDN) とを適切に置換することもできる.例えば,url-loader はオプションが limit: 1 ならば常に (画像をインラインイメージにするのではなく) URL を置換してくれる.


devServer
const DEV_PORT = process.env.PORT || 4444
 
  devServer: {
    contentBase: 'public/',
    historyApiFallback: true,
    port: DEV_PORT
  },

付録 1. how to develop with webpack を先に読んだ方が分かりやすい


devServer.contentBase

Tell the server where to serve content from. This is only necessary if you want to serve static files. devServer.publicPath will be used to determine where the bundles should be served from, and takes precedence.

By default it will use your current working directory to serve content, but you can modify this to another directory:

contentBase: path.join(__dirname, "public")

Note that it is recommended to use an absolute path.
https://webpack.js.org/configuration/dev-server/#devserver-contentbase


devServer.historyApiFallback

404 になるようなアクセスをいっぺん index.html とかにリダイレクトさせ (て react-router とかで本来アクセスしたかったページに遷移させ) るご様子.SPA を念頭に置いた機能っぽい.production では他の方法でリダイレクトさせる.
https://webpack.js.org/configuration/dev-server/#devserver-historyapifallback
https://blog.mismithportfolio.com/web/reactrouter-cannnotget


module
module: {
    rules: [
      {
        test: /\.js$/,
        use: 'babel-loader',
        exclude: /node_modules/
      }
    ]
  },


Babel 公式 interactive setup guide によると,Babel を webpack で使いたかったら

yarn add babel-loader babel-core --dev

して

module: {
  rules: [
    { test: /\.js$/, exclude: /node_modules/, loader: "babel-loader" }
  ]
}

しろ,とだけ漢らしく書かれている:
https://babeljs.io/docs/setup#installation

↑ の設定の読み方:
http://pepeky.hatenablog.com/entry/2018/03/13/231145#loaders

詳細 (読まなくても当面は支障ないと思うけど):
https://github.com/babel/babel-loader
https://webpack.js.org/loaders/babel-loader/


yarn run build 💢

"scripts": {
  "watch": "webpack-dev-server --hot --mode development",
  "build:dev": "webpack --mode development",
  "build": "NODE_ENV=production webpack --mode production"
}

webpack 4 からは

mizchi さんの scripts の他の項目は 付録 5. scripts の他の項目 💢⚠️ にて調べる予定


Hello World 💢


付録 0. Node.js の環境変数

# デフォルトの環境変数には何があるかを確認する
$ node
> process.env
 
# 環境変数を設定して node を起動する
$ NODE_HOGE=huga node
> process.env

NODE_ENV などの環境変数
Node.js の起動オプション、環境変数、npm start の話 - Block Rockin’ Codes


注意: process.env.NODE_ENV は webpack.config.js 内で使えない

Technically, NODE_ENV is a system environment variable that Node.js exposes into running scripts. It is used by convention to determine dev-vs-prod behavior by server tools, build scripts, and client-side libraries. Contrary to expectations, process.env.NODE_ENV is not set to "production" within the build script webpack.config.js, see #2537. Thus, conditionals like process.env.NODE_ENV === 'production' ? '[name].[hash].bundle.js' : '[name].bundle.js' within webpack configurations do not work as expected.
https://webpack.js.org/guides/production/#specify-the-environment


webpack 4 からは mode オプションが導入された
@about_hiroppy - 次のリリースであるwebpack 4の主な変更点まとめ - Modeオプションの追加


付録 1. how to develop with webpack

各項目を雑に紹介する.詳細は ↓.これらはすべて開発中のオプションでありプロダクトをビルドするときに使ってはいけない.
https://webpack.js.org/guides/development/


ビルド時に出力されるログの読み方

公式ドキュメントを漁ってみてもちょっと見当たらなかったけど,多分 ↓ ここらへんのこととかを言ってそう.
https://webpack.js.org/configuration/stats/

極軽くコードを漁ってみたら意味が分かったっぽい.ざっと見,{ }: chunk id (以下 ci), <{ }>: parents ci, ={ }=: siblings ci, >{ }<: children ci, ... げ. https://github.com/webpack/webpack/blob/e15df707388c16d45cbf5f83936b22d95f1f92e8/lib/Stats.js

いずれにせよ,公式のはイマイチなのでとっとと webpack-dashboard とかを使った方がよさげ?
https://speakerdeck.com/mukai21/webpacktozhong-liang-kunarou


inline source map

使い方:
webpack.config.js にて `devtool: 'inline-source-map'` する
ご利益:
バンドル前の何というファイル の 何行目 でエラーが生じたかがブラウザの devtool の console を見れば分かる


watch mode

使い方:
package.json にて `"scripts": {"watch": "webpack --watch"}`
ターミナルにて `yarn run watch` する (プロンプトは帰ってこない)
ご利益:
dependency graph 中のファイルに変化が生じたのを自動的に webpack が察知してそれらをモジュール単位でコンパイルしなおしてくれる


webpack-dev-server

使い方:
ターミナルにて `yarn add webpack-dev-server --dev`
webpack.config.js にて `devServer: { contentBase: './dist'}`
package.json にて `"scripts": {"start": "webpack-dev-server --open"}`
ターミナルにて `npm run start` する
ご利益:
dist ディレクトリ以下のファイルに変化が生じるたびに自動的に webpack が (モジュール単位で?) コンパイルしなおして webpack-dev-server がそれらをブラウザにリロードしてくれる (デフォルト localhost: 8080)

詳細
https://webpack.js.org/configuration/dev-server/

後継の開発サーバ
http://yami-beta.hateblo.jp/entry/2018/03/07/191730


webpack-dev-middleware

使い方:
省略
ご利益:
webpack で処理されたファイルを 開発サーバに送ってくれる (webpack-dev-server 内でも使われている).

開発サーバの使い方:
開発サーバの設定を server.js に書いて npm scripts に "server": "node server.js" と書いて yarn run server すると 開発サーバが起動する
https://webpack.js.org/guides/development/#using-webpack-dev-middleware


ページ構成

以降の項目で plugins などについては

  1. hoge 公式の説明
  2. hoge が導入された背景 (mizchi 氏個人のお話)
  3. 疑問 (宿題), hoge ってなんやねん など

という構成を基本とする


付録 2. インストールするもの一覧

foo-bar VS. @foo/bar (npm レジストリ)

Scoped packages:

When used in package names, scopes are preceded by an @ symbol and followed by a slash, e.g. @somescope/somepackagename
https://docs.npmjs.com/misc/scope


scopes (scoped packages) ってなんやねん:

Scopes are used to group related packages together, and to create a namespace, like a domain, for npm modules.
This is explained in more detail here.
https://docs.npmjs.com/getting-started/scoped-packages


これによって例えば Babel とは全く関係のない第三者が Babel 公式になりすまして勝手に babel-preset-hoge という preset を npm 上に公開したりするのを防げるとのこと

そして,Babel の preset に scoped package と non-scoped package があるのは,↓のリネームの過渡期であるというだけであって,新しい ver. (Babel 7以降) のは scoped package,古い ver. のは non-scoped package というだけのお話
Scoped: rename package names to @babel/ [skip ci] · babel/babel@1cd564b · GitHub


Loaders (webpack)

↓のがまとまっていて分かりやすかった
https://note.mu/konpyu/n/n694491cd9e80


webpack supports modules written in a variety of languages and preprocessors, via loaders. Loaders describe to webpack how to process non-JavaScript modules and include these dependencies into your bundles.
https://webpack.js.org/concepts/modules/


ローダの使い方 webpack.config.js に設定を書く ver.

  module: {
    rules: [{
        test: /.css$/,  # ローダによる処理の対象となるファイルは何か (この場合 .csshoge はマッチしない)
        exclude: /node_modules/,  # ただし,node_modules ディレクトリ以下のファイルは除外する
        use: [
          { loader: 'style-loader' },  # 何のローダを使うか
          {
            loader: 'css-loader',  # 同上
            options: {
              modules: true  # css-loader のオプション
            }
          }
        ]
    }]
  }


ローダの使い方 npm scripts を介した ver.

// package.json にて
"scripts": {
  "build:hoge" : "webpack --module-bind jade-loader --module-bind 'css=style-loader!css-loader'"
}
 
// ターミナルにて
yarn run build:hoge


ローダの使い方 .js ファイル中で import 文を使う ver. もあるご様子
https://webpack.js.org/concepts/loaders/


Plugins (webpack)

プラグインとは何か,ローダとの違いは何かは ↓ の http://pepeky.hatenablog.com/entry/2018/02/27/191944#Loaders-VS-Plugins-webpack に譲って,ここではプラグインの使い方について簡単に触れる.

プラグインの実装は,"function.prototype.apply をオーバーライドしたコンストラクタ" であり,そのコンストラクタを module.exports している.そして,プラグインを使うには,例えば

// ターミナルにて
yarn add html-webpack-plugin --dev
 
// webpack.config.js にて
const HtmlWebpackPlugin = require('html-webpack-plugin')
 
module exports = {
  plugins: [new HtmlWebpackPlugin(options)]
}

するだけ.
https://github.com/webpack/docs/wiki/plugins


Loaders VS. Plugins (webpack)

As you might have realized, Loaders work at the individual file level during or before the bundle is generated.

Whereas Plugins work at bundle or chunk level and usually work at the end of the bundle generation process. And some Plugins like commonsChunksPlugins go even further and modify how the bundles themselves are created.
https://medium.com/@rajaraodv/webpack-the-confusing-parts-58712f8fcad9

参考: webpack 4 の optimization.splitChunks の使い方、使い所 〜廃止された CommonsChunkPlugin から移行する〜 - Qiita


devDependencies 💢

Babel

設定ファイルについては 付録 4. .babelrc または .babelrc.js


preset ってなんやねん

Don’t want to assemble your own set of plugins? No problem! Presets are sharable .babelrc configs or simply an array of babel plugins.
https://babeljs.io/docs/plugins/#presets


babel-core

主に parse と transform を担っているご様子
https://github.com/babel/babel/tree/master/packages/babel-core


babel-preset-env

Without any configuration options, babel-preset-env behaves exactly the same as babel-preset-latest (or babel-preset-es2015, babel-preset-es2016, and babel-preset-es2017 together).
https://babeljs.io/docs/plugins/preset-env


babel-polyfill

This will emulate a full ES2015+ environment and is intended to be used in an application rather than a library/tool.
Make sure it is called before all other code/require statements!
https://babeljs.io/docs/usage/polyfill


ポリフィルってなんやねん: http://pepeky.hatenablog.com/entry/2018/03/13/231145#polyfill


babel-preset-react

これさえ入れとけば React を使った .js ファイルをビルドする際に,

Babel can convert JSX syntax (* into React.createElement and its arguments) and strip out (* Flow's) type annotations.
https://babeljs.io/docs/plugins/preset-react/


babel-register

One of the ways you can use Babel is through the require hook. The require hook will bind itself to node’s require and automatically compile files on the fly.
https://babeljs.io/docs/usage/babel-register/

webpack で Babel を使うだけならいらなそう


eslint 💢⚠️

保留
リンタ & ベストプラクティス養成ギプス & 無駄な議論から解放してくれる & 上記の理由により非常に重要


prettier 💢️️⚠️

保留
コードフォーマッタ & 無駄な議論から解放してくれる & 上記 (eslint) の理由により非常に重要


jest 💢⚠️

保留
FB製のテスティングフレームワーク dominant in JS testing frameworks

上記の理由によりフロントエンドにおいてはテストアフターが妥当なプラクティスらしい


enzyme 💢⚠️

保留

storybook 💢⚠️⚠️

保留
まだ webpack 4 に追いついていないので省略 (メンテされていないとかいうお話も???)

flow-bin 💢⚠️

保留

glow 💢⚠️

保留

netlify-cli 💢⚠️

保留

react-ほげ 💢
react-hot-loader 💢⚠️

保留
まだ webpack 4 に追いついていないご様子

https://gaearon.github.io/react-hot-loader/getstarted/
https://github.com/gaearon/react-hot-loader


react-redux 💢⚠️

保留

react-test-renderer 💢
regenerator-runtime 💢⚠️⚠️

保留

webpack 💢
webpack-cli 💢

npm scripts を介して webpack を使うのに必要

webpack-dev-server 💢


dependencies 💢

axios 💢⚠️⚠️

保留

history 💢⚠️⚠️

保留

recompose 💢⚠️⚠️

保留

react 💢
react-dom 💢
redux 💢⚠️

保留

redux-logger 💢⚠️

保留

redux-promise 💢⚠️

保留

redux-thunk 💢⚠️

保留

styled-components 💢⚠️⚠️

保留

universal-router 💢⚠️⚠️

保留


付録 3. モジュール

ES Modules のお話
Node.jsのES Modulesサポートの現状確認と備え - teppeis blog
ES modulesのexport defaultは使わないほうがよい - Islands in the byte stream


JavaScript のモジュールについて
https://webpack.js.org/concepts/modules/


付録 4. .babelrc または .babelrc.js

.babelrc の公式ドキュメント (あまり参考にならない)
https://babeljs.io/docs/usage/babelrc/


https://github.com/mizchi/fe-base/blob/master/.babelrc.js

const plugins = [
'react-hot-loader/babel',
'@babel/plugin-proposal-object-rest-spread',
[
  'module-resolver',
  {
    root: ['./src'],
    alias: {
      '~': './src',
      test: './test'
    }
  }
]
]
 
const presets = ['@babel/preset-flow', '@babel/preset-react']
 
const presetsByEnv = {
development: [['@babel/preset-env', { targets: { chrome: 65 } }]],
test: [['@babel/preset-env', { targets: { node: '8.5' } }]],
production: [
  [
    '@babel/preset-env',
    {
      modules: false,
      browsers: ['last 2 versions', 'ie >= 11']
      }
    ]
  ]
}
 
module.exports = {
  plugins,
  presets: [...presets, ...presetsByEnv[process.env.NODE_ENV || 'development']]
}

直接 webpack.config.js に babel-loader が何の preset を使うかなどの設定を書かなくても Babel の設定ファイルである .babelrc または .babelrc.js (Babel 7以降) に ↑ のように書いておけば OK とのこと

設定ファイルが .js ファイルになったことによって便利になった点については ↓ で挙げられているようなことっぽい
http://abouthiroppy.hatenablog.jp/entry/babel7


plugins

ここでは共通の plugins を指定している

react-hot-loader/babel

React Hot Loader を使うのに必要な設定.yarn add react-hot-loader すれば勝手についてくるので .babelrc に ↓ と書くだけ (react-hot-loader は --dev ではない)

{"plugins": ["react-hot-loader/babel"]}

https://github.com/gaearon/react-hot-loader#install


@babel/plugin-proposal-object-rest-spread

This plugin allows Babel to transform rest properties for object destructuring assignment (* 分割代入) and spread properties for object literals.

// Rest Properties
let { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 }
console.log(x) // 1
console.log(y) // 2
console.log(z) // { a: 3, b: 4 }
 
// Spread Properties
let n = { x, y, ...z }
console.log(n) // { x: 1, y: 2, a: 3, b: 4 }
https://github.com/babel/babel/tree/master/packages/babel-plugin-proposal-object-rest-spread


この plugin が導入された背景:
チーム開発におけるパフォーマンス上の懸念材料たる Immutable JS の代替として ES2015 の object-rest-spread を使いたい
2017末時点での React Component 設計のベストプラクティス - 本当に必要になるまで ImmutableJS を使わない


疑問 (宿題):
MDN によると spread operator は Shallow-cloning (excluding prototype) なんだけど,それでどうやってイミュータブルを実現していくんだろう?


module-resolve

This plugin can simplify the require/import paths in your project. For example, instead of using complex relative paths like ../../../../utils/my-utils, you can write utils/my-utils.
https://github.com/tleunen/babel-plugin-module-resolver


この plugin が導入された背景:

やりたいこと
import bbb from 'aaa/bbb' の解決先を、src/aaa/bbb にしたい

やりたくないこと
Webpackに依存したくない。Babelのレイヤーで解決したい。Babel側に寄せておけば、Webpackが腐ったときも巻き込まれずに済む
https://qiita.com/mizchi/items/b24720e01562a652775b


resolve module ってなんやねん:
http://pepeky.hatenablog.com/entry/2018/03/13/231145#module-resolution


presets

ここでは共通の presets を指定している


@babel/preset-react

Strip flow types and transform JSX into createElement calls. https://babeljs.io/docs/plugins/preset-react/


@babel/preset-flow

Babel preset for all Flow plugins

preset-flow は preset-react に同梱されているので,恐らく react を使わない案件用にボイラープレートに含められているものと思われる.


presetsByEnv

ここでは環境ごとに @babel/preset-env のオプションを設定している.これによって preset-env が環境ごとに必要な plugins と polyfills を自動的に特定する.NODE_ENV は node 起動時に設定しているっぽい.

// 1. 論理演算子の短絡評価 × Object [キー] 構文 × スプレッド演算子 というショートハンド
...presetsByEnv[process.env.NODE_ENV || 'development']
 
// 2. NODE_ENV が設定されていない場合
...presetsByEnv['development']
 
// 3. キー 'development' の値の配列がスプレッド演算子で展開された
// [preset or plugins, {options}]
['@babel/preset-env', { targets: { chrome: 65 } }]


@babel/preset-env

A Babel preset that compiles ES2015+ down to ES5 by automatically determining the Babel plugins and polyfills you need based on your targeted browser or runtime environments.
https://github.com/babel/babel/tree/master/packages/babel-preset-env


付録 5. scripts の他の項目 💢⚠️

  "scripts": {
    "lint": "eslint src",
    "test": "NODE_ENV=test jest",
    "test:watch": "yarn test --watch",
    "glow": "glow --watch",
    "test:cov": "yarn test --collectCoverage",
//  "watch": "webpack-dev-server --hot --mode development",
//  "build:dev": "webpack --mode development",
//  "build": "NODE_ENV=production webpack --mode production",
    "build:size": "NODE_ENV=production webpack --json | webpack-bundle-size-analyzer",
    "build:ci": "yarn lint && yarn test:cov && yarn build",
    "deploy": "yarn build && netlify deploy",
    "storybook": "start-storybook -p 6006"
  },

保留
watch, build:dev, build は http://pepeky.hatenablog.com/entry/2018/02/27/191944#yarn-run-build- で既に触れた