了解模块化
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
模块。