如何在 Node.js 中使用 ES6 导入?

How can I use an ES6 import in Node.js?

我试图在 Node.js 中掌握 ES6 导入的窍门,并尝试使用此示例中提供的语法:

Cheatsheet Link

我正在查看 the support table,但无法找到支持新导入语句的版本(我尝试查找文本 import/require)。我目前正在 运行ning Node.js 8.1.2 并且还相信,由于备忘单指的是 .js 文件,因此它应该适用于 .js 文件。

正如我 运行 代码(取自备忘单的第一个示例):

import { square, diag } from 'lib';

我收到错误:

SyntaxError: Unexpected token import.

对我尝试导入的库的引用:

//------ lib.js ------
export const sqrt = Math.sqrt;
export function square(x) {
    return x * x;
}
export function diag(x, y) {
    return sqrt(square(x) + square(y));
}

我缺少什么以及如何让 node 识别我的 import 声明?

Node.js has included experimental support for ES6 support. Read more about here: https://nodejs.org/docs/latest-v13.x/api/esm.html#esm_enabling.

TLDR;

Node.js >= v13

在 Node.js 13 及更高版本中非常简单。您需要:

  • 使用 .mjs 扩展名保存文件,或
  • 在最近的package.json中添加{ "type": "module" }

您只需执行上述其中一项即可使用 ECMAScript 模块。

Node.js <= v12

如果您使用的是 Node.js 版本 9.6 - 12,保存 ES6 模块文件 .mjs 扩展名和 运行 喜欢:

node --experimental-modules my-app.mjs

你可以试试esm.

这里是一些介绍:esm

如果你在服务器端使用模块系统,你根本不需要使用Babel。要在 Node.js 中使用模块,请确保:

  1. 使用支持 --experimental-modules 标志的节点版本
  2. 您的 *.js 文件必须重命名为 *.mjs

就是这样。

然而,这是一个很大的问题,虽然你闪亮的纯 ES6 代码将 运行 在像 Node.js(例如 9.5.0)这样的环境中,但你仍然会疯狂地转译去测试。另请记住,Ecma 已声明 JavaScript 的发布周期将会更快,并且会更定期地提供新功能。虽然这对于像 Node.js 这样的单一环境来说没有问题,但对于浏览器环境来说这是一个稍微不同的提议。很明显,测试框架在迎头赶上方面有很多工作要做。您可能仍然需要为测试框架进行转译。我建议使用 Jest.

还要注意捆绑框架。你会运行在那里遇到问题。

回到 Jonathan002 关于

的原始问题

"... what version supports the new ES6 import statements?"

基于 2018 年 3 月 29 日的 article by Dr. Axel Rauschmayer, there is a plan to have it supported by default (without the experimental command line flag) in Node.js 10.x LTS. According to node.js's release plan,它可能会在 2018 年 4 月之后 可用, 而它的 LTS 将于 10 月开始2018.

解决方案

https://www.npmjs.com/package/babel-register

// This is to allow ES6 export syntax
// to be properly read and processed by node.js application
require('babel-register')({
  presets: [
    'env',
  ],
});

// After that, any line you add below that has typical ES6 export syntax
// will work just fine

const utils = require('../../utils.js');
const availableMixins = require('../../../src/lib/mixins/index.js');

下面是文件的定义 *mixins/index.js

export { default as FormValidationMixin } from './form-validation'; // eslint-disable-line import/prefer-default-export

在我的 Node.js CLI 应用程序中工作得很好。

我只想在 JavaScript 个文件中使用 importexport

大家都说不可能。但是,截至 2018 年 5 月,可以在 Node.js 中直接使用上面的内容,而无需 Babel 等任何模块

这是一个简单的方法。

创建以下文件,运行,然后自己查看输出。

另外别忘了看下面的Explanation

文件myfile.mjs

function myFunc() {
    console.log("Hello from myFunc")
}

export default myFunc;

文件index.mjs

import myFunc from "./myfile.mjs"  // Simply using "./myfile" may not work in all resolvers

myFunc();

运行

node  --experimental-modules  index.mjs

输出

(node:12020) ExperimentalWarning: The ESM module loader is experimental.

Hello from myFunc

