共计 2398 个字符,预计需要花费 6 分钟才能阅读完成。
发现问题
最近在应用公司组件库中的穿梭框组件时发现 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 开发入门
正文完