最近因项目需要要将之前做的 npm 包的 css 样式,包括字体样式和字体文件(主要是使用了阿里的iconfont)打到js中,因为之前样式都是直接还是用外链的方式,要改掉,因此,花了一天的时间搞这个,碰到了些比较奇葩的事情,在此记录一下。
下载 iconfont 相关文件到本地
去掉了一些用不到的文件剩下如图所示文件,包括iconfont.css
、iconfont.eot
、iconfont.svg
、iconfont.ttf
、iconfont.woff
、iconfont.woff2
,iconfont.css是字体样式,其余的为字体文件:iconfont.woff2为主要目前流行的字体文件格式,兼容性最好,其他则是为了兼容不同浏览器及不同版本浏览器。
1 2 3 4 5 6 7 8
| @font-face {font-family: "iconfont_sp"; src: url('iconfont.eot?t=1575340034756'); src: url('iconfont.eot?t=1575340034756#iefix') format('embedded-opentype'), /* IE6-IE8 */ url('data:application/x-font-woff2;charset=utf-8;base64,此处为base64编码') format('woff2'), url('iconfont.woff?t=1575340034756') format('woff'), url('iconfont.ttf?t=1575340034756') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+ */ url('iconfont.svg?t=1575340034756#iconfont_sp') format('svg'); }
|
由此可见,阿里 iconfont+ 平台给我们生成的样式里面除了 woff2 打成了 DataUrl 即 转换成base64编码的字符串形式,并存储在 URL 中,冠以 mime-type,其他都都是之间都是直接使用文件路径。
改造 webpack 配置,将 css 打包进 js,最终输出 一个 umd 模块化的 npm 模块 js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| const path = require('path');
module.exports = { devtool: '#source-map', entry: [ './src/index' ], output: { path: path.resolve(__dirname, 'build'), filename: 'selectPartner.js', libraryTarget: 'umd', library: 'selectPartner' }, module: { rules: [ { test: /\.css$/, use: [ 'style-loader', 'css-loader', 'postcss-loader' ], include: path.resolve(__dirname, 'src') }, { test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/, loader: 'url-loader', options: { limit: 20000, name: 'fonts/[name]-[hash].[ext]' } }, { test: /\.(png|jpe?g|gif|svg)(\?.*)?$/, loader: 'url-loader', options: { limit: 20000, name: 'images/[name]-[hash].[ext]' } }, ] }, resolve: { extensions: ['.js', '.vue', '.json', '.html'] } };
|
使用css-loader 处理 css 文件,使用 url-loader 对 css文件中引用的字体文件进行处理,将字体文件打包成 DataUrl 即 转换成base64编码的字符串形式,并存储在 URL 中,冠以 mime-type。当一切都准备好,打包也ok,确定代码逻辑啥的是没问题的。虽然打包成功,但是还是要测试一下,因为将最终打包出来的 umd 模块代码导入到项目代码中测试,测试结果如下图。
icon图表并没有显示出来,审查一下元素查看对应样式代码,url 除了有一个 base64 是 iconfont+打包下来自带的 base64,其他的都是 [object Module]
,这问题看起来很奇葩。
原因排查
网上兜了一圈,找了挺久,终于在 stackoverflow 上找到类型的问题。
大概的意思就是我打包出来的东西违反了 csp 相关内容,浏览器为了安全拒绝读取相应的DataUrl数据。
什么是 csp,即内容安全策略( Content-Security-Policy ),是一个额外的安全层,用于检测并削弱某些特定类型的攻击,包括跨站脚本 (XSS) 和数据注入攻击等。无论是数据盗取、网站内容污染还是散发恶意软件,这些攻击都是主要的手段。具体就不展开细说。了解 csp 可参见 https://developer.mozilla.org/zh-CN/docs/Web/HTTP/CSP
疑问点及尝试解决方案
其实最终我打包出来的js里面是有将 eot、ttf、woff等这些文件 DataUrl (base64)数据的,但是浏览器并没有执行。
综合发现,除了 woff2 的 DataUrl mineType 是 application/x-font-woff2
,其他的都是 font/woff
这种方式。出于好奇,代码中把所有格式的字体 url 都去掉,只保留 woff2
。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| @font-face {font-family: "iconfont_sp"; src: url('data:application/x-font-woff2;charset=utf-8;base64,d09GMgABAAAAAAXAAAsAAAAAC3wAAAVwAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHEIGVgCDeAqIVIcHATYCJAMoCxYABCAFhREHgQYbzwnIrrApw6/Q3XaiJEI0Mxiwx0nwjQviye6rXncP/woMj2AEMj0HoYTZk9Od/t30VSx1CzVJJ27QiaXJS6BIuJCKp5vDxICa2/7c/80Gzy2tBIfSjxJ84wF35VVS83I2ZGzwvcL+/59jqZcJlt/u2uX/615kYAVtYAPM59FFAxsWSBKMfSbi1Zucjsybx0MAnwzKkNZbdh0C5hgiv6DTZAmNA/NWAjOjFNywPbKtQTYBiqtWG84BG/OPly/UiDkoLE10ou5jN5NgXSANuZr//zJoHrzbywGMnUADZYABmTeaNxejsq4Mje/VGNMR4H+Gi0IFdlAT7PmY2xgQiPCcUZ5PHC0NCo3Bwsbx/vE8EJsoEAbuvHoPAokBBQGgIQAMBIAFAWBDoIcDQY0eAsEePVxoyE3gge2vHAdEgVSCnBfczh0FjUJAVJwWZhUuBXYUpvcbNcBKMI6u1fTzISSs5vvUYRRZpR7IDKepmsxBTSjx4KFtj1x5YPL9HT5dUPOZ68PRaPkqtYtIl+mq1xx78MG0BlcDm9+vXFPNVwVYVdRk1qb0hqSQpkU69R3eWajVuNL6nAqn4xxiEh8x9WFJ6hDEe95dhvWmYofYm4/oPqkvRR889LEqANFVuMi/FdlU1ueGarXO5fUgHoB0jGQuHgzW6w2icwtc1ujUTl0IcmCm5KYsbg0fDa2dLr7B7tzuZDuv1rYHb9XnGuQOBle2B2qr3fm8FNc3nBSjrebQHbULcmbB6NM7mLMwWl/p7KzlnQ79xw0BtglzuBHV2kdtxASFRoBtjLL3OQzPIwCX1XGjb/9NP2Gac1z315QQuoXeJmwzmryEodROXlQaTVxc9M7EpfR1dd3NOeL3LJv3xjwF3GXG91NT7luEacz4fs1OvbdU39oyR1GQEC1DhUEi4DQqbceOqrqq2h2dvozow9VU3IvYsT096sKUL3pZsiPr7bb7Vlrq2oKHaQRSvQ+A6Aaaq2Pbtnc0Eqbz/M//may0NJPE+wDRe0alWnHfut/d+uDQeaK1OY+Y1olHmZd6nVa0RU6eNNhSJDGbsMWg9TL2fE1n96HV42OYyZgFZm7LFxxRWxYIy+TusRM/XdNZ+9yNzsN9puadNn6e8sM4eCTQ4gascV6L4n771/oG+TmtNRS2iGInds8dDgpuGnKGHf9Q0DN8buDm6AyydOJDk5Ji/JAwpcRTdze9XOMF7dt0BWrLMq82s51+O0ufLou3+Q2Y6aub26ijXjULg+c0QOMG/V2n5nVr9S8d11b+0Gl16/VKnQ4EYQowqP0gsH/6ViGU+Kn/HOY+mX6fsl31z7U0ADwNfVJKWeMqA7aTcBkpR+Az7mSOML47SvrGHVzs+inVT8AIPjoxfBoHn/GiGF5uOxTP7ghCiPgaFA5ZoAlRyDTcGqbFbcK0ue3Bp5ReO4eIZQFGiPGAEjYLEBI4BooI7oAmgVdMw/3HsKRiybS5AvDpK0v3GaJAriIbWYhzkERjklAJwSgomeaQ4pWnVMoDkI6T4WyvZ6USQVYlmYzOx+aNNG6FCshubwNVPL2A4yiUYhk5ukWcDMpkDKpkmVhIcJiY45QroqIo/4kwgpEDhFawQHA4ICQoI0kCZQIEDAqoNMDdrj56v8kpVCg5AIQmDhk47PwARmxFQFhUSOYGpZoKqnjMrQEFt89jbDmLeGgWqEoOaqWxsDDIQWmLHIiM6hhQpo8vFQuEgANj/Bo1SlZQqYw1lhvAjiIkf/zdf65+ovP5okSLEUtsccQVT3wJYY2SMSpoKm+Os4TYlIVyJh6asBJazJkRYkhIIWlMMgkKizhF85JOkGBUSjFkYSTFsJExrISkoSmBKwgoAwAAAAA=') format('woff2'); }
.iconfont_sp { font-family: "iconfont_sp" !important; font-size: 16px; font-style: normal; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; }
.icon_sp-close:before { content: "\e632"; }
|
试了一下,果真可以了,iconfont 字体显示出来。
总结
通过 url-loader 打报出来的 eot、ttf、woff 等文件打包出来的 DataUrl 对应 MIME Types 是有问题的,违反,stackoverflow 上找到了相关内容,https://stackoverflow.com/questions/26177849/mime-types-for-woff-ttf-svg-and-eot-404ing-despite-being-setup-in-iis。
1 2 3 4 5 6 7 8 9 10 11 12
| <staticContent> <remove fileExtension=".woff" /> <mimeMap fileExtension=".woff" mimeType="application/font-woff" /> <remove fileExtension=".ttf" /> <mimeMap fileExtension=".ttf" mimeType="application/font-ttf" /> <remove fileExtension=".eot" /> <mimeMap fileExtension=".eot" mimeType="application/vnd.ms-fontobject" /> <remove fileExtension=".otf" /> <mimeMap fileExtension=".otf" mimeType="application/font-otf" /> <remove fileExtension=".svg" /> <mimeMap fileExtension=".svg" mimeType="image/svg+xml" /> </staticContent>
|