Javascript 使用 Node.js require 与 ES6 导入/导出

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/31354559/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 06:35:03  来源:igfitidea点击:

Using Node.js require vs. ES6 import/export

javascriptnode.jsecmascript-6babeljs

提问by kpimov

In a project I'm collaborating on, we have two choices on which module system we can use:

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

  1. Importing modules using require, and exporting using module.exportsand exports.foo.
  2. Importing modules using ES6 import, and exporting using ES6 export
  1. 导入使用的模块require,并使用导出module.exportsexports.foo
  2. 使用 ES6 导入模块,使用 ES6import导出export

Are there any performance benefits to using one over the other? Is there anything else that we should know if we were to use ES6 modules over Node ones?

使用其中一种是否有任何性能优势?如果我们要使用 ES6 模块而不是 Node 模块,还有什么我们应该知道的吗?

采纳答案by Felix Kling

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

使用其中一种是否有任何性能优势?

Keep in mind that there is no JavaScript engine yet that natively supports ES6 modules. You said yourself that you are using Babel. Babel converts importand exportdeclaration to CommonJS (require/module.exports) by default anyway. So even if you use ES6 module syntax, you will be using CommonJS under the hood if you run the code in Node.

请记住,目前还没有原生支持 ES6 模块的 JavaScript 引擎。你自己说你正在使用 Babel。无论如何,Babel 都会默认转换importexport声明为 CommonJS ( require/ module.exports)。因此,即使您使用 ES6 模块语法,如果您在 Node.js 中运行代码,您也会在幕后使用 CommonJS。

There are technical differences between CommonJS and ES6 modules, e.g. CommonJS allows you to load modules dynamically. ES6 doesn't allow this, but there is an API in development for that.

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

Since ES6 modules are part of the standard, I would use them.

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

回答by Amit

There are several usage / capabilities you might want to consider:

您可能需要考虑多种用途/功能:

Require:

要求:

  • You can have dynamic loading where the loaded module name isn't predefined /static, or where you conditionally load a module only if it's "truly required" (depending on certain code flow).
  • Loading is synchronous. That means if you have multiple requires, they are loaded and processed one by one.
  • 您可以在加载的模块名称未预定义/静态的情况下进行动态加载,或者仅在“真正需要”(取决于某些代码流)时有条件地加载模块。
  • 加载是同步的。这意味着如果您有多个requires,它们将被一一加载和处理。

ES6 Imports:

ES6 导入:

  • You can use named imports to selectively load only the pieces you need. That can save memory.
  • Import can be asynchronous (and in current ES6 Module Loader, it in fact is) and can perform a little better.
  • 您可以使用命名导入来选择性地仅加载您需要的部分。这样可以节省内存。
  • 导入可以是异步的(在当前的 ES6 模块加载器中,它实际上是)并且可以执行得更好一点。

Also, the Require module system isn't standard based. It's is highly unlikely to become standard now that ES6 modules exist. In the future there will be native support for ES6 Modules in various implementations which will be advantageous in terms of performance.

此外,Require 模块系统不是基于标准的。既然存在 ES6 模块,它就不太可能成为标准。未来将在各种实现中原生支持 ES6 模块,这将在性能方面具有优势。

回答by snozza

The main advantages are syntactic:

主要优点是语法:

  • More declarative/compact syntax
  • ES6 modules will basically make UMD (Universal Module Definition) obsolete - essentially removes the schism between CommonJS and AMD (server vs browser).
  • 更具声明性/紧凑的语法
  • ES6 模块基本上会使 UMD(通用模块定义)过时——基本上消除了 CommonJS 和 AMD(服务器与浏览器)之间的分歧。

You are unlikely to see any performance benefits with ES6 modules. You will still need an extra library to bundle the modules, even when there is full support for ES6 features in the browser.

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

回答by prosti

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

使用其中一种是否有任何性能优势?

The current answer is no, because none of the current browser engines implements import/exportfrom the ES6 standard.

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

Some comparison charts http://kangax.github.io/compat-table/es6/don't take this into account, so when you see almost all greens for Chrome, just be careful. importkeyword from ES6 hasn't been taken into account.

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

In other words, current browser engines including V8 cannot import new JavaScript filefrom the main JavaScript filevia any JavaScript directive.

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

