Angular组件库引入theme npm包时,@forward替代@import后字体文件解析失败的问题
我完全懂你现在的困扰——之前用@import把theme npm包导入Angular组件库shared-elements时一点问题都没有,换成@forward之后就开始报字体文件找不到的错误,这确实挺让人摸不着头脑的。咱们先把问题的根源理清楚,再给你解决办法。
为什么@import能用,@forward就不行?
这本质上是@import和@forward在SCSS中的工作机制完全不同导致的:
- @import是「内容插入」:它会把你导入的SCSS文件的代码直接复制粘贴到当前文件里,相当于两个SCSS文件合并成了一个。之前你用
@import引入theme包时,_fonts.scss里的@font-face代码其实是直接被插入到组件库的编译上下文里的,这时候../fonts的相对路径是相对于组件库编译后的文件位置来解析的,刚好能对应到theme包中被安装到node_modules里的字体文件路径,所以不会报错。 - @forward是「模块暴露」:它不会复制代码,只是把另一个SCSS模块的变量、混合宏、样式规则暴露给外部引用,相当于建立了一个模块引用的链接。这时候Angular的Ivy编译或者ng-packagr在处理时,会保留theme包自身的模块上下文——
_fonts.scss里的../fonts路径是相对于theme包自己的scss文件夹的(也就是theme/src/scss/../fonts,对应theme/src/assets/fonts),但组件库编译时的上下文是自己的项目根目录,它会去自己的项目里找../fonts,而不是node_modules/theme/src/assets/fonts,自然就找不到字体文件了。
结合你的文件结构来说,theme包的_fonts.scss在src/scss下,../fonts指向src/assets/fonts,当用@forward时,组件库编译时不会把这个路径转换成相对于自己的路径,而是直接沿用theme包内的相对路径,导致解析失败。
解决办法
针对这个问题,你可以从以下几个方向入手:
1. 修改theme包内的字体路径为基于包的绝对路径
把_fonts.scss里的url路径改成指向theme包内字体文件的绝对路径(基于node_modules的位置):
@font-face { font-family: "webFont"; // 用~符号指向node_modules里的theme包 src: url("~theme/src/assets/fonts/web_font.woff") format("woff"); font-weight: 400; font-style: normal; }
这样Angular的编译工具会直接从node_modules/theme目录下找字体文件,不受当前编译上下文的影响。
2. 配置theme包的打包规则,调整字体文件的输出位置
修改theme包的打包脚本,把字体文件复制到和scss目录同层级的位置,比如打包后theme的dist目录结构变成:
dist/ ├─ scss/ │ ├─ _fonts.scss │ └─ theme.scss ├─ fonts/ │ └─ web-font.woff
然后把_fonts.scss里的路径改成url("./fonts/web_font.woff"),这样不管是@forward还是@import,相对路径都能正确解析。
你可以在theme包的package.json里的files字段指定要包含的资源:
"files": [ "dist/scss", "dist/fonts" ]
再配合打包脚本把src/assets/fonts复制到dist/fonts。
3. 在组件库的ng-package.json中配置资源复制
如果不想修改theme包,可以在shared-elements库的ng-package.json里添加assets配置,把theme包的字体文件复制到组件库的dist目录中:
{ "$schema": "../../node_modules/ng-packagr/ng-package.schema.json", "dest": "../../dist/shared-elements", "lib": { "entryFile": "src/public-api.ts" }, "assets": [ { "glob": "**/*.woff", "input": "./node_modules/theme/src/assets/fonts", "output": "./assets/fonts" } ] }
然后把theme包_fonts.scss里的路径改成url("../assets/fonts/web_font.woff"),这样组件库编译时会自动把字体文件复制到自己的dist目录,路径就能匹配上了。
4. 临时回退:在theme包中用@import转发(应急可用)
如果你暂时需要快速恢复功能,可以在theme包的theme.scss里用@import导入_fonts.scss,然后再用@forward暴露整个theme.scss:
// theme.scss @forward "xy"; @import "fonts"; // 先用@import把字体代码插入 @forward "fonts" hide *; // 再暴露变量等内容
不过这只是权宜之计,还是建议用前面的方法从根源解决。
内容来源于stack exchange

