使用 Node 运行 ES6 模块

由于 Node 的模块组织方式和 ES6 的模块组织方式不同,因此 ES6 的模块导入和导出语法在 Node 命令行程序执行下会报错 另外,某些 ES6 关键字的用法亦不兼容,因此需要使用 Babel 进行转换后执行 比如: 有个 ES6 写的 logger.js 直接上代码:

const Level = {
  DEBUG: 1,
  INFO: 2,
  ERROR: 3,
  NONE: 4,
};
class Logger {
  constructor(level) {
    this.level = level || Level.INFO;
  }
}
// 执行默认构造行数并打印
const logger1 = new Logger();
console.log(logger1);

// 执行指定Level的构造函数并打印
const logger2 = new Logger(Level.DEBUG);
console.log(logger2);

// 定义LoggerFactory并输出
const LoggerFactory = {
  getLogger(level) {
    return new Logger(level);
  },
};
// ES6输出模块
export { LoggerFactory };

直接在 Node 的命令行下执行

node logger.js

会报错

export {
^^^^^^

SyntaxError: Unexpected token export
    at Module._compile (internal/modules/cjs/loader.js:743:23)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:810:10)
    at Module.load (internal/modules/cjs/loader.js:666:32)
    at tryModuleLoad (internal/modules/cjs/loader.js:606:12)
    at Function.Module._load (internal/modules/cjs/loader.js:598:3)
    at Function.Module.runMain (internal/modules/cjs/loader.js:862:12)
    at internal/main/run_main_module.js:21:11

那么需要一个代理类使用 Babel 的注册类来转换代码:

yarn -D add babel-register babel-preset-env

之后写一个 logger_test.js 作为代理程序:

require("babel-register")({
  presets: ["env"],
});

module.exports = require("./logger.js");

然后运行

node logger_test.js

成功输出:

Logger { level: 2 }
Logger { level: 1 }

后记

如果用一个文件代理多个文件呢?这样就不用每个文件都写一个这个代理文件了?有解! 请参考 https://github.com/visionmedia/commander.js

安装 commander

yarn add commander

可以将 logger_test.js 改造为 run.js

require("babel-register")({
  presets: ["env"],
});
let path = "./logger.js";
module.exports = require(path);

每次运行仍旧要要改文件路径,能够通过参数方式传入吗? 可以: 将 run.js 改造为 js-run.sh

#!/usr/bin/env node

/**
 * Module dependencies.
 */
require("babel-register")({
  presets: ["env"],
});
var program = require("commander");

program.version("0.1.0").option("-f, --file <jsfile>", "请指定要运行的JavaScript文件").parse(process.argv);
let file = program.file;
if (typeof file === "undefined") {
  program.help();
  process.exit(1);
  return;
}
// 监听未捕获的异常
process.on("uncaughtException", function (err) {
  console.log(err);
});
// 处理传进来的文件路径参数,使得可以更短的输入命令行字符数
if (file.endsWith(".js") === false) file = file + ".js";
if (file.indexOf("/") === -1) file = "./" + file;

// console.log('运行文件javascript文件: --file=%s', file)
console.log("--------------------------------------------------------------------");
try {
  module.exports = require(file);
} catch (err) {
  console.log(err);
}
console.log();

然后就可以使用

./js-run.sh -f logger.js

运行你的程序了。

在任意目录运行你的 js

首先新增个主运行脚本 js.sh 来调用上面那个 run-js.sh

#!/bin/bash
# 获取要运行脚本的当前文件夹并传递第一个参数(文件名)
JS_FILE=`pwd`/$1
echo $JS_FILE
/data/bash/js-run.sh -f $JS_FILE

之后在你的主目录编辑 .bash_profile 增加这个文件的别名

alias js='/data/bash/js.sh'
export PATH="$PATH:/data/bash"

或者使用 ln 创建 js.sh 的软链接

ln -s js.sh js

之后就可以在任意目录使用

# js后面的参数可以是绝对路径文件/相对路径文件/或直接文件名即可(无需添加.js后缀)
js test.js

愉快的运行你的 ES6 javascript 程序了!