先日、業務中にこんなコードに出会いました。
import _ from "lodash";
// ここは適当なオブジェクトです
const user = {
username: {
first: "taro",
last: "yamada",
},
};
const userCopy = _.cloneDeep(user);
あれ?この書き方ってtree shaking効くのかな?
そういえばlodashって、lodash-esと2パターンあったけど、何が違うんだっけ?
と思ったので、試してみました。
結論
先に結論ですが、こうなりました。
lodashはES Module形式で書かれていないため、tree shakingを使用するにはlodash-esを使用する必要がありました。
パターン | ファイルサイズ | tree shaking |
---|---|---|
lodashで関数を指定せずimport | 69.5kb | × |
lodashで関数を指定してimport | 69.5kb | × |
lodash-esで関数を指定せずimport | 81.4kb | × |
lodash-esで関数を指定してimport | 12.1kb | ○ |
検証
実際に以下の通り試してみました。
ファイル構成
app
┣ node_modules
┣ dist
┃ ┗ bundle.js
┣ src
┃ ┗ app.js
┣ package.json
┣ package-lock.json
┗ webpack.config.js
webpackの設定
const path = require("path");
module.exports = {
mode: "production",
entry: "./src/app.js",
output: {
filename: "bundle.js",
path: path.join(__dirname, "dist"),
},
};
先に必要なライブラリを入れておきます。
npm i webpack webpack-cli lodash lodash-es
パターン1. lodashで関数を指定せずimport
前述の通り、そもそもlodashはES Moduleに対応していないため、関数指定の有無に関わらずtree shakingが効きません。
import _ from "lodash";
const user = {
username: {
first: "taro",
last: "yamada",
},
};
const userCopy = _.cloneDeep(user);
productionモードでバンドルします。
npx webpack
69.5kbでした。
パターン2. lodashで関数を指定せずimport
import { cloneDeep } from "lodash";
const user = {
username: {
first: "taro",
last: "yamada",
},
};
const userCopy = cloneDeep(user);
tree shakingが効かないため、パターン1と同じ結果となりました。
パターン3. lodash-esで関数を指定せずimport
import _ from "lodash-es";
const user = {
username: {
first: "taro",
last: "yamada",
},
};
const userCopy = _.cloneDeep(user);
lodash-esはES Module形式なのでtree shakingに対応していますが、バンドルサイズはlodashより増えています。
tree shakingが出来ていないようです。
パターン4. lodash-esで関数を指定してimport
import { cloneDeep } from "lodash-es";
const user = {
username: {
first: "taro",
last: "yamada",
},
};
const userCopy = cloneDeep(user);
最後にこちらのパターンですが、明らかにバンドルサイズが小さいですね。
tree shakingが成功しました。
まとめ
以下の事が分かりました。
- lodashではなくlodash-esを使用する
- 使用する関数のみimportする
誤り等ございましたら、恐縮ですがご指摘いただけますと幸いです。