字体图标在生产环境乱码的问题

问题描述

使用 element-ui 或者使用字体图标时,并且同时使用 dart-sass 来编译你的 scss/sass 代码,在生产环境偶尔就会出现图标变成乱码的现象,类似这样:

字体图标乱码示例

很多文章会让你改用 node-sass 来解决这个问题,诚然,node-sass 中不存在这个问题,因为 node-sass 没有在编译的时候将 ASCII 码做 UTF-8 转换,但 node-sass 因低下的性能且难以安装的特性,已然被淘汰了。可是 sass 的作者似乎不太支持 ASCII 码不做转换的行为,所以提供了其他方式来解决这个问题。

解决方案一

Vue CLI

如果你是使用 Vue CLI 创建的项目,那么你可以在 vue.config.js 中加入以下配置:

vue.config.js
1
2
3
4
5
6
7
8
9
module.exports = {
css: {
loaderOptions: {
scss: {
sassOptions: { outputStyle: 'expanded' },
},
},
},
}

webpack

如果你是使用 webpack ,那么你可以在 webpack.config.js 中加入以下配置:

webpack.config.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
module.exports = {
// ...
module: {
rules: [
{
test: /\.scss$/,
use: [
'style-loader',
'css-loader',
{
loader: 'sass-loader',
options: {
// 同 vue.config.js 中的 css.loaderOptions.scss.sassOptions
sassOptions: { outputStyle: 'expanded' },
},
},
],
},
],
},
}

那么就会在编译输出的 css 文件顶部加入 charset 声明:

1
2
3
4
5
6
7
8
9
10
/* input */
.title::after {
content: '\1F46D';
}

/* output */
@charset "UTF-8";
.title::after {
content: '👭';
}

这时浏览器会明确使用 utf-8 格式来解析 css 文件。

解决方案二(不推荐)

如果你使用了 postcssVue CLI 创建的项目默认使用了 postcss,所以也适用以下方案),那么也可以用 postcss 的插件来将 UTF-8 字符转换为 ASCII 的表示形式。

postcss-sass-unicode 插件

安装 postcss 的插件 postcss-sass-unicode

npm install postcss-sass-unicode --save-dev

配置

配置 postcss.config.js,根目录没有则新建

postcss.config.js
module.exports = {
// ...
plugins: [require('postcss-sass-unicode')],
// ...
}

编译结果对比

1
2
3
4
5
6
7
8
9
/* input */
.title::after {
content: '\e6e9';
}

/* output */
.title::after {
content: '\e6e9';
}

不推荐的原因

这种方式不推荐,因为插件没有对其他场景做处理,导致 content 中有多个中文字符的时候转换出问题,比如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/* input */
.title::after {
content: '你好';
}

/* output */
.title::after {
content: '\597d'; /* \597d = 好 */
}

/* input */
.title::after {
content: '👼';
}

/* output */
.title::after {
content: '\dc7c'; /* \dc7c = � */
}

终极解决方案

使用 svg 图标。

完。