Lodashインポート時のファイルサイズを削減する

## まとめ

* `import _ from "lodash"`
  * 圧倒的にやめたほうがよい
* `import { get } from "lodash"`
  * ファイルサイズ削減にはならない
  * が、削除しようという意思があるので、そう自分のプロダクトに書いてあったら自分を褒めましょう
* `import get from "lodash/get`
  * この書き方が一番よい
  * 関数数個の import だと、lodash 全体の 20%くらいに収まる気がする
  * すべての関数をインポートすると逆に重くなる（1.5 倍くらい？）
  * 100 くらいのインポートの wrapper ファイル作るくらいならよさそう

## 解析結果

![127.0.0.1_8888_ (4).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/112929/24e52b5c-c7a6-bf13-d033-60303eaf65ec.png)

Gzipするなら144関数インポートしてもよさそう。

-- | StatSize(KB) | ParsedSize(KB) | GzippedSize(KB)
:---: | :---: | :---: | :---:
from "lodash" | 531 | 554 | 96
import 3 func | 70 | 126 | 18
import 22 func | 193 | 315 | 49
import 144 func | 387 | 640 | 95
import 304 func | 546 | 928 | 132

## コード提案

今回の結果を受けて自分がコードをこう変えようと思ったという結果を乗せておきます。
lodashを減らす方向で、直接importせずにまとめたwrapperクラスを作って一つずつ減らしていく方向にしようかなと思い。

```terminal
# _.get みたいな使い方しているところをgrepして必要な関数を特定する
$ grep  "\_\." -r ./src/
```

```js
const arr = `_.pick
_.isNil
_.get
_.pick
_.pick
`.split("\n")

// 一意にする
console.log(Array.from(new Set(a)).join("\n"))
```

```js
// こんな感じの一覧ができる
_.pick
_.isNil
_.get
_.isPlainObject
_.keys
_.snakeCase
_.set
_.isArray
_.camelCase
_.isEmpty
_.cloneDeep
_.assign
_.values
_.isInteger
_.fill
```


```lodashWrapper.js
import pick from "lodash/pick";
import isNil from "lodash/isNil";
import get from "lodash/get";
import isPlainObject from "lodash/isPlainObject";
import keys from "lodash/keys";
import snakeCase from "lodash/snakeCase";
import set from "lodash/set";
import isArray from "lodash/isArray";
import camelCase from "lodash/camelCase";
import isEmpty from "lodash/isEmpty";
import cloneDeep from "lodash/cloneDeep";
import assign from "lodash/assign";
import values from "lodash/values";
import isInteger from "lodash/isInteger";
import fill from "lodash/fill";

export default {
  pick,
  isNil,
  get,
  isPlainObject,
  keys,
  snakeCase,
  set,
  isArray,
  camelCase,
  isEmpty,
  cloneDeep,
  assign,
  values,
  isInteger,
  fill,
};
```

```imported.js
import _ from "lodashWrapper";
_.get('', '');
```

wrapperクラスに一括置換しやすいようにconfigファイル修正したりして `../` 記法をなくして import from 'lodashWrapper' みたいにしてもよさそう。

```webpack.config.js
module.exports = {
  resolve: {
    alias: {
      'lodashWrapper': path.resolve(__dirname, './src/lodashWrapper')
    },
  }
}
```



## 解析コード

自分で触ってみたい人は参考にでも、以下のコードで動くと思います。

```terminal
$ npm i
$ npm run build
$ npm run analyze
```

```terminal
$ brew install tree
$ tree -L 2 -I node_modules/
.
├── dist
│   ├── import30.bundle.js
│   ├── importAll.bundle.js
│   ├── importHalf.bundle.js
│   ├── index1.bundle.js
│   ├── index2.bundle.js
│   └── index3.bundle.js
├── package-lock.json
├── package.json
├── src
│   ├── import30.js
│   ├── importAll.js
│   ├── importHalf.js
│   ├── index1.js
│   ├── index2.js
│   └── index3.js
└── webpack.config.js
```

```package.json
{
  "name": "sample",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "build": "webpack",
    "analyze": "webpack --analyze"
  },
  "keywords": [],
  "author": "",
  "license": "MIT",
  "devDependencies": {
    "webpack": "^5.75.0",
    "webpack-bundle-analyzer": "^4.7.0",
    "webpack-cli": "^5.0.1"
  },
  "dependencies": {
    "lodash": "^4.17.21"
  }
}
```

