问题描述
最近发现项目在测试环境下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'}
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。