关于javascript:使用Node.js需要与ES6导入/导出

Using Node.js require vs. ES6 import/export

在我正在合作的项目中,我们有两个选择,我们可以使用哪个模块系统:

  • 使用require导入模块,并使用module.exportsexports.foo导出。
  • 使用ES6 import导入模块,并使用ES6 export导出
  • 使用一个优于另一个是否有任何性能优势? 如果我们使用ES6模块而不是Node模块,还有什么我们应该知道的吗?


    Are there any performance benefits to using one over the other?

    请记住,还没有本身支持ES6模块的JavaScript引擎。你说你自己在使用巴别塔。无论如何,Babel默认将importexport声明转换为CommonJS(require / module.exports)。因此,即使您使用ES6模块语法,如果您在Node中运行代码,也将使用CommonJS。

    CommonJS和ES6模块之间存在技术差异,例如: CommonJS允许您动态加载模块。 ES6不允许这样做,但是有一个API正在开发中。

    由于ES6模块是标准的一部分,我会使用它们。


    您可能需要考虑以下几种用法/功能:

    要求:

    • 您可以在加载的模块名称不在的地方进行动态加载
      预定义/静态,或仅在有条件地加载模块的情况下
      它是"真正需要的"(取决于某些代码流)。
    • 加载是
      同步。这意味着如果你有多个require,它们就是
      一个一个地加载和处理。

    ES6进口:

    • 您可以使用
      命名导入以选择性地仅加载您需要的部分。这样可以
      节省内存。
    • 导入可以是异步的(在当前的ES6模块加载器中,它实际上是)并且可以执行得更好。

    此外,Require模块系统不是基于标准的。现在ES6模块存在的可能性很小。将来,在各种实现中将对ES6模块提供原生支持,这在性能方面将是有利的。


    主要优点是句法:

    • 更多声明/紧凑语法
    • ES6模块基本上会使UMD(通用模块定义)过时 - 基本上消除了CommonJS和AMD(服务器与浏览器)之间的分裂。

    您不太可能看到ES6模块的任何性能优势。即使在浏览器中完全支持ES6功能,您仍然需要一个额外的库来捆绑模块。


    Are there any performance benefits to using one over the other?

    目前的答案是否定的,因为当前的浏览器引擎都没有从ES6标准实现import/export

    一些比较图表http://kangax.github.io/compat-table/es6/不考虑这一点,所以当你看到Chrome的几乎所有绿色时,请小心。 ES6中的import关键字未被考虑在内。

    换句话说,包括V8在内的当前浏览器引擎无法通过任何JavaScript指令从主JavaScript文件中导入新的JavaScript文件。

    (根据ES6规范,在V8实现之前,我们可能仍然只是几个或几年之后。)

    我们需要这份文件,这份文件是我们必须遵守的。

    并且ES6标准表示模块依赖性应该在我们读取模块之前就像在编程语言C中那样,我们有(头文件).h文件。

    这是一个良好且经过良好测试的结构,我相信创建ES6标准的专家会考虑到这一点。

    这使得Webpack或其他软件包捆绑器能够在某些特殊情况下优化软件包,并减少捆绑软件中不需要的依赖关系。但是如果我们有完美的依赖关系,这将永远不会发生。

    它需要一些时间,直到import/export本机支持生效,并且require关键字将不会长时间在任何地方。

    什么是require

    这是加载模块的node.js方式。 (https://github.com/nodejs/node)

    Node使用系统级方法来读取文件。使用require时,你基本上都依赖它。 require将以某些系统调用结束,如uv_fs_open(取决于终端系统,Linux,Mac,Windows)来加载JavaScript文件/模块。

    要检查这是否属实,请尝试使用Babel.js,您将看到import关键字将转换为require

    enter image description here


    使用ES6模块可以用于"树摇动";即启用Webpack 2,Rollup(或其他捆绑包)以识别未使用/导入的代码路径,因此不会将其放入生成的捆绑包中。这可以通过消除您永远不需要的代码来显着减少其文件大小,但默认情况下捆绑了CommonJS,因为Webpack等人无法知道是否需要它。

    这是使用代码路径的静态分析完成的。

    例如,使用:

    1
    import { somePart } 'of/a/package';

    ...给捆绑者一个package.anotherPart不需要的提示(如果它没有导入,它不能被使用 - 对吗?),所以它不会打扰捆绑它。

    要为Webpack 2启用此功能,您需要确保您的转换器不会吐出CommonJS模块。如果您使用带有babel的es2015插件,可以在.babelrc中禁用它,如下所示:

    1
    2
    3
    4
    5
    {
     "presets": [
        ["es2015", { modules: false }],
      ]
    }

    汇总和其他人可能会有不同的工作方式 - 如果您有兴趣,请查看文档。


    当涉及异步或延迟加载时,import ()更强大。看看我们何时以异步方式需要组件,然后我们以const变量使用await以某种异步方式使用import

    1
    const module = await import('./module.js');

    或者如果你想使用require()那么,

    1
    const converter = require('./converter');

    事实import()实际上是异步的。正如ReactConf中的neehar venugopal所提到的,您可以使用它来动态加载客户端架构的反应组件。

    在路由方面也更好。当用户将特定网站连接到其特定组件时,这是使网络日志下载必要部分的一个特殊事情。例如仪表板之前的登录页面不会下载仪表板的所有组件。因为需要当前即登录组件,只会下载。

    export也是如此:ES6 export与CommonJS module.exports完全相同。

    注 - 如果您正在开发node.js项目,那么您必须严格使用require(),因为如果您将使用import,节点将抛出异常错误invalid token 'import'。因此节点不支持import语句。

    更新 - 正如Dan Dascalescu所建议的:自v8.5.0(2017年9月发布)以来,node --experimental-modules index.mjs允许您使用import而不使用Babel。您可以(也应该)将您的npm包发布为本机ESModule,具有旧require方式的向后兼容性。

    有关使用异步导入的更多信息,请参阅此内容 - https://www.youtube.com/watch?v=bb6RCrDaxhw


    最重要的是要知道ES6模块确实是官方标准,而CommonJS(Node.js)模块则不是。

    在2019年,84%的浏览器支持ES6模块。 虽然Node.js将它们放在--experimental-modules标志后面,但是还有一个方便的节点包叫做esm,这使得集成变得平滑。

    您可能在这些模块系统之间遇到的另一个问题是代码位置。 Node.js假定源保存在node_modules目录中,而大多数ES6模块部署在平面目录结构中。 这些并不容易协调,但可以通过使用安装前和安装后脚本来破解package.json文件来完成。 这是一个示例同构模块和一篇解释它是如何工作的文章。


    我个人使用import,因为我们可以使用import导入所需的方法,成员。

    1
    import {foo, bar} from"dep";

    FileName:dep.js

    1
    2
    export foo function(){};
    export const bar = 22

    归功于Paul Shan。更多信息。