了解模块化
Commonjs
- 加载模块:
require
- 导出模块:
module.exports / exports.xxx
ES Module
- 加载模块:
import
- 导出模块:
export default / export xxx
痛点分析
使用 Commonjs
导出一个模块 utils
// test-cli-0174\bin\utils.js
module.exports = function () {
console.log('hello utils');
};
主文件中通过 ES Module
的方式引入模块
// test-cli-0174\bin\index.js
#!/usr/bin/env node
import utils from './utils';
utils();
运行程序,发现会报错 Cannot use import statement outside a module
,意思就是不让用 import
语法。
那么我们如何让 Node
环境支持 ES Module
呢?
利用 webpack
安装 webpack
npm i -D webpack webpack-cli
修改代码
主文件使用 require
去调用 webpack
构建后的 core.js
// test-cli-0174\bin\index.js
#!/usr/bin/env node
require('./dist/core');
core.js
使用 es module
引入 utils.js
// test-cli-0174\bin\core.js
import utils from './utils';
utils();
配置好 webpack.config.js
// 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 字段
"scripts": {
"build": "webpack",
"dev": "webpack -w"
},
执行构建
npm run build
构建完成会出现 dist
目录以及构建后的 core.js
再次运行程序,发现可以正常运行。
可以启动监听状态,当文件发生变化时,自动执行构建过程
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
};
// test-cli-0174\bin\utils.js
import { pathExistsSync } from 'path-exists';
export function exists(p) {
return pathExistsSync(p);
}
// test-cli-0174\bin\core.js
import path from 'path';
import { exists } from './utils';
console.log(path.resolve('.'));
console.log(exists(path.resolve('.')));
执行程序,没有什么问题了。
利用 babel 兼容低版本 node
安装依赖
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-0174\bin\index.mjs
#!/usr/bin/env node
import './core.mjs';
// test-cli-0174\bin\core.mjs
import path from 'path';
import { exists } from './utils.mjs';
console.log(path.resolve('.'));
console.log(exists(path.resolve('.')));
// test-cli-0174\bin\utils.js
import { pathExistsSync } from 'path-exists';
export function exists(p) {
return pathExistsSync(p);
}
最后 通过一个指令来执行程序
node --experimental-modules bin/index.mjs
// node14版本之后 不需要加 --experimental-modules 指令也可以
node bin/index.mjs
同样能得到结果,没有什么问题。
如果不希望将后缀名改成 .mjs
,可以在项目的 package.json
文件中,指定 type
字段为 module
。
{
"type": "module"
}
一旦设置了以后,该目录里面的 JS
脚本,就被解释用 ES6
模块。