了解模块化
Commonjs
- 加载模块:
require - 导出模块:
module.exports / exports.xxx
ES Module
- 加载模块:
import - 导出模块:
export default / export xxx
痛点分析
使用 Commonjs 导出一个模块 utils
// test-cli-0174binutils.js
module.exports = function () {
console.log('hello utils');
};主文件中通过 ES Module 的方式引入模块
// test-cli-0174binindex.js
#!/usr/bin/env node
import utils from './utils';
utils();运行程序,发现会报错 Cannot use import statement outside a module ,意思就是不让用 import 语法。

那么我们如何让 Node 环境支持 ES Module 呢?
利用 webpack
安装 webpack
代码语言:javascript复制npm i -D webpack webpack-cli修改代码
主文件使用 require 去调用 webpack 构建后的 core.js
// test-cli-0174binindex.js
#!/usr/bin/env node
require('./dist/core');core.js 使用 es module 引入 utils.js
// test-cli-0174bincore.js
import utils from './utils';
utils();配置好 webpack.config.js
代码语言:javascript复制// webpack.config.js
const path = require('path');
module.exports = {
entry: './bin/core.js',
output: {
path: path.join(__dirname, '/dist'),
filename: 'core.js',
},
mode: 'development',
};修改 packag.json 的 scripts 字段
代码语言:javascript复制 "scripts": {
"build": "webpack",
"dev": "webpack -w"
},执行构建
代码语言:javascript复制npm run build构建完成会出现 dist 目录以及构建后的 core.js

再次运行程序,发现可以正常运行。

可以启动监听状态,当文件发生变化时,自动执行构建过程
代码语言:javascript复制npm run dev通过 webpack target 属性支持 Node 内置库
当我们调用 node 的内置库时,比如 path、fs,webpack 构建会报错,因为 webpack 默认使用 web 环境进行构建,web 环境不存在 node 的内置库,所以我们需要修改 target 属性为 node。
// webpack.config.js
const path = require('path');
module.exports = {
entry: './bin/core.js',
output: {
path: path.join(__dirname, '/dist'),
filename: 'core.js',
},
target: 'node', // 默认是web
};代码语言:javascript复制// test-cli-0174binutils.js
import { pathExistsSync } from 'path-exists';
export function exists(p) {
return pathExistsSync(p);
}代码语言:javascript复制// test-cli-0174bincore.js
import path from 'path';
import { exists } from './utils';
console.log(path.resolve('.'));
console.log(exists(path.resolve('.')));执行程序,没有什么问题了。

利用 babel 兼容低版本 node
安装依赖
代码语言:javascript复制npm i -D
babel-loader
@babel/core
@babel/preset-env
@babel/plugin-transform-runtime
@babel/runtime-corejs3配置 webpack
// webpack.config.js
const path = require('path');
module.exports = {
entry: './bin/core.js',
output: {
path: path.join(__dirname, '/dist'),
filename: 'core.js',
},
mode: 'development',
target: 'node', // 默认是web
module: {
rules: [
{
test: /.js$/,
exclude: /(node_modules|dist)/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env'],
plugins: [
[
'@babel/plugin-transform-runtime',
{
corejs: 3,
regenerator: true,
useESModules: true,
helpers: true,
},
],
],
},
},
},
],
},
};node 原生如何支持 ES Module
需要修改文件名的后缀为 .mjs,并且一旦使用 mjs,所有的内容都需要使用 ES Module,不可混用,否则会报错。
// test-cli-0174binindex.mjs
#!/usr/bin/env node
import './core.mjs';代码语言:javascript复制// test-cli-0174bincore.mjs
import path from 'path';
import { exists } from './utils.mjs';
console.log(path.resolve('.'));
console.log(exists(path.resolve('.')));代码语言:javascript复制// test-cli-0174binutils.js
import { pathExistsSync } from 'path-exists';
export function exists(p) {
return pathExistsSync(p);
}最后 通过一个指令来执行程序
代码语言:javascript复制node --experimental-modules bin/index.mjs
// node14版本之后 不需要加 --experimental-modules 指令也可以
node bin/index.mjs同样能得到结果,没有什么问题。

如果不希望将后缀名改成 .mjs,可以在项目的 package.json 文件中,指定 type 字段为 module。
{
"type": "module"
}一旦设置了以后,该目录里面的 JS 脚本,就被解释用 ES6 模块。


