正确的导入lodash方式

270

我在下方收到一条Pull Request反馈,想知道导入lodash的正确方式是哪种?

你最好这样导入:import has from 'lodash/has'.. 对于早期版本的lodash(v3),它本身就很重,我们应该只导入一个特定的模块/函数,而不是整个lodash库。不确定新版本(v4)如何处理。

import has from 'lodash/has';

对比

import { has } from 'lodash';

谢谢


7
请参考这篇答案,更深入地讨论为什么后者在某些环境中(例如Webpack)仍然可以实现性能优化。这是由于使用了静态分析和树摇晃技术。 - Patrick Roberts
这个回答解决了你的问题吗?如何导入单个 Lodash 函数? - Henke
10个回答

328

import has from 'lodash/has'; 更好,因为lodash将所有函数都保存在单个文件中,所以不必导入整个100k的'lodash'库,只需导入可能只有2k大小的lodash的has函数即可。


2
@GeorgeKatsanos 你只需要导入你想使用的函数,不需要'_'。 - Bill
10
'lodash/has' 并不是一个单独的包。在常规 'lodash' 包的根目录中有一个名为 has.js 的文件,使用 import has from 'lodash/has' (或 const has = require ('lodash/has'))将加载该文件。在 npm 上确实有单独的方法包,但它们使用 "点语法": 'lodash.has'。如果您不介意为每个使用的方法安装单独的包(可能会导致您的 package.json 文件变得非常庞大),这也是一种有效的方法。 - daemone
95
我必须在这里补充说明,如果您使用webpack 2或支持树摇的打包工具rollup,则import { has } from 'lodash'将以相同的方式工作,因为其余部分将被剥离。 - Alex JM
3
@PDN,webpack 2 的 tree shaking 功能应该可以自动为您完成这个任务。 - Bill
30
与其他一些方法不同,我的“摇树”功能无法使用更明显的语法,只有在我切换到lodash-es并使用“import has from 'lodash-es/has'”语法后才能完全实现“摇树”。文件大小从526KB降至184KB,详见 https://dev59.com/TFgQ5IYBdhLWcg3w7ofY。 - Brandon Culley
显示剩余11条评论

153

如果您正在使用 webpack 4,则以下代码是可树摇的。

import { has } from 'lodash-es';

