create-react-library发布React组件库后静态图片不显示如何解决
这个问题的核心是create-react-library默认webpack配置处理静态图片资源时,生成的是相对路径引用。组件被业务项目安装引入后,img标签的src路径会以业务项目的域名根目录为解析基准,不会自动指向node_modules/对应组件/dist目录内的图片文件,因此出现加载失败。你测试到的直接从dist目录引图片能正常显示、把图片复制到业务项目public目录能正常加载,本质都是修正了路径的解析基准位置。
方案1:调整webpack静态资源配置(根源解决,推荐)
修改组件库的webpack打包配置,给静态资源指定正确的publicPath,让打包后的资源引用路径直接指向组件包在node_modules中的可访问位置:
- 找到项目内的webpack配置文件,create-react-library初始化的项目配置一般存放在
scripts/config目录下 - 定位到处理png、jpg、gif等图片资源的规则项,按你使用的webpack版本调整配置:
- webpack4及更早版本(使用file-loader/url-loader):给loader增加publicPath字段,替换成你实际发布的npm包名,带scope的包要补全scope路径
{ test: /\.(png|jpe?g|gif|svg)$/i, use: [ { loader: 'url-loader', options: { limit: 10240, // 小于10KB的资源自动转base64内联 fallback: 'file-loader', // 替换成自己的包名,@scope包要写全路径如 /node_modules/@scope/xxx/dist/ publicPath: '/node_modules/your-component-name/dist/', outputPath: 'static/media' } } ] }- webpack5版本(使用内置Asset Modules):在generator配置项中增加publicPath
{ test: /\.(png|jpe?g|gif|svg)$/i, type: 'asset', parser: { dataUrlCondition: { maxSize: 10 * 1024 // 小于10KB转base64 } }, generator: { // 替换成自己的包实际路径 publicPath: '/node_modules/your-component-name/dist/', filename: 'static/media/[name][ext]' } } - 重新打包发布组件包,业务项目更新依赖后图片即可正常加载。
方案2:小体积图片全量转base64内联
如果组件内用到的静态图片体积都很小,可以直接调高静态资源转base64的体积阈值,让所有图片都转成base64编码直接内联到JS代码中,不会生成独立的图片文件,自然不存在路径问题。
只需要把上述配置中limit(webpack4)或dataUrlCondition.maxSize(webpack5)的值调到大于你所有图片的单卷最大体积即可,比如设为100 * 1024就代表100KB以下的图片全部内联。
注意:大体积图片不适合用这个方案,base64编码会增大JS包体积,拖慢页面加载速度。
方案3:切换rollup打包(长期维护组件库推荐)
如果是长期维护的组件库,更推荐使用rollup做构建,配合静态资源处理插件,可以更适配组件库的发布场景,默认就能生成下游业务项目可正常解析的资源路径,不会出现webpack相对路径的适配问题。
核心配置参考:
// rollup.config.js import url from '@rollup/plugin-url' export default { // 其余入口、输出等基础配置省略 plugins: [ url({ limit: 10240, // 替换成自己组件包的实际路径 publicPath: '/node_modules/your-component-name/dist/', include: ['**/*.png', '**/*.jpg', '**/*.gif', '**/*.svg'] }) ] }
如果暂时不方便修改组件库的构建配置,可以在业务项目层面做临时适配:
- 配置业务项目的webpack别名,把组件内引用的图片路径映射到node_modules下组件包的dist目录
- 提前把组件用到的所有静态图片复制到业务项目的public目录,和你手动测试的效果一致
这两种方案都需要业务项目配合改配置,不属于根源解决方式,仅适合临时应急使用。
内容的提问来源于stack exchange,提问作者Morteza Darzi

