TreeShakingについて
TreeShaking
webpackなどのバンドラーでファイルを出力する際にデッドコード(利用されないコード)除去し、ファイルサイズが肥大化するのを防ぐ(不要なコードが巻き取られない)
条件
ES2015(ES6)のimport/export構文でモジュールを取り扱う(require()、modeule.exportsで記述した場合はTreeShakingされない)
productionモードで実行する
webpack注意書き
TreeShakingが有効かどうかは-- display-used-exports
をつけることで確認できる。
webpack + babel-loaderを利用する場合、設定によってはTreeShakingされないケースがあるため、注意する。
具体的にはbabelの設定ファイルにmodules: false
の設定がないとESモジュール構文が別のモジュールタイプへ変換されてしまうため、上記の条件のとおり設定が必要になる。
{
"presets": [
[
"@babel/preset-env", # 別の機会に
{
"useBuiltIns": "entry" # 別の機会に
},
{
"modules": false
},
]
]
}
Enable transformation of ES module syntax to another module type. Note that cjs is just an alias for commonjs. Setting this to false will preserve ES modules. Use this only if you intend to ship native ES Modules to > browsers. If you are using a bundler with Babel, the default modules: "auto" is always preferred.
書かれている通り初期値はauto
となっている。このautoに関しては以下
The default auto will automatically select false if ES6 module syntax is already supported by the caller, or "commonjs" otherwise.
呼び出し元(target)がES6をサポートしている環境であれば自動的にimport/exportは有効でmodules: false
と同じ意味になる。
コード側でのケア
TreeShakingされない
import Module from "./module"
TreeShakingされる
import { hello } from "./module"
TreeShakingではないがES5モジュール構文でない場合のケア
TreeShakingではないが、不要なコードを読み込まない(有名なlodashだと)
lodashはimport/exportで記述されていないため、TreeShakingが利用できない
必要なモジュールだけ読み込む。一ファイルにlodashの複数メソッドを読み込んでこねくり回すなんてそうないので以下のように必要なモジュールだけ読み込んでおけばいい。
import map from "lodash/map"
import each from "lodash/each"
上記を複数書くと可読性が下がるため、以下のように読み込めるようにして、不要なファイルも除去したい
import { map, each } from 'lodash`
そこで babel-plugin-tranform-imports を利用する方法がある
$ yarn add -D babel-plugin-tranform-imports
.babelrc
{
"plugins": [
["transform-imports", {
"react-bootstrap": {
"transform": "react-bootstrap/lib/${member}",
"preventFullImport": true
},
"lodash": {
"transform": "lodash/${member}",
"preventFullImport": true # 後述
}
}]
]
}
上記リンクままですが、こうすることでimport { map, each } from 'lodash
といった記述ができるようになり、かつ不要なファイルは除去される。
preventFullImport
のオプションはモジュール全体が読み込まれるのを防ぐ設定。この設定を追加してimport _ from 'lodash
とするとトランスパイルでエラーとなる。