如何在 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 中使用模块,请确保:
- 使用支持 --experimental-modules 标志的节点版本
- 您的 *.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 个文件中使用 import
和 export
。
大家都说不可能。但是,截至 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
解释:
- 由于是实验模块,.js文件命名为.mjs文件
- 在 运行ning 时,您将
--experimental-modules
添加到 node index.mjs
- 虽然 运行 输出中的实验模块你会看到:“(节点:12020)实验警告:ESM 模块加载器是实验性的。
“
- 我有 Node.js 的当前版本,所以如果我 运行
node --version
,它会给我“v10.3.0”,尽管 LTE/stable/recommended 版本是 8.11 .2 LTS.
- 将来有一天,您可以使用 .js 代替 .mjs,因为功能变得稳定而不是实验性的。
- 有关实验性功能的更多信息,请参阅: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')
您还可以使用名为 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)
我试图在 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 中使用模块,请确保:
- 使用支持 --experimental-modules 标志的节点版本
- 您的 *.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 个文件中使用 import
和 export
。
大家都说不可能。但是,截至 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
解释:
- 由于是实验模块,.js文件命名为.mjs文件
- 在 运行ning 时,您将
--experimental-modules
添加到node index.mjs
- 虽然 运行 输出中的实验模块你会看到:“(节点:12020)实验警告:ESM 模块加载器是实验性的。 “
- 我有 Node.js 的当前版本,所以如果我 运行
node --version
,它会给我“v10.3.0”,尽管 LTE/stable/recommended 版本是 8.11 .2 LTS. - 将来有一天,您可以使用 .js 代替 .mjs,因为功能变得稳定而不是实验性的。
- 有关实验性功能的更多信息,请参阅: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')
您还可以使用名为 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)