前言:本文讲述前端代码模块化发展历程,再介绍构建工具对代码予以指定条件下的打包构建。
一、前端模块化历程
无模块化(入口函数加载)→ AMD → CommonJS → UMD → ES Module
- 无模块化:通过入口函数即可加载
- CommonJS:Node.js环境下的模块引入方式
- UMD:并不是一种全新的模块系统,而是整合了无模块化、AMD、CommonJS三种模块规范,其可以在任何环境下工作
- ES Module:ECMAScript 2015引入的模块化规范,部分浏览器支持,不支持该特性的浏览器需要使用构建工具来提供支持
Commonjs
nodejs不能使用es6的模块导入导出
node.js 使用 commonjs 规范,es6 module 的推出和完善,node 从 v13开始原生支持 es6 module。
在node环境下是不能使用es6语法中import export导入导出语法的,解决办法有babel转义,或者如下面的一种新方法(需要Node.js 版本 13.x.x 以上),个人推荐最好还是用babel配置babel配置文件在转义,因为可以自行一些配置。
- 解决方案一:Node.js 版本 13.x.x 以上的版本,使用 官方推荐的方法 在
package.json
文件中设置"type": "module"
。
{
"type": "module"
}
- 解决方案二:使用 babeljs ,然后在项目中添加相关配置即可,具体可以查阅相关教程。
导入导出
导出
【第一种方式】
- 就是在模块里面定义好变量/方法,然后利用
exports.let_1= let_1;
exports.fun_1 = fun_1;
这种形式,一个个导出
【第二种方式】module.exports.version = version;
导入
const a = require('文件路径');
模块的查找规则
ES Module
export
const checkStr = (str, type) => {
// 等内容
}
module.exports = {
checkStr,
}
export const updateInfo: any = (data: any) => {
return fetch({
method: 'post',
url: `/*****************`,
data: data,
})
}
import
import fetch from '../utils/fetch'
与class结合
class StorageFn {
ls: Storage
ss: Storage
constructor() {
this.ls = window.localStorage
this.ss = window.sessionStorage
}
/*设置cookie*/
setCookie(name: any, value: any, day: any) {}
// 等内容
}
export default StorageFn
二、模块化实现方式
实现各种环境下都能使用模块化代码,需要使用打包工具来对一套代码进行打包,打包工具主流有:
- Webpack:适合应用类打包
- roolup.js:适合工具类以及SDK打包
打包目标:
- 编写ECMAScript 2015及其之后版本的新特性代码
- 兼容各种浏览器和Node.js环境运行
- 输出各类模块规范
- 可以按需加载
roolup.js打包
- sideEffects:实现按需加载
{
···
"main": "dist/index.js",
"jsnext:main": "dist/index.esm.js",
"module": "dist/index.esm.js",
"sideEffects": false,
"scripts": {
"build:self": "rollup -c config/rollup.config.js",
"build:esm": "rollup -c config/rollup.config.esm.js",
"build:aio": "rollup -c config/rollup.config.aio.js",
"build": "npm run build:self && npm run build:esm && npm run build:aio",
},
"devDependencies": {
"@babel/core": "^7.1.2",
"@babel/plugin-transform-runtime": "^7.1.0",
"@babel/preset-env": "^7.1.0",
"rollup": "^0.57.1",
"rollup-plugin-babel": "^4.0.3",
"rollup-plugin-commonjs": "^8.3.0",
"rollup-plugin-node-resolve": "^3.0.3"
},
"dependencies": {
"@babel/runtime-corejs2": "^7.12.5",
"@babel/runtime-corejs3": "^7.12.5",
"core-js": "^3.7.0"
}
···
}
- banner:打包后的公共头部注释
- 输入
npx browserslist
可查看浏览器版本支持情况
var babel = require("rollup-plugin-babel");
var pkg = require("../package.json");
var version = pkg.version;
var banner = `/*!
* ${pkg.name} ${version}
* Licensed under MIT
*/
`;
function getCompiler(opt) {
return babel({
babelrc: false,
presets: [
[
"@babel/preset-env",
{
targets: {
browsers:
"last 2 versions, > 1%, ie >= 8, Chrome >= 45, safari >= 10",
node: "0.12",
},
modules: false,
loose: false,
},
],
],
plugins: [
[
"@babel/plugin-transform-runtime",
{
corejs: 2,
helpers: false,
regenerator: false,
},
],
],
runtimeHelpers: true,
exclude: "node_modules/**",
});
}
exports.name = "clone";
exports.banner = banner;
exports.getCompiler = getCompiler;
// commonjs
var common = require("./rollup.js");
module.exports = {
input: "src/index.js",
output: {
file: "dist/index.js",
format: "cjs",
// When export and export default are not used at the same time, set legacy to true.
// legacy: true,
banner: common.banner,
},
plugins: [common.getCompiler()],
};
// ES output
var common = require("./rollup.js");
module.exports = {
input: "src/index.js",
output: {
file: "dist/index.esm.js",
format: "es",
// When export and export default are not used at the same time, set legacy to true.
// legacy: true,
banner: common.banner,
},
plugins: [common.getCompiler()],
};
- roolup打包CommonJS需要配合插件来执行
// umd
var nodeResolve = require("rollup-plugin-node-resolve");
var commonjs = require("rollup-plugin-commonjs");
var common = require("./rollup.js");
module.exports = {
input: "src/index.js",
output: {
file: "dist/index.aio.js",
format: "umd",
// When export and export default are not used at the same time, set legacy to true.
// legacy: true,
name: common.name,
banner: common.banner,
},
plugins: [
nodeResolve({
main: true,
extensions: [".js"],
}),
commonjs({
include: "node_modules/**",
}),
common.getCompiler(),
],
};
三、参考
模块化理解
- 分析组件库以及构建产物:https://zhuanlan.zhihu.com/p/502956467
- 这一次,我要弄懂javascript的模块化 - 掘金:https://juejin.cn/post/6844903636108066830
模块化打包
- vite的项目,使用rollup打包的方法:https://juejin.cn/post/7036207262414667790
- 如何将 CommonJS 转化为 ESM | 前端工程化三十八讲 | 大厂面试题每日一题
- https://github.com/rollup/plugins/tree/master/packages/commonjs
- Rollup打包工具的使用(超详细,超基础,附代码截图超简单) - 掘金
- 【实战篇】最详细的Rollup打包项目教程 - 掘金
- rollup打包一个工具库并发布到npm - 掘金
ts的模块导入导出
评论区