问题:
项目使用 talebase-ui 组件的 iconfont 会偶尔出现乱码的情况:
问题定位分析:
定位到图标元素可以看到,组件的图标 Unicode 格式经 sass 编译后,都变成乱码格式了(错误地将 Unicode 字符作为文字字符编译输出):
图标未编译前:
1 2 3
| .t-icon-search:before { content: '\e651'; }
|
经 sass 编译后:
如果通过浏览器限速,模拟慢网速状态,则图标乱码的情况几乎每次必出现:
解决方案:
(1)node-sass 替换 sass(dart-sass):这是网上出现最多的建议,但考虑到目前项目使用的是 sass,切换 node-sass 需要环境配置的兼容,可能会有许多未知的问题出现,故没有采用。
(2) 升级 sass(推荐)
查看 sass 的更新日志,幸运的是在sass@1.38.0版本时修复了这个问题,将 Unicode 字符作为转义序列而不是文字字符输出。
目前项目安装的 sass 依赖版本是 1.32.0,升级至 1.48.0 最新版后:
(Unicode图标编译成功)
注意:升级 sass 版本后,项目可能会出现代码语法格式引起的报错(以下是宽度计算-号之间需加空格),修改成符合语法即可:
(3)采用自定义的 webpack loader:
问题原因是 sass 将 Unicode 字符当成文字字符进行编译了,也就是说可以通过在 webpack 配置中添加自定义的 loader 在 sass-loader 之前,实现将文字字符转译成Unicode字符再由sass编译。
转译原理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| .sass::after { content: "中国"; } .icon-content::after { content: "?"; }
.sass::after { content: "\4e2d\56fd"; } .icon-content::after { content: "\e6df"; }
|
webpack loader 实现:
1 2 3 4 5 6 7 8 9 10 11 12
| const UNICODE_MATCH_REG = /[^\x00-\xff]/g; const CONTENT_MATCH_REG = /(?<!-)content\s*:\s*([^;\}]+)/g;
module.exports = function (source) { source = source.replace(CONTENT_MATCH_REG, function (m) { return m.replace(UNICODE_MATCH_REG, function (m) { return "\\" + m.charCodeAt(0).toString(16); }); }); return source; }
|
webpack 配置:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| module.exports = { configureWebpack: config => { const sassLoader = require.resolve('sass-loader') config.module.rules .filter(rule => { return rule.test.toString().indexOf('scss') !== -1 }) .forEach(rule => { rule.oneOf.forEach(oneOfRule => { const sassLoaderIndex = oneOfRule.use.findIndex( item => item.loader === sassLoader ) oneOfRule.use.splice(sassLoaderIndex, 0, { loader: require.resolve('./css-unicode-loader') }) }) }) } }
|