软件包封装:多种JS模块标准的软件包
一款成熟的类库都会提供多种模块的封装形式,如常用的Vue,就提供了cjs、esm、umd等多种封装模式,并且还会提供对应的压缩版本、方便在开发、生产环境下使用。
工程化场景下需要考虑支持哪些模块的规范
目前常用的模块规范有:
IFFE
: 使用立即执行函数实现模块化。例: (function(){})()CJS
: 基于 CommonJs 标准的模块化。AMD
: 使用 Require 编写。CMD
: 使用 SeaJs 编写。ESM
: ES标准的模块化方案(ES6标准提出)。UMD
: 兼容 CJS、AMD、IFFEG 规范。
其中最常用的有三类:ESM、CJS、IFFE 。ESM标准目前是前端开发的标配,无论是选用webpack或是vite,都会采用这种模块规范。其次是CJS,不可否认,有大量的存量代码还在使用CJS规范,完全没有必要因为引入一个库去更改编译规则。最后就是IFFE这种类型,非常适合用于逻辑简单,无须搭建工程化环境的前端应用。
需要考虑代码的压缩和混淆问题
- 代码压缩是指去除代码中的空格、制表符、换行符等内容,将代码压缩至几行甚至是一行,这样可以提高网站的加载速度。
- 混淆是指将代码转换成一种功能上等价,但是难以阅读和理解的形式。混淆的主要目的是增加反向工程的难度,同时也可以相对减少代码的体积,比如将变量名缩短等。
需要考虑 SourceMap 配置
SourceMap
是一个信息文件,里面存储了代码打包转换后的位置信息,实质上是一个json描述文件,维护了打包前后的代码映射关系。通常输出的模块不会提供 SourceMap
, 因为通过 Sourcemap
很容易还原原始代码。但是如果你想在浏览器中断点调试代码,或者希望在异常监控工具中定位出错位置, SourceMap
就非常有必要。所以需要正确掌握 SourceMap
的生成方式。
基于vite的打包方案
rollupOption 配置
vite.config.ts
ts
const rollupOptions = {
external: ["vue"],
output: {
globals: {
vue: "Vue",
},
},
}
由于 Vite
的构建是通过 rollup
完成的,所以 rollup
中的一些配置是通过这个属性传递给 rollup
。 其中需要配置的两个解释如下:
external
作用是将某个模块保留在bundle
之外, 比如在数组中添加了vue
, 就是为了不让vue
打包到组件库中output
这个配置用于UMD/IFFE
包中,意思是全局中的某个模块在组件库中叫什么名字。比如:
js
import $ from 'jquery'
// 意味着jquery模块的id等同于 $ 变量
var MyBundle = (function($){
// 代码
})(window.jquery);
打包配置
javascript
export default defineConfig({
build: {
rollupOptions,
minify: 'terser', // boolean | 'terser' | 'esbuild'
sourcemap: true, // 输出单独 source文件
brotliSize: true, // 生成压缩大小报告
cssCodeSplit: true,
lib: {
entry: "./src/entry.ts",
name: "SmartyUI",
fileName: "smarty-ui",
formats: ["esm", "umd", "iife"], // 导出模块类型
},
},
});
minify
是混淆的意思。这里有两个混淆工具terser
和esbuild
。sourcemap
是否生成SourceMap
源文件
bash
pnpm i terser -D
lib.name
生成包的名字,在iife/umd 包,同一页上的其它脚本可以访问它lib.fileName
文件名,其实只是一个输出文件名的前缀,默认情况下会和模块类型配合组成最终的文件名。lib.formats
["esm", "umd", "iife"] 打包输出的模块类型文件