问题描述
最近发现项目在测试环境下icon偶尔会出现乱码的情况,我自己本地一直没能复现,在测试环境复现的话就需要打开控制台,然后按键刷新,一次不行就多刷新几次,就可以复现这个问题。

原因分析
这个问题可能是因为项目中有用到element-ui库,而项目中安装的sass和element-ui源码中的sass(node-sass)安装版本不一致造成的。
项目中的sass

具体:
一般使用不会出现这个问题,因为一般引入的是element-ui的css文件,问题出在于为了主题色变化啊,需要用到scss变量引入了scss文件。
@import “~element-ui/packages/theme-chalk/src/index”;
而dart-sass在编译element-ui里icon伪元素的content unicode编码时会转换成对应unicode明文,所以通过伪元素来展示的图标如el-icon-arrow:before{ content: “\e6df”},编译之后就变成了el-icon-arrow:before{ content: “”},“”便是一个双字节字符,导致出现乱码。
解决方法
直接uninstall项目中的sass,然后安装node-sass(因为是公司项目,不好做修改)
- node-sass 是用 node(调用 cpp 编写的 libsass)来编译 sass;node-sass是自动编译实时的
- dart-sass 是用 drat VM 来编译 sass;dart-sass需要保存后才会生效
- node-sass 因为国情问题经常装不上
- sass官方已经将dart-sass作为未来主要的的开发方向了,有任何新功能它会优先支持
和后端商量下,让css资源请求的响应头的Content-Type增加"charset=utf-8"声明。(没做尝试)
看到大佬写的一个方法 https://github.com/styzhang/css-unicode-loader
安装大佬写的loader
yarn add css-unicode-loader --dev
对应的配置
if use vue-cli 4+ and scss(sass), add the loader in the vue config file .
// vue.config.js
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") });
});
});
}
}vue.config.js具体配置
const path = require('path');
const webpack = require('webpack');
const buildDate = JSON.stringify(new Date().toLocaleString());
let devServer = null;
try {
devServer = require('./devServer');
}
catch (e) {
devServer = {};
}
function resolve(dir) {
return path.join(__dirname, dir);
}
// 将之前的plugins提出来封装成一个函数
function getPlugins() {
const plugins = [
// Ignore all locale files of moment.js
new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/),
new webpack.DefinePlugin({
APP_VERSION: `"${require('./package.json').version}"`,
BUILD_DATE: buildDate,
}),
];
return plugins;
}
const vueConfig = {
// configureWebpack: {
// // webpack plugins
// plugins: [
// // Ignore all locale files of moment.js
// new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/),
// new webpack.DefinePlugin({
// APP_VERSION: `"${require('./package.json').version}"`,
// BUILD_DATE: buildDate,
// }),
// ],
// },
configureWebpack: config => {
config.module.rules.filter(rule => {
return rule.test.toString().indexOf('scss') !== -1;
})
.forEach(rule => {
rule.oneOf.forEach(oneOfRule => {
oneOfRule.use.splice(oneOfRule.use.indexOf(require.resolve('sass-loader')), 0,
{ loader: require.resolve('css-unicode-loader') });
});
});
// 获取plugins函数的内容
const plugins = getPlugins();
//这里要返回一个对象
return { plugins };
},
chainWebpack: (config) => {
config.plugin('html')
.tap(args => {
args[0].title = process.env.VUE_APP_TITLE;
return args;
});
config.module
.rule('svg')
.exclude.add(resolve('./src/assets/icons'))
.end();
config.module
.rule('icons')
.test(/\.svg$/)
.include.add(resolve('./src/assets/icons'))
.end()
.use('svg-sprite-loader')
.loader('svg-sprite-loader');
},
css: {
loaderOptions: {
less: {
// DO NOT REMOVE THIS LINE
javascriptEnabled: true,
},
},
},
devServer,
// disable source map in production
productionSourceMap: false,
lintOnSave: true,
// babel-loader no-ignore node_modules/*
transpileDependencies: [],
};
module.exports = vueConfig;验证方法
修改前yarn build,检查dist/css/app.xxx.css文件中的emp-icon-xxx:before{content:""}

修改后 yarn build ,检查dist/css/app.xxx.css文件中的emp-icon-xxx:before{content: '\xxx'}

总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持好代码网。




