如何解决Yarnberry Monorepo中UI包公共组件图片加载异常问题?
Monorepo(Yarnberry 3.6)中UI包图片在Next.js项目显示异常的解决方案
问题背景
使用Yarnberry 3.6构建Monorepo,目录结构如下:
pakages | └── ui | └──src | └──assets | └── close.png | └──modals | └──Modal.tsx | sevices └── └── next-app
UI包的package.json配置如下:
{ "name": "@common/ui", "packageManager": "yarn@3.6.1", "main": "./src/index.ts", "scripts": { ... }, "devDependencies": { "@babel/cli": "^7.22.9", "@babel/core": "^7.22.9", "@babel/preset-env": "^7.22.9", "@babel/preset-react": "^7.22.5", "@babel/preset-typescript": "^7.22.5", "esbuild": "latest", "esbuild-css-modules-plugin": "^2.7.1", "esbuild-sass-plugin": "^2.10.0", "react": "^18.2.0", "react-dom": "^18.2.0", "sass": "^1.64.1", "vite": "^4.4.7" }, }
UI包相关代码:
// packages/ui/src/index.ts export { default as Modal } from "./modals/Modal";
// packages/ui/src/modals/Modal.tsx import Close from '../../assets/close.png'; const Modal = ({ title, content, buttonName }: IConfirmType) => { return ( <div className="popup_message_view_align"> <img className="btn_close" src={Close} alt="close" /> ... </div> ); };
将UI包的Modal组件导入至services/next-app后,组件可正常渲染,但图片无法加载,img元素的src属性值显示为[object Object]。
问题原因
Next.js对静态资源的导入会返回一个包含src、width等属性的对象(而非直接返回文件路径字符串),而UI组件直接将该对象赋值给img的src属性,导致显示异常。同时,Monorepo中UI包的资源未被Next.js构建流程正确识别处理。
解决方案
方案1:修改组件中图片的使用方式
直接提取导入图片对象的src属性赋值给img标签:
// Modal.tsx import Close from '../../assets/close.png'; const Modal = ({ title, content, buttonName }: IConfirmType) => { return ( <div className="popup_message_view_align"> <img className="btn_close" src={Close.src} {/* 改为获取src属性 */} alt="close" /> ... </div> ); };
方案2:配置Next.js处理UI包资源
在services/next-app/next.config.js中添加transpilePackages,让Next.js将UI包纳入自身构建流程:
/** @type {import('next').NextConfig} */ const nextConfig = { transpilePackages: ['@common/ui'], } module.exports = nextConfig;
配置完成后重启Next.js项目,配合方案1即可正常加载图片。
方案3:预构建UI包资源
通过构建工具将UI包中的图片处理为可直接引用的路径,避免Next.js的资源解析逻辑干扰:
- 在UI包的
package.json中添加构建脚本:
{ "scripts": { "build": "esbuild src/index.ts --bundle --outfile=dist/index.js --loader:.png=file --asset-names=assets/[name]-[hash]" } }
该命令会将图片复制到dist/assets目录,并在代码中替换为相对路径。
2. 修改UI包的package.json入口字段:
"main": "./dist/index.js", "types": "./dist/index.d.ts" // 若需类型支持,需额外配置TypeScript编译输出类型声明
- 执行构建:
yarn workspace @common/ui build,之后Next.js项目会使用构建后的UI包代码,图片路径可直接正常使用。
方案4:使用Next.js Image组件(需依赖Next.js)
若UI组件无需跨框架通用,可改用Next.js的Image组件,它会自动处理静态资源:
// Modal.tsx import Image from 'next/image'; import Close from '../../assets/close.png'; const Modal = ({ title, content, buttonName }: IConfirmType) => { return ( <div className="popup_message_view_align"> <Image className="btn_close" src={Close} alt="close" width={24} // 根据实际图片尺寸设置 height={24} /> ... </div> ); };
内容的提问来源于stack exchange,提问作者김정수
相关产品推荐
相关产品推荐

