如何在 NodeJS 中写 ES6 import
2020 年更新
什么时候可以不要下面那么曲折的方法,直接在 Node 里使用 ES Modules ?
In Node.js 13 we removed the need to include the --experimental-modules flag, but when running EcmaScript Modules in Node.js, this would still result in a warning ExperimentalWarning: The ESM module loader is experimental.
自 Node 13 开始可以直接使用 ES Modules 但是会报警,Node 14 后可以使用并且不报警了。
问题
本人 node 环境是 9.0.0,直接起项目时发现下文(更新:Node 12 中也是如此):
$ node server.js
/Users/everlose/workspace/fedidea/graphql-server/server.js:1
(function (exports, require, module, __filename, __dirname) { import Koa from 'koa'
^^^^^^
SyntaxError: Unexpected token import
at createScript (vm.js:80:10)
at Object.runInThisContext (vm.js:152:10)
at Module._compile (module.js:605:28)
at Object.Module._extensions..js (module.js:652:10)
at Module.load (module.js:560:32)
at tryModuleLoad (module.js:503:12)
at Function.Module._load (module.js:495:3)
at Function.Module.runMain (module.js:682:10)
at startup (bootstrap_node.js:191:16)
at bootstrap_node.js:613:3
在本机可以检测 node 所支持的 es6 语法,如下所示,由此可知我本地其他 es6 语法大体上都支持,除了 import 和 export。而 es6 注定绕不过这个。
$ node -v
v9.0.0
$ npm install -g es-checker
$ es-checker
ECMAScript 6 Feature Detection (v1.4.1)
Variables
√ let and const
√ TDZ error for too-early access of let or const declarations
√ Redefinition of const declarations not allowed
√ destructuring assignments/declarations for arrays and objects
√ ... operator
Data Types
√ For...of loop
√ Map, Set, WeakMap, WeakSet
√ Symbol
√ Symbols cannot be implicitly coerced
Number
√ Octal (e.g. 0o1 ) and binary (e.g. 0b10 ) literal forms
√ Old octal literal invalid now (e.g. 01 )
√ Static functions added to Math (e.g. Math.hypot(), Math.acosh(), Math.imul() )
√ Static functions added to Number (Number.isNaN(), Number.isInteger() )
String
√ Methods added to String.prototype (String.prototype.includes(), String.prototype.repeat() )
√ Unicode code-point escape form in string literals (e.g. \u{20BB7} )
√ Unicode code-point escape form in identifier names (e.g. var \u{20BB7} = 42; )
√ Unicode code-point escape form in regular expressions (e.g. var regexp = /\u{20BB7}/u; )
√ y flag for sticky regular expressions (e.g. /b/y )
√ Template String Literals
Function
√ arrow function
√ default function parameter values
√ destructuring for function parameters
√ Inferences for function name property for anonymous functions
× Tail-call optimization for function calls and recursion
Array
× Methods added to Array.prototype ([].fill(), [].find(), [].findIndex(), [].entries(), [].keys(), [].values() )
√ Static functions added to Array (Array.from(), Array.of() )
√ TypedArrays like Uint8Array, ArrayBuffer, Int8Array(), Int32Array(), Float64Array()
√ Some Array methods (e.g. Int8Array.prototype.slice(), Int8Array.prototype.join(), Int8Array.prototype.forEach() ) added to the TypedArray prototypes
√ Some Array statics (e.g. Uint32Array.from(), Uint32Array.of() ) added to the TypedArray constructors
Object
√ __proto__ in object literal definition sets [[Prototype]] link
√ Static functions added to Object (Object.getOwnPropertySymbols(), Object.assign() )
√ Object Literal Computed Property
√ Object Literal Property Shorthands
√ Proxies
√ Reflect
Generator and Promise
√ Generator function
√ Promises
Class
√ Class
√ super allowed in object methods
√ class ABC extends Array { .. }
Module
× Module export command
× Module import command
=========================================
Passes 38 feature Detections
Your runtime supports 90% of ECMAScript 6
=========================================
步骤
- 安装三个依赖
npm install --save-dev babel-cli babel-preset-stage-2 babel-preset-es2015 babel-plugin-transform-runtime
其中 babel-cli 自带 babel-node 命令
- 修改 package.json 的 script
"scripts": {
"start": "babel-node server.js"
},
- 再加入.babelrc
{
"presets": [
"es2015",
"stage-2"
],
"plugins": ["transform-runtime"]
}
- 最后运行
npm run start
启动程序
如果要在 vscode 中调试 es6 代码
在 package.json 里加入一下代码,能将除了 node_modules 以外的代码都打包入 dist 文件夹
"scripts": {
// 省略其他...
"build": "babel ./ --ignore node_modules -d dist --source-maps",
},
接着在 .vscode 文件夹下加入 task.json
{
"version": "0.1.0",
"command": "npm",
"isShellCommand": true,
"showOutput": "always",
"suppressTaskName": true,
"tasks": [
{
"taskName": "build",
"args": [ "run", "build" ],
"isBuildCommand": true
}
]
}
再于 .vscode 加入 launch.json
{
// 使用 IntelliSense 了解相关属性。
// 悬停以查看现有属性的描述。
// 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.1.0",
"configurations": [
{
"name": "Launch",
"type": "node",
"request": "launch",
"program": "${workspaceRoot}/server.js",
"stopOnEntry": false,
"args": [],
"cwd": "${workspaceRoot}",
"preLaunchTask": "build",
"runtimeExecutable": null,
"runtimeArgs": [ "--nolazy" ],
"env": {
"NODE_ENV": "development"
},
"console": "integratedTerminal",
"sourceMaps": true,
"outFiles": ["${workspaceRoot}/dist/*.js"]
}
]
}
最后按F5启动,每次启动都会由 preLaunchTask 来预先 运行 build task 来把 es6 代码编译了,再启动