解释:

  1. 由于是实验模块,.js文件命名为.mjs文件
  2. 在 运行ning 时,您将 --experimental-modules 添加到 node index.mjs
  3. 虽然 运行 输出中的实验模块你会看到:“(节点:12020)实验警告:ESM 模块加载器是实验性的。 “
  4. 我有 Node.js 的当前版本,所以如果我 运行 node --version,它会给我“v10.3.0”,尽管 LTE/stable/recommended 版本是 8.11 .2 LTS.
  5. 将来有一天,您可以使用 .js 代替 .mjs,因为功能变得稳定而不是实验性的。
  6. 有关实验性功能的更多信息,请参阅:https://nodejs.org/api/esm.html

我不知道这是否适合你的情况,但我是 运行 一个 Express.js 服务器:

nodemon --inspect ./index.js --exec babel-node --presets es2015,stage-2

这使我能够导入和使用扩展运算符,即使我只使用 Node.js 版本 8。

您需要安装 babel-cli、babel-preset-es2015 和 babel-preset-stage-2 才能完成我正在做的事情。

使用:

  "devDependencies": {
    "@babel/core": "^7.2.0",
    "@babel/preset-env": "^7.2.0",
    "@babel/register": "^7.0.0"
  }

文件.babelrc

{
  "presets": ["@babel/preset-env"]
}

Node.js 应用程序的入口点:

require("@babel/register")({})

// Import the rest of our application.
module.exports = require('./index.js')

How To Enable ES6 Imports in Node.js

您还可以使用名为 esm 的 npm 包,它允许您在 Node.js 中使用 ES6 模块。它不需要配置。使用 esm,您将能够在 JavaScript 文件中使用 export/import。

运行 在您的终端上输入以下命令

yarn add esm

npm install esm

之后,在使用 node.js 启动服务器时需要 require 这个包。例如,如果您的节点服务器 运行s index.js 文件,您将使用命令

node -r esm index.js

您也可以像这样将其添加到 package.json 文件中

{
  "name": "My-app",
  "version": "1.0.0",
  "description": "Some Hack",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "node -r esm index.js"
  },

}

然后运行这个终端命令启动你的节点服务器

npm start

查看 this link 了解更多详情。

使用 .mjs 扩展(如接受的答案中所建议的那样)以启用 ECMAScript 模块。但是,对于 Node.js v12,您还可以在 package.json 文件中全局启用此功能。

official documentation states:

import statements of .js and extensionless files are treated as ES modules if the nearest parent package.json contains "type": "module".

{
  "type": "module",
  "main": "./src/index.js"
}

(当然你仍然需要在启动应用程序时提供标志--experimental-modules。)

使用 Node.js v12.2.0,我可以像这样导入所有标准模块:

import * as Http from 'http'
import * as Fs from 'fs'
import * as Path from 'path'
import * as Readline from 'readline'
import * as Os from 'os'

与我之前所做的对比:

const
  Http = require('http')
  ,Fs = require('fs')
  ,Path = require('path')
  ,Readline = require('readline')
  ,Os = require('os')

只要在其 package.json 文件中包含此字段,就可以导入任何属于 ECMAScript 模块的模块而无需使用 .mjs 扩展名:

"type": "module"

所以请确保将这样的 package.json 文件放在与您正在制作的模块相同的文件夹中。

要导入未更新 ECMAScript 模块支持的模块,您可以这样做:

// Implement the old require function
import { createRequire } from 'module'
const require = createRequire(import.meta.url)

// Now you can require whatever
const
  WebSocket = require('ws')
  ,Mime = require('mime-types')
  ,Chokidar = require('chokidar')

当然,不要忘记这实际上是 运行 使用模块导入的脚本所必需的(v13.2 之后不需要):

node --experimental-modules my-script-that-use-import.js

并且父文件夹需要此 package.json 文件以使该脚本不抱怨导入语法:

{
  "type": "module"
}

如果您要使用的模块尚未更新为支持使用导入语法导入,那么您别无选择,只能使用 require(但使用我上面的解决方案这不是问题)。

我还想分享这段代码,它实现了模块中缺少的 __filename__dirname 常量:

import {fileURLToPath} from 'url'
import {dirname} from 'path'
const __filename = fileURLToPath(import.meta.url)
const __dirname = dirname(__filename)