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

我试图在Node.js中获得ES6导入的窍门,并试图使用本示例中提供的语法:

Cheatsheet Link

我正在寻找支撑台,但我无法找到什么版本支持新的导入语句(我尝试寻找文本导入/要求)。我目前正在运行Node.js 8.1.2,也相信由于备考表引用的是.js文件,它应该与.js文件一起工作。

当我运行代码时(摘自备忘单的第一个例子):

import { square, diag } from 'lib';

我得到了错误:

SyntaxError:意外的令牌导入。

引用库,我试图导入:

//------ 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语句?

628762 次浏览

Node.js包含了对ES6支持的实验性支持。 阅读更多关于这里: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

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

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

就是这样。

然而,这是一个很大的问题,当你的漂亮的纯ES6代码可以在Node.js(例如,9.5.0)这样的环境中运行时,你仍然会为了测试而疯狂地转译。还要记住,Ecma已经声明JavaScript的发布周期将会更快,更新的特性将会更有规律地发布。虽然这对于Node.js这样的单一环境没有问题,但对于浏览器环境则略有不同。很明显,测试框架在追赶上有很多事情要做。您可能仍然需要为测试框架进行编译。我建议使用开玩笑

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

回到Jonathan002最初的问题

“…什么版本支持新的ES6导入语句?”

基于文章由Axel Rauschmayer博士撰写,有一个默认支持在Node.js 10。x LTS的计划(没有实验性的命令行标志)。根据2018年3月29日的Node.js的发布计划,它可能会变成2018年4月之后,,而它的LTS将在2018年10月开始。

解决方案

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中使用上面的代码,不需要任何像巴别塔这样的模块。

这里有一个简单的方法。

创建下面的文件,运行并自己查看输出。

别忘了看看下面的Explanation

文件# EYZ0

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


export default myFunc;

文件# EYZ0

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. 运行时,您将添加--experimental-modulesnode index.mjs
  3. 在输出中运行实验模块时,你会看到:"(node:12020) ExperimentalWarning: ESM模块加载器是实验性的。 “李< / >
  4. 我有当前版本的Node.js,所以如果我运行node --version,它会给我&;v10.3.0&;尽管LTE/稳定/推荐版本是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-预置-es2015和babel-预置-stage-2来完成我正在做的工作。

使用:

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

文件# EYZ0

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

Node.js应用的入口点:

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


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

看到# EYZ0

你也可以使用npm包esm,它允许你在Node.js中使用ES6模块。它不需要配置。使用esm,您将能够在JavaScript文件中使用导出/导入。

在终端上运行以下命令

yarn add esm

npm install esm

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

node -r esm index.js

你也可以把它添加到你的包中。这样的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

查看这个链接了解更多细节。

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

# EYZ0:

.js和无扩展文件的import语句被视为ES模块,如果最近的父包。Json包含&;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')

任何ECMAScript模块都可以导入,而不需要使用.mjs扩展名,只要它的包中有这个字段。json文件:

"type": "module"

所以一定要放一个这样的包。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

父文件夹需要这个包。Json文件,该脚本不抱怨导入语法:

{
"type": "module"
}

如果您想要使用的模块还没有更新到支持使用import语法导入,那么您除了使用require别无选择(但对于上面的解决方案,这不是问题)。

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

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