发现问题
最近在应用公司组件库中的穿梭框组件时发现icon
图标全都乱码了
剖析问题
经排查发现,组件款式文件(scss
)引入的iconfont
矢量图标字体,构建时,\e601
这类Unicode
字符在通过sass
编译后就变成了文字字符(双字节字符),导致呈现乱码
.icon-ok:before { content: "\e601";}
Sass
编译后
.icon-ok:before { content: "";}
解决问题
(1)降级sass版本
在Sass@1.38.0
版本中对这个问题做了修复,能够将我的项目中应用的版本下级到1.38.0+
,详情查看Sass
更新日志
// index.scss.icon-ok:before { content: "\e601";}
执行npx sass@1.38.0 index.scss index.css
// index.css.icon-ok:before { content: "\e601";}/*# sourceMappingURL=index.css.map */
(2)自定义webpack loader
下面剖析问题时说到构建时Sass
将Unicode
字符编译成文字字符,那么咱们能不能在loader
队列中sass-loader
后退出咱们自定义的loader
,将CSS
中的文字字符转译成Unicode
字符呢?当然是能够的
const CONTENT_MATCH_REG = /(?<!-)content\s*:\s*([^;\}]+)/g; // 找出伪元素里content那块内容const UNICODE_MATCH_REG = /[^\x00-\xff]/g; // 找出非单字节符function fun(source) { this.cacheable(); // 利用缓存来进步编译效率 source = source.replace(CONTENT_MATCH_REG, function (m, p1) { return m.replace(UNICODE_MATCH_REG, function (m) { return "\\" + m.charCodeAt(0).toString(16); // m.charCodeAt(0)返回字符串第一个字符的 Unicode 编码,前面再转16进制,后面加一斜杠 }); }); return source;}
测试
let test = `.el-icon-ice-cream-square:before { content: ""; }`;console.log(fun(test));// 打印后果// .el-icon-ice-cream-square:before {// content: "\e6da";// }
能够参考:https://github.com/styzhang/c...
(3)自定义webpack plugin
开发webpack
插件须要晓得的几个必要条件:
- 获取编译器 compiler 对象,通过这个对象能过获取包含
config
配置,资源文件,编译信息,钩子函数等信息 - 编译阶段的生命周期函数,找到适宜的钩子函数解决对应逻辑
- 返回后果反对同步和异步两种形式
/** * 编码unicode字符串 * encodeUnicodeChar('•') // 等价于 '\\2022'; */module.exports.encodeUnicodeChar = function (str) { let content = ""; for (let i = 0; i < str.length; i++) { const codePoint = str.codePointAt(i); if (codePoint > 127) { content += "\\" + str.codePointAt(i).toString(16); } else { content += str.charAt(i); } } return content;};module.exports.encodeCssContentUnicodeChar = function (css) { return css.replace( /([{\s;]content:\s?['"])(.+?)(['"][;\s}])/g, (match, p1, p2, p3, offset, str) => { return p1 + module.exports.encodeUnicodeChar(p2) + p3; } );};
在将构建后的生成的资源文件输入到目标目录之前执行,emit
是一个异步系列钩子
const { encodeCssContentUnicodeChar } = require("./utils");class CssContentUnicodePlugin { apply(compiler) { compiler.hooks.emit.tap("CssUnicodePlugin", function (compilation) { Object.keys(compilation.assets) .filter((filename) => /\.css$/.test(filename)) .forEach((filename) => { const asset = compilation.assets[filename]; let fileContent = asset.source(); fileContent = encodeCssContentUnicodeChar(fileContent); asset.source = () => fileContent; asset.size = () => fileContent.length; }); }); }}module.exports = CssContentUnicodePlugin;
参考:
Sass更新日志
sass unicode字符编码问题
Sass:unicode本义没有保留在.css文件中
webpack篇-插件plugin开发
如何开发一个webpack loader
webpack loader开发入门