何时在Node.JS中使用“import”和“require”?

10

当我查看Node.JS中“path”模块的文档时,文档明确指出您必须通过以下方式导入该模块:const path = require('path');

当我查看Node.JS中文件系统“fs”模块的文档时,它没有提到要执行const fs = require('fs);相反,它谈论了使用导入方法import { mkdir } from 'fs';但是当我尝试使用导入方法时出现语法错误:SyntaxError: Cannot use import statement outside a module

使用const fs = require('fs');可以正常工作,但我想确保我的代码一致/正确,因此应该使用哪个并解释原因?如果不需要使用某些模块很重要,我想找出如何使其正常运行。


2
这个回答解决了你的问题吗?“require(x)”和“import x”的区别。 - esqew
2个回答

20

概述

import 是Javascript语言在nodejs和浏览器中的未来,用于ECMAScript模块(ESM模块)加载其他模块,无论是静态还是动态。

require() 是nodejs加载模块的最初方式,用于CommonJS模块。require() 在nodejs中有本地支持,但在浏览器中不支持(尽管有一些第三方库提供了类似于require的模块加载器)。

选择一种

通常情况下,您希望选择一种机制并将其用于整个项目,因为混合/匹配会使事情变得复杂。 import 在nodejs中曾经有过一些成长的烦恼,但现在的实现已经相当完整。 无论哪种方式,您可能会遇到一些不属于您选择的项目类型的模块,并且必须学习如何处理它们。

如果我要开始一个预计会持续很长时间并且我将在接下来的几年内工作的新项目,我会选择使用ESM模块和import,因为这是Javascript模块的当前/未来架构。

如果我正在编写一个依赖于一堆只在CommonJS中可用的脚本的快速“完成它”的脚本,我可能会使用CommonJS require()

如果我要编写我想在nodejs和浏览器之间共享的模块,我会选择ESM,因为它在两者中都受支持。

你的问题

当我查看Node.JS文件系统模块“fs”的文档时,它没有提到使用const fs = require('fs);,而是讨论使用import方法import { mkdir } from 'fs'。

当前版本的fs文档可以让您选择代码示例是否显示CJS或ESM模块语法。显然您正在查看以ESM语法显示的文档,您可以进行切换。两者都可以使用。

当您在文档中看到此图像enter image description here时,这意味着您可以将文档中的示例代码从CJS切换到ESM或反向切换。

SyntaxError: Cannot use import statement outside a module

在nodejs中,您必须以某种方式告诉nodejs您的顶级模块是CJS还是ESM。默认情况下,.js文件被视为CJS,而.mjs文件被视为ESM。如果nodejs认为您有一个CJS文件,则无法使用import(那只适用于ESM模块)。

你也可以修改控制特定脚本的package.json文件(通过添加"type": "module"),如果想要将您的文件强制转换为ESM模块,那么就可以使用.js文件作为ESM模块。

使用const fs = require('fs');也完全没问题

是的,如果nodejs认为你正在使用CJS模块。

我想确保我的代码一致/正确,所以我该使用哪一个模块类型?为什么?

关于何时选择每个模块类型,请参见我的先前解释。如果您只是在学习,请学习如何告诉nodejs您正在使用ESM模块并使用import,因为这是该语言的未来方向。require()不会很快消失,但如果我们开始看到仅支持较新的ESM语法并且只能从ESM模块加载的新NPM包(共享模块),那将不足为奇。通过一些小心的工作,可以制作一个既可以通过ESM模块又可以通过CJS模块加载的可共享模块。此外,ESM模块正在获得一些功能(例如顶层await),而CJS模块永远不会获得这些功能。

更多细节

有关详细信息,建议阅读此文章:

Node模块之争-为什么CommonJS和ESM模块无法相处


1
在 package.json 中添加 "type": "module" 可以启用导入功能,但会完全取消 Node 包装器 exports, require, module, __filename, __dirname。我的 Node.JS 文档中没有 CJS 和 ESM 切换选项。你发的链接非常有帮助。我是新手,正在努力理解这些东西。这很困难。自 16 年前使用 PHP/MySQL 以来就没有编写过任何代码了。 - Mickey
1
@Mickey - 是的,ESM模块没有modulerequire__filename__dirname。你需要使用import代替require,使用export代替module.exports,而__filename__dirname可以从import.meta.url中合成。ESM模块是一种不同类型的模块,使用时需要遵循它们的规则。 - jfriend00
@Mickey - 看这里:https://nodejs.org/api/fs.html#file-system。你应该看到可以切换示例代码的开关。它只适用于某些方法,而不是全部。 - jfriend00
我现在正在学习Node.JS。我讨厌有很多“随心所欲仍然有效”的实例。我喜欢编程语言只有一种方法的情况,所以这很令人困惑。我可以使用100%的CJS或100%的ESM,还是必须同时使用两者? - Mickey
1
@jfriend00,我在我的nodejs代码中混合使用importrequire有一个非常简单的原因,我需要使用debugjs,它只支持cjs,在我的esm代码中,我总是添加import { createRequire } from "module"; const require = createRequire(import.meta.url);来使用debugjs,到目前为止,我还没有遇到任何问题。 - Qiulang
@jfriend00,即使在我的ts代码中,我也混合使用importrequire来使用debugjs,因为我在这里提出了一个问题 https://dev59.com/QM77oIgBc1ULPQZFDygF 你能看一下吗? - Qiulang

1
正如 @jfriend00 所提到的,即使您不想混合使用 require 和 import,但有些情况下您需要的某些包无法作为模块导入。在这种情况下,您可以在 require 语句之前使用以下代码。
import { createRequire } from "module";
const require = createRequire(import.meta.url);

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