```webpack.config.js
module.exports = {
  mode: "development", // production
  entry: {
    index1: "./src/index1.js",
    index2: "./src/index2.js",
    index3: "./src/index3.js",
    import30: "./src/import30.js",
    importAll: "./src/importAll.js",
    importHalf: "./src/importHalf.js",
  },
  output: {
    path: __dirname + "/dist",
    filename: "[name].bundle.js",
  },
};
```

```src/index1.js
import _ from "lodash";

export default _;
```

```src/index2.js
import { join, compact, cloneDeep } from "lodash";

export default {
  join,
  compact,
  cloneDeep,
};
```

```src/index3.js
import join from "lodash/join";
import compact from "lodash/compact";
import cloneDeep from "lodash/cloneDeep";

export default {
  join,
  compact,
  cloneDeep,
};
```


<details>
<summary>importAll</summary>

```src/importAll.js
// const _ = require("lodash");
// Object.keys(_).map((key) => {
//   console.log(`import ${key} from "lodash/${key}"`);
// });
// Module not found: Error: Can't resolve 'lodash/noConflict' in '/Users/yk/workspace/sample/src'
// Module not found: Error: Can't resolve 'lodash/runInContext' in '/Users/yk/workspace/sample/src'
// Module not found: Error: Can't resolve 'lodash/VERSION' in '/Users/yk/workspace/sample/src'

import templateSettings from "lodash/templateSettings";
import after from "lodash/after";
import ary from "lodash/ary";
import assign from "lodash/assign";
import assignIn from "lodash/assignIn";
import assignInWith from "lodash/assignInWith";
import assignWith from "lodash/assignWith";
import at from "lodash/at";
import before from "lodash/before";
import bind from "lodash/bind";
import bindAll from "lodash/bindAll";
import bindKey from "lodash/bindKey";
import castArray from "lodash/castArray";
import chain from "lodash/chain";
import chunk from "lodash/chunk";
import compact from "lodash/compact";
import concat from "lodash/concat";
import cond from "lodash/cond";
import conforms from "lodash/conforms";
import constant from "lodash/constant";
import countBy from "lodash/countBy";
import create from "lodash/create";
import curry from "lodash/curry";
import curryRight from "lodash/curryRight";
import debounce from "lodash/debounce";
import defaults from "lodash/defaults";
import defaultsDeep from "lodash/defaultsDeep";
import defer from "lodash/defer";
import delay from "lodash/delay";
import difference from "lodash/difference";
import differenceBy from "lodash/differenceBy";
import differenceWith from "lodash/differenceWith";
import drop from "lodash/drop";
import dropRight from "lodash/dropRight";
import dropRightWhile from "lodash/dropRightWhile";
import dropWhile from "lodash/dropWhile";
import fill from "lodash/fill";
import filter from "lodash/filter";
import flatMap from "lodash/flatMap";
import flatMapDeep from "lodash/flatMapDeep";
import flatMapDepth from "lodash/flatMapDepth";
import flatten from "lodash/flatten";
import flattenDeep from "lodash/flattenDeep";
import flattenDepth from "lodash/flattenDepth";
import flip from "lodash/flip";
import flow from "lodash/flow";
import flowRight from "lodash/flowRight";
import fromPairs from "lodash/fromPairs";
import functions from "lodash/functions";
import functionsIn from "lodash/functionsIn";
import groupBy from "lodash/groupBy";
import initial from "lodash/initial";
import intersection from "lodash/intersection";
import intersectionBy from "lodash/intersectionBy";
import intersectionWith from "lodash/intersectionWith";
import invert from "lodash/invert";
import invertBy from "lodash/invertBy";
import invokeMap from "lodash/invokeMap";
import iteratee from "lodash/iteratee";
import keyBy from "lodash/keyBy";
import keys from "lodash/keys";
import keysIn from "lodash/keysIn";
import map from "lodash/map";
import mapKeys from "lodash/mapKeys";
import mapValues from "lodash/mapValues";
import matches from "lodash/matches";
import matchesProperty from "lodash/matchesProperty";
import memoize from "lodash/memoize";
import merge from "lodash/merge";
import mergeWith from "lodash/mergeWith";
import method from "lodash/method";
import methodOf from "lodash/methodOf";
import mixin from "lodash/mixin";
import negate from "lodash/negate";
import nthArg from "lodash/nthArg";
import omit from "lodash/omit";
import omitBy from "lodash/omitBy";
import once from "lodash/once";
import orderBy from "lodash/orderBy";
import over from "lodash/over";
import overArgs from "lodash/overArgs";
import overEvery from "lodash/overEvery";
import overSome from "lodash/overSome";
import partial from "lodash/partial";
import partialRight from "lodash/partialRight";
import partition from "lodash/partition";
import pick from "lodash/pick";
import pickBy from "lodash/pickBy";
import property from "lodash/property";
import propertyOf from "lodash/propertyOf";
import pull from "lodash/pull";
import pullAll from "lodash/pullAll";
import pullAllBy from "lodash/pullAllBy";
import pullAllWith from "lodash/pullAllWith";
import pullAt from "lodash/pullAt";
import range from "lodash/range";
import rangeRight from "lodash/rangeRight";
import rearg from "lodash/rearg";
import reject from "lodash/reject";
import remove from "lodash/remove";
import rest from "lodash/rest";
import reverse from "lodash/reverse";
import sampleSize from "lodash/sampleSize";
import set from "lodash/set";
import setWith from "lodash/setWith";
import shuffle from "lodash/shuffle";
import slice from "lodash/slice";
import sortBy from "lodash/sortBy";
import sortedUniq from "lodash/sortedUniq";
import sortedUniqBy from "lodash/sortedUniqBy";
import split from "lodash/split";
import spread from "lodash/spread";
import tail from "lodash/tail";
import take from "lodash/take";
import takeRight from "lodash/takeRight";
import takeRightWhile from "lodash/takeRightWhile";
import takeWhile from "lodash/takeWhile";
import tap from "lodash/tap";
import throttle from "lodash/throttle";
import thru from "lodash/thru";
import toArray from "lodash/toArray";
import toPairs from "lodash/toPairs";
import toPairsIn from "lodash/toPairsIn";
import toPath from "lodash/toPath";
import toPlainObject from "lodash/toPlainObject";
import transform from "lodash/transform";
import unary from "lodash/unary";
import union from "lodash/union";
import unionBy from "lodash/unionBy";
import unionWith from "lodash/unionWith";
import uniq from "lodash/uniq";
import uniqBy from "lodash/uniqBy";
import uniqWith from "lodash/uniqWith";
import unset from "lodash/unset";
import unzip from "lodash/unzip";
import unzipWith from "lodash/unzipWith";
import update from "lodash/update";
import updateWith from "lodash/updateWith";
import values from "lodash/values";
import valuesIn from "lodash/valuesIn";
import without from "lodash/without";
import words from "lodash/words";
import wrap from "lodash/wrap";
import xor from "lodash/xor";
import xorBy from "lodash/xorBy";
import xorWith from "lodash/xorWith";
import zip from "lodash/zip";
import zipObject from "lodash/zipObject";
import zipObjectDeep from "lodash/zipObjectDeep";
import zipWith from "lodash/zipWith";
import entries from "lodash/entries";
import entriesIn from "lodash/entriesIn";
import extend from "lodash/extend";
import extendWith from "lodash/extendWith";
import add from "lodash/add";
import attempt from "lodash/attempt";
import camelCase from "lodash/camelCase";
import capitalize from "lodash/capitalize";
import ceil from "lodash/ceil";
import clamp from "lodash/clamp";
import clone from "lodash/clone";
import cloneDeep from "lodash/cloneDeep";
import cloneDeepWith from "lodash/cloneDeepWith";
import cloneWith from "lodash/cloneWith";
import conformsTo from "lodash/conformsTo";
import deburr from "lodash/deburr";
import defaultTo from "lodash/defaultTo";
import divide from "lodash/divide";
import endsWith from "lodash/endsWith";
import eq from "lodash/eq";
import escape from "lodash/escape";
import escapeRegExp from "lodash/escapeRegExp";
import every from "lodash/every";
import find from "lodash/find";
import findIndex from "lodash/findIndex";
import findKey from "lodash/findKey";
import findLast from "lodash/findLast";
import findLastIndex from "lodash/findLastIndex";
import findLastKey from "lodash/findLastKey";
import floor from "lodash/floor";
import forEach from "lodash/forEach";
import forEachRight from "lodash/forEachRight";
import forIn from "lodash/forIn";
import forInRight from "lodash/forInRight";
import forOwn from "lodash/forOwn";
import forOwnRight from "lodash/forOwnRight";
import get from "lodash/get";
import gt from "lodash/gt";
import gte from "lodash/gte";
import has from "lodash/has";
import hasIn from "lodash/hasIn";
import head from "lodash/head";
import identity from "lodash/identity";
import includes from "lodash/includes";
import indexOf from "lodash/indexOf";
import inRange from "lodash/inRange";
import invoke from "lodash/invoke";
import isArguments from "lodash/isArguments";
import isArray from "lodash/isArray";
import isArrayBuffer from "lodash/isArrayBuffer";
import isArrayLike from "lodash/isArrayLike";
import isArrayLikeObject from "lodash/isArrayLikeObject";
import isBoolean from "lodash/isBoolean";
import isBuffer from "lodash/isBuffer";
import isDate from "lodash/isDate";
import isElement from "lodash/isElement";
import isEmpty from "lodash/isEmpty";
import isEqual from "lodash/isEqual";
import isEqualWith from "lodash/isEqualWith";
import isError from "lodash/isError";
import isFinite from "lodash/isFinite";
import isFunction from "lodash/isFunction";
import isInteger from "lodash/isInteger";
import isLength from "lodash/isLength";
import isMap from "lodash/isMap";
import isMatch from "lodash/isMatch";
import isMatchWith from "lodash/isMatchWith";
import isNaN from "lodash/isNaN";
import isNative from "lodash/isNative";
import isNil from "lodash/isNil";
import isNull from "lodash/isNull";
import isNumber from "lodash/isNumber";
import isObject from "lodash/isObject";
import isObjectLike from "lodash/isObjectLike";
import isPlainObject from "lodash/isPlainObject";
import isRegExp from "lodash/isRegExp";
import isSafeInteger from "lodash/isSafeInteger";
import isSet from "lodash/isSet";
import isString from "lodash/isString";
import isSymbol from "lodash/isSymbol";
import isTypedArray from "lodash/isTypedArray";
import isUndefined from "lodash/isUndefined";
import isWeakMap from "lodash/isWeakMap";
import isWeakSet from "lodash/isWeakSet";
import join from "lodash/join";
import kebabCase from "lodash/kebabCase";
import last from "lodash/last";
import lastIndexOf from "lodash/lastIndexOf";
import lowerCase from "lodash/lowerCase";
import lowerFirst from "lodash/lowerFirst";
import lt from "lodash/lt";
import lte from "lodash/lte";
import max from "lodash/max";
import maxBy from "lodash/maxBy";
import mean from "lodash/mean";
import meanBy from "lodash/meanBy";
import min from "lodash/min";
import minBy from "lodash/minBy";
import stubArray from "lodash/stubArray";
import stubFalse from "lodash/stubFalse";
import stubObject from "lodash/stubObject";
import stubString from "lodash/stubString";
import stubTrue from "lodash/stubTrue";
import multiply from "lodash/multiply";
import nth from "lodash/nth";
import noop from "lodash/noop";
import now from "lodash/now";
import pad from "lodash/pad";
import padEnd from "lodash/padEnd";
import padStart from "lodash/padStart";
import parseInt from "lodash/parseInt";
import random from "lodash/random";
import reduce from "lodash/reduce";
import reduceRight from "lodash/reduceRight";
import repeat from "lodash/repeat";
import replace from "lodash/replace";
import result from "lodash/result";
import round from "lodash/round";
import sample from "lodash/sample";
import size from "lodash/size";
import snakeCase from "lodash/snakeCase";
import some from "lodash/some";
import sortedIndex from "lodash/sortedIndex";
import sortedIndexBy from "lodash/sortedIndexBy";
import sortedIndexOf from "lodash/sortedIndexOf";
import sortedLastIndex from "lodash/sortedLastIndex";
import sortedLastIndexBy from "lodash/sortedLastIndexBy";
import sortedLastIndexOf from "lodash/sortedLastIndexOf";
import startCase from "lodash/startCase";
import startsWith from "lodash/startsWith";
import subtract from "lodash/subtract";
import sum from "lodash/sum";
import sumBy from "lodash/sumBy";
import template from "lodash/template";
import times from "lodash/times";
import toFinite from "lodash/toFinite";
import toInteger from "lodash/toInteger";
import toLength from "lodash/toLength";
import toLower from "lodash/toLower";
import toNumber from "lodash/toNumber";
import toSafeInteger from "lodash/toSafeInteger";
import toString from "lodash/toString";
import toUpper from "lodash/toUpper";
import trim from "lodash/trim";
import trimEnd from "lodash/trimEnd";
import trimStart from "lodash/trimStart";
import truncate from "lodash/truncate";
import unescape from "lodash/unescape";
import uniqueId from "lodash/uniqueId";
import upperCase from "lodash/upperCase";
import upperFirst from "lodash/upperFirst";
import each from "lodash/each";
import eachRight from "lodash/eachRight";
import first from "lodash/first";
```

</details>

## 参考

何番煎じとかいうツッコミなしでお願いします。以下サイトの追加検証になります。

* [Lodash のファイルサイズを削減する](https://blog.ryou103.com/post/lodash-reduce-bundle/)