需要注意的要点:

  1. CommonJS模块不支持tree shaking,因此你应该使用 lodash-es,它是作为ES模块导出的Lodash库,而不是lodash(CommonJS)。

  2. lodash-es的package.json包含"sideEffects": false,这通知webpack 4该包中的所有文件都没有副作用(参见https://webpack.js.org/guides/tree-shaking/#mark-the-file-as-side-effect-free)。

  3. 这些信息对于tree shaking至关重要,因为模块打包程序不会tree shake可能包含副作用的文件,即使其导出的成员在任何地方也没有被使用。

编辑

从版本1.9.0开始,Parcel也支持"sideEffects": false,因此import { has } from 'lodash-es';在Parcel中也是支持tree shaking的。 它还支持tree shaking CommonJS模块,尽管根据我的实验,ES模块的tree shaking可能比CommonJS更有效率。


我把所有的lodash导入都转换成了import { ... } from 'lodash-es';,但我的打包文件仍然包含整个库。 - Isaac Pak
3
请确保您没有将ES模块转换为CommonJS格式。如果您正在使用TypeScript,您需要将编译器选项--module设置为es6es2015esnext - kimamula
很遗憾,目前无法在Jest中使用lodash-es: https://github.com/facebook/jest/issues/4842#issuecomment-491434065 - apollo
3
在使用 webpack-4 时,import has from 'lodash-es/has'import {has} from 'lodash-es' 这两种变体都会进行树摇优化。 - Legends
在使用jest时无法正常工作:https://github.com/facebook/create-react-app/issues/5241 - Victor
显示剩余4条评论

26

Import specific methods inside of curly brackets

import { map, tail, times, uniq } from 'lodash';

Pros:

  • Only one import line(for a decent amount of functions)
  • More readable usage: map() instead of _.map() later in the javascript code.

Cons:

  • Every time we want to use a new function or stop using another - it needs to be maintained and managed

摘自:正确导入Lodash库的方法-基准测试一文,作者为Alexander Chertkov。


2
感谢您提供有用的答案。然而,我喜欢使用_.map()语法来明确表示正在使用外部库。import _ from 'lodash'与您的建议同样有效吗?或者还有其他方法可以使用这种语法吗? - Toivo Säwén
2
@ToivoSäwén,我完全同意,并且也更喜欢显式的_.map()语法。你能找到一种在进行ES6导入和摇树优化时仍然保持它的方法吗? - Raj
这个答案看起来像是从https://www.blazemeter.com/blog/the-correct-way-to-import-lodash-libraries-a-benchmark复制粘贴过来的。如果是这样,最好提供相应的来源说明。 - Lacek
1
import { map as _map, tail } from 'lodash' - McKay
1
链接的文章实际上指出了最小的捆绑包大小,没有一些特殊的插件,就是“一个一个地或‘模块’导入”。例如:import map from "lodash/map" - TurtleTread

11

你可以将它们导入为

import {concat, filter, orderBy} from 'lodash';

或者作为

import concat from 'lodash/concat';
import orderBy from 'lodash/orderBy';
import filter from 'lodash/filter';
第二个比第一个优化得多,因为它只加载所需的模块。
然后像这样使用。
pendingArray: concat(
                    orderBy(
                        filter(payload, obj => obj.flag),
                        ['flag'],
                        ['desc'],
                    ),
                    filter(payload, obj => !obj.flag),

4
如果您正在使用babel,应该查看babel-plugin-lodash,它会为您挑选您正在使用的lodash部分,减少麻烦和更小的捆绑包。
它有一些限制条件
  • 您必须使用ES2015导入来加载Lodash
  • Babel < 6和Node.js < 4不受支持
  • 链式序列不受支持。请参阅此博客文章以获取替代方案。
  • 模块化方法包不受支持

2

我认为这个答案可以轻松地用在任何项目中,并且只需付出较少的努力即可获得最佳结果。

对于Typescript用户,使用方法如下:

// lodash.utils.ts
export { default as get } from 'lodash/get';
export { default as isEmpty } from 'lodash/isEmpty';
export { default as isNil } from 'lodash/isNil';
...

它可以像导入lodash一样使用:

//some-code.ts
import { get } from './path/to/lodash.utils'

export static function getSomething(thing: any): any {
    return get(thing, 'someSubField', 'someDefaultValue')
}

或者,如果您希望保留_以避免冲突(例如rxjs中的maplodash),也可以这样做。

//some-other-code.ts
import * as _ from './path/to/lodash.utils'

export static function getSomething(thing: any): any {
    return _.get(thing, 'someSubField', 'someDefaultValue')
}

更新: 似乎正确的导出方式是:
export * as get from 'lodash/get';
export * as isEmpty from 'lodash/isEmpty';
export * as isNil from 'lodash/isNil';
...

但是与@types/lodash发生了奇怪的冲突,我已经删除了这个类型包,因为我会得到以下错误:

模块“"/../project/node_modules/@types/lodash/cloneDeep"”使用'export =',不能与'export *'一起使用.ts(2498)

更新:

经过一些研究,我将tsconfig.jsonesModuleInterop特性更改为true,并允许我执行以下操作:

import get from 'lodash/get';
import isEmpty from 'lodash/isEmpty';
import isNil from 'lodash/isNil';
...

export { get, isEmpty, isNil, ... };

请注意,这会影响到您在项目中定义为import * as lib from 'lib'的所有导入。请按照文档说明确保适用于您。

2

我只是将它们放在自己的文件中,并为节点和webpack导出:

// lodash-cherries.js
module.exports = {
  defaults: require('lodash/defaults'),
  isNil: require('lodash/isNil'),
  isObject: require('lodash/isObject'),
  isArray: require('lodash/isArray'),
  isFunction: require('lodash/isFunction'),
  isInteger: require('lodash/isInteger'),
  isBoolean: require('lodash/isBoolean'),
  keys: require('lodash/keys'),
  set: require('lodash/set'),
  get: require('lodash/get'),
}

0

import { cloneDeep, groupBy } from 'lodash';

我认为当您不需要使用 _ 将数组转换为 lodash 对象时,这会更简单。

const groupData = groupBy(expandedData, (x) => x.room.name);


-2

对于那些想继续使用下划线的人,只需像这样导入它们:

import groupBy from 'lodash/groupBy';
import filter from 'lodash/filter';
import get from 'lodash/get';

window._ = {groupBy, filter, get};

-7

我认为更简洁的导入lodash的方法就是这样:

import _ from 'lodash'

然后你可以使用任何你想要的东西,只需使用这个下划线就像这样:

_.has()

如果你这样做,lodash将会加载整个包。这对应用程序捆绑包来说是很重的。请参考文档。 - Guillaume Piedigrossi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接