发现问题
最近在使用公司组件库中的穿梭框组件时发现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;
参考:
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。