前言
有时候,项目的特殊需求要求我们将一些依赖包通过
UMD
为了解决这个问题,我们可以利用UMD(Universal Module Definition)模块来兼容不支持script标签引入的包。UMD模块允许我们将一个包同时适配CommonJS、AMD和全局对象的使用方式。 引用文章:链接聊聊 js 模块化(CommonJS, AMD, UMD, CMD, ES6) 下面是一个简单的UMD模块示例:
(function (global, factory) {
// 兼容CommonJS
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
// 兼容AMD
typeof define === 'function' && define.amd ? define(['exports'], factory) :
// 挂载到全局window对象中,这里的global是第8行传进来的this,而这个是自执行函数,这个this在浏览器中就是window对象了
// globalThis 是访问全局变量的,比如在浏览器环境,它会指向 window,在 Node 环境,它会指向 global
// self主要是Web Workers中的全局对象
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.TableCore = {}));
})(this, (function (exports) {
// 源码
}));
Rollup
对于那些原本不提供UMD产物的包,能不能自己制作一个umd.js呢,当然可以的。 我们可以通过使用Rollup工具来打包它们。Rollup是一个类似Webpack的打包工具,通常用于打包库项目。 以下是我项目中的部分代码: 首先添加依赖
pnpm i -D rollup rollup-plugin-terser @rollup/plugin-commonjs @rollup/plugin-node-resolve
创建一个文件夹library,在这个文件夹中创建需要打包的js文件,比如说solid-main.js
module.exports = require("solid-js");
写一个rollup.config.js配置文件
// rollup.config.js
const { nodeResolve } = require('@rollup/plugin-node-resolve');
const commonjs = require('@rollup/plugin-commonjs');
const { terser } = require('rollup-plugin-terser');
const path = require('path');
const common = {
plugins: [
nodeResolve({ jsnext: true, preferBuiltins: true, browser: true }),
commonjs(),
terser(),
],
};
module.exports = (env = 'production') => {
return [
{
...common,
input: path.join(__dirname, '/library/solid-main.js'),
output: {
file: path.join(__dirname, '/public/project/resources/csc_js/solid-js/solid.min.js'),
format: 'umd',
name: 'Solid',
sourcemap: true,
},
external: [],
},
{
...common,
input: path.join(__dirname, '/library/solid-web.js'),
output: {
file: path.join(__dirname, '/public/project/resources/csc_js/solid-js/solid-web.min.js'),
format: 'umd',
name: 'SolidWeb',
sourcemap: true,
globals: {
'solid-js': 'Solid',
},
},
external: ['solid-js']
},
{
...common,
input: path.join(__dirname, '/library/solid-store.js'),
output: {
file: path.join(__dirname, '/public/project/resources/csc_js/solid-js/solid-store.min.js'),
format: 'umd',
name: 'SolidStore',
sourcemap: true,
globals: {
'solid-js': 'Solid',
},
},
external: ['solid-js']
},
];
};
在上面的配置文件中,我们定义了三个UMD配置,使用format: 'umd'来指定输出格式,并设置name来指定模块挂载到window对象上的名称。 需要特别注意的是,solid-web.js和solid-store.js都依赖solid-js,所以需要设置external,不然会把solid-js的源码也打包进去。globals用于指定external中拆分出去的依赖包可以通过window访问到变量名,因为在上面声明的是Solid,所以这里都要统一。 而且这里的三个名字都不是随便设置的,因为我还用到了TanStack Table,这个包提供了UMD模块的js文件,它里面是直接拿到了SolidWeb和SolidStore。 最后,在webpack中指定externals,将这些UMD模块与项目中其他依赖进行关联:
module.exports = {
...
externals: {
'solid-js': 'Solid',
'solid-js/web': 'SolidWeb',
'solid-js/store': 'SolidStore',
'@tanstack/table-core': 'TableCore',
'@tanstack/solid-table': 'SolidTable',
echarts: 'echarts',
flatpickr: 'flatpickr',
'fast-xml-parser': 'xmlParser',
'algebra.js': 'algebra',
'@floating-ui/core': 'FloatingUICore',
'@floating-ui/dom': 'FloatingUIDOM',
'dayjs': 'dayjs'
}
}
在这里我之前还犯了一个错误,设置完成之后发现没效果。 因为我以为externals对象的key代表指定的变量名,value代表依赖包的名称。其实正好相反。 key代表依赖包的名称,value表示引入进来的全局变量名,千万不要像我一样粗心大意。
总结
在某些特殊情况下,需要将一些依赖包通过script标签的方式引入HTML,而不是直接打包进最终产物的JavaScript中。对于一些不支持script标签引入的包,可以通过制作UMD模块来实现。使用Rollup工具可以打包这些依赖包,并生成UMD模块,使其能够通过script标签引入到HTML中。在项目中,通过设置Webpack的externals配置,将这些引入的全局变量与依赖包进行关联,从而优化整体项目的构建和依赖管理。