( We may be still just a few bugs awayor years away until V8 implements that according to the ES6 specification. )

(在V8 根据 ES6 规范实现它之前,我们可能还有几个错误或几年之后。)

This documentis what we need, and this documentis what we must obey.

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

And the ES6 standard said that the module dependencies should be there before we read the module like in the programming language C, where we had (headers) .hfiles.

ES6 标准规定,在我们读取模块之前,模块依赖关系应该存在,就像在编程语言 C 中一样,我们有(头文件).h文件。

This is a good and well-tested structure, and I am sure the experts that created the ES6 standard had that in mind.

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

This is what enables Webpack or other package bundlers to optimize the bundle in some specialcases, and reduce some dependencies from the bundle that are not needed. But in cases we have perfect dependencies this will never happen.

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

It will need some time until import/exportnative support goes live, and the requirekeyword will not go anywhere for a long time.

import/export原生支持上线还需要一些时间,而且require关键字在很长一段时间内都不会去任何地方。

What is require?

什么是require

This is node.jsway to load modules. ( https://github.com/nodejs/node)

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

Node uses system-level methods to read files. You basically rely on that when using require. requirewill end in some system call like uv_fs_open(depends on the end system, Linux, Mac, Windows) to load JavaScript file/module.

Node 使用系统级方法来读取文件。使用require. require将在一些系统调用uv_fs_open(取决于最终系统、Linux、Mac、Windows)中结束以加载 JavaScript 文件/模块。

To check that this is true, try to use Babel.js, and you will see that the importkeyword will be converted into require.

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

enter image description here

在此处输入图片说明

回答by Lee Benson

Using ES6 modules can be useful for 'tree shaking'; i.e. enabling Webpack 2, Rollup (or other bundlers) to identify code paths that are not used/imported, and therefore don't make it into the resulting bundle. This can significantly reduce its file size by eliminating code you'll never need, but with CommonJS is bundled by default because Webpack et al have no way of knowing whether it's needed.

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

This is done using static analysis of the code path.

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

For example, using:

例如,使用:

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

... gives the bundler a hint that package.anotherPartisn't required (if it's not imported, it can't be used- right?), so it won't bother bundling it.

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

To enable this for Webpack 2, you need to ensure that your transpiler isn't spitting out CommonJS modules. If you're using the es2015plug-in with babel, you can disable it in your .babelrclike so:

要为 Webpack 2 启用此功能,您需要确保您的转译器不会输出 CommonJS 模块。如果你使用es2015babel 插件,你可以.babelrc像这样禁用它:

{
  "presets": [
    ["es2015", { modules: false }],
  ]
}

Rollupand others may work differently - view the docs if you're interested.

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

回答by Meet Zaveri

When it comes to async or maybe lazy loading, then import ()is much more powerful. See when we require the component in asynchronous way, then we use importit in some async manner as in constvariable using await.

当涉及异步或延迟加载时,那么import ()它的功能要强大得多。看看我们何时以异步方式需要组件,然后我们import以某种异步方式使用它,就像在const变量 using 中一样await

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

Or if you want to use require()then,

或者如果你想使用require()

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

Thing is import()is actually async in nature. As mentioned by neehar venugopal in ReactConf, you can use it to dynamically load react components for client side architecture.

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

Also it is way better when it comes to Routing. That is the one special thing that makes network log to download a necessary part when user connects to specific website to its specific component. e.g. login page before dashboard wouldn't download all components of dashboard. Because what is needed current i.e. login component, that only will be downloaded.

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

Same goes for export: ES6 exportare exactly same as for CommonJS module.exports.

同样适用于export:ES6export与 CommonJS 完全相同module.exports

NOTE- If you are developing a node.js project, then you have to strictly use require()as node will throw exception error as invalid token 'import'if you will use import. So node does not support import statements.

注意- 如果你正在开发一个 node.js 项目,那么你必须严格使用,require()因为 node 会抛出异常错误,invalid token 'import'就像你将使用import. 所以 node 不支持 import 语句。

UPDATE - As suggested by Dan Dascalescu: Since v8.5.0 (released Sep 2017), node --experimental-modules index.mjslets you use importwithout Babel. You can (and should) also publish your npm packages as native ESModule, with backwards compatibilityfor the old requireway.

更新 - 正如Dan Dascalescu所建议的:自 v8.5.0(2017 年 9 月发布)以来,node --experimental-modules index.mjs让您import无需使用Babel。您还可以(并且应该)将您的 npm 包发布为原生 ESModule,并具有对旧require方式的向后兼容性

See this for more clearance where to use async imports - https://www.youtube.com/watch?v=bb6RCrDaxhw

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

回答by isysd

The most important thing to know is that ES6 modules are, indeed, an official standard, while CommonJS (Node.js) modules are not.

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

In 2019, ES6 modules are supported by 84%of browsers. While Node.js puts them behind an --experimental-modulesflag, there is also a convenient node package called esm, which makes the integration smooth.

2019 年,84%的浏览器支持 ES6 模块。虽然Node.js的把他们身后的--experimental模块的标志,也有一个方便的节点包叫ESM,这使得整合顺利。

Another issue you're likely to run into between these module systems is code location. Node.js assumes source is kept in a node_modulesdirectory, while most ES6 modules are deployed in a flat directory structure. These are not easy to reconcile, but it can be done by hacking your package.jsonfile with pre and post installation scripts. Here is an example isomorphic moduleand an articleexplaining how it works.

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

回答by chandoo

I personally use import because, we can import the required methods, members by using import.

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

import {foo, bar} from "dep";

FileName:dep.js

文件名:dep.js

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

Credit goes to Paul Shan. More info.

归功于 Paul Shan。更多信息

回答by Hasan Sefa Ozalp

As of right now ES6 import, export is always compiled to CommonJS, so there is no benefitusing one or other. Although usage of ES6 is recommended since it should be advantageous when native support from browsers released. The reason being, you can import partials from one file while with CommonJS you have to require all of the file.

就目前 ES6 导入而言,导出始终编​​译为 CommonJS,因此使用其中之一没有任何好处。虽然推荐使用 ES6,因为当浏览器的本机支持发布时它应该是有利的。原因是,您可以从一个文件导入部分文件,而使用 CommonJS,您必须需要所有文件。

ES6 → import, export default, export

ES6 → import, export default, export

CommonJS → require, module.exports, exports.foo

CommonJS → require, module.exports, exports.foo

Below is common usage of those.

以下是这些的常见用法。

ES6 export default

ES6 导出默认

// hello.js
function hello() {
  return 'hello'
}
export default hello

// app.js
import hello from './hello'
hello() // returns hello


ES6 export multiple and import multiple

ES6导出多个导入多个

// hello.js
function hello1() {
  return 'hello1'
}
function hello2() {
  return 'hello2'
}
export { hello1, hello2 }

// app.js
import { hello1, hello2 } from './hello'
hello1()  // returns hello1
hello2()  // returns hello2


CommonJS module.exports

CommonJS 模块.exports

// hello.js
function hello() {
  return 'hello'
}
module.exports = hello

// app.js
const hello = require('./hello')
hello()   // returns hello


CommonJS module.exports multiple

CommonJS module.exports 多个

// hello.js
function hello1() {
  return 'hello1'
}
function hello2() {
  return 'hello2'
}
module.exports = {
  hello1,
  hello2
}

// app.js
const hello = require('./hello')
hello.hello1()   // returns hello1
hello.hello2()   // returns hello2

回答by l00k

Not sure why (probably optimization - lazy loading?) is it working like that, but I have noticed that importmay not parse code if imported modules are not used.
Which may not be expected behaviour in some cases.

不知道为什么(可能是优化 - 延迟加载?)它是这样工作的,但我注意到import如果不使用导入的模块可能无法解析代码。
在某些情况下,这可能不是预期的行为。

Take hated Foo class as our sample dependency.

将讨厌的 Foo 类作为我们的示例依赖项。

foo.ts

export default class Foo {}
console.log('Foo loaded');

For example:

例如:

index.ts

索引.ts

import Foo from './foo'
// prints nothing

index.ts

索引.ts

const Foo = require('./foo').default;
// prints "Foo loaded"

index.ts

索引.ts

(async () => {
    const FooPack = await import('./foo');
    // prints "Foo loaded"
})();

On the other hand:

另一方面:

index.ts

索引.ts

import Foo from './foo'
typeof Foo; // any use case
// prints "Foo loaded"