如何在基于Vite.js的第三方UI组件库中嵌入小众开源字体并合规包含许可证文件?
解决方案:自定义Vite资源输出规则,保留目录结构
针对你在Vite组件库中嵌入小众字体+许可证的需求,核心思路是通过Vite的Rollup配置自定义资源输出路径,同时让字体和许可证文件保持原目录关联,避免分散或路径问题。以下是具体步骤:
1. 先规划本地资源目录
把字体文件和许可证放在组件库源码内的统一目录下,比如:
src/ assets/ fonts/ my-code-font/ myfont.woff2 LICENSE
这样后续打包时可以基于这个目录结构生成目标路径。
2. 配置Vite自定义资源输出路径
修改你的vite.config.js,重点配置build.rollupOptions.output.assetFileNames,同时确保Vite识别所有需要的资源类型:
import { defineConfig } from 'vite'; import pkg from './package.json'; // 引入package.json获取包名 export default defineConfig({ assetsInclude: ['**/*.woff2', '**/LICENSE'], // 明确让Vite识别字体和许可证 build: { lib: { // 你的组件库lib配置,比如entry, name, formats等 entry: 'src/index.js', name: 'YourUIComponentLib', formats: ['es', 'umd'], fileName: (format) => `your-ui-lib.${format}.js` }, rollupOptions: { output: { // 自定义资源输出路径,完全匹配你想要的结构 assetFileNames: `com.company.framework/Embed/${pkg.name}/[dirname]/[name].[hash][extname]`, // 如果有其他资源(比如css),可以单独配置cssFileNames cssFileNames: `com.company.framework/Embed/${pkg.name}/styles/[name].[hash].css` } } } });
这里的[dirname]会保留资源文件所在的相对目录(也就是my-code-font),[name].[hash][extname]保留文件名和哈希,既保证缓存击穿,又维持了目录结构。
3. 在CSS中正确引入字体
在你的组件库CSS(比如src/styles/fonts.css)中用相对路径写@font-face:
@font-face { font-family: 'MyCodeFont'; src: url('../assets/fonts/my-code-font/myfont.woff2') format('woff2'); font-weight: normal; font-style: normal; font-display: swap; }
Vite会自动解析这个相对路径,打包后替换成最终的输出路径(比如com.company.framework/Embed/your-package-name/my-code-font/myfont.woff2)。
4. 许可证文件的处理
因为我们把LICENSE和字体放在同一个目录,且在assetsInclude中声明了它,Vite会把它当作静态资源处理,打包后会和字体文件一起出现在目标目录下,不需要额外的import license操作——之前的第一种方案就是因为把LICENSE当作JS模块导入,才导致它被单独归类到JS资源目录,和字体分散。
为什么之前的方案不行?
- 方案1(import LICENSE):Vite会把导入的LICENSE当作JS模块处理,最终输出到JS资源目录,和字体这种静态资源的输出路径分离,自然会分散。
- 方案2(public目录):Vite的public目录是针对最终应用设计的,组件库打包后public资源会放在dist根目录,而组件库发布到NPM后,消费端引用时路径会出现不匹配的问题;开发环境下Vite对public资源的路由规则也不适合组件库的场景,导致你遇到的重定向问题。
关于缓存的补充
你提到的哈希处理确实是为了强制浏览器加载新资源,HTTP服务器配置缓存控制是辅助手段,但保留哈希依然是更可靠的方式(尤其是组件库被多个应用引用时,你无法控制所有消费端的服务器配置)。我们的方案既保留了哈希,又维持了规整的目录结构,两者可以兼得。
内容的提问来源于stack exchange,提问作者Nope

