2.记一次Icon没展示的bugfix

滴滴云控制台为了升级vue,UI库和脚手架,使用qiankun做了拆分。拆分后的发现Icon的展示有问题。

项目结构如下

1
2
3
4
5
6
7
|____node_modules
| |____ui-lib
| | |____index.css
| | |____fonts
| | | |____ui-lib.woff
|____src
| |____main.js

main.js

1
import 'ui-lib/index.css'

node_modules中的ui-lib

1
@font-face{font-family:ui-lib;src:url(fonts/ui-lib.woff) format("woff")}

vue.config.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
const publicPath = process.env.NODE_ENV === "production" ? '//cdn.myservice.com/' : `/`;
module.exports = {
publicPath,
configureWebpack: {
entry: { app:'./src/main.js'},
module: {
rules: [
{
test: /\.css$/,
exclude: /node_modules/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
importLoaders: 1,
},
},
{
loader: "postcss-loader",
options: {
postcssOptions: {
},
execute: true,
},
},
],
},
],
},
},
chainWebpack: config => {
const imgRule = config.module.rule('images');
imgRule.uses.clear();
imgRule
.use('file-loader')
.loader('file-loader')
.options({
name: 'img/[name].[hash:8].[ext]',
publicPath
})
.end()
},
}

编译后的文件app.css

1
@font-face{font-family:ui-lib;src:url(../fonts/ui-lib.woff) format("woff")}

这里变成了../fonts/ui-lib.woff,而没有变成预期的cdn.myservice.com/fonts/ui-lib.woff。所以浏览器加载的时候path报错了。
我最先尝试的是在configureWebpack.module.rules增加url-loader

1
2
3
4
5
6
7
8
{
test: /\.(woff?|eot|ttf|otf)(\?.*)?$/,
loader: 'url-loader',
query: {
limit: 2048,
name: 'fonts/[name].[hash:7].[ext]'
}
},

结果顺利的被解析成了base64。而base64的内容是module.exports = __webpack_public_path__ + "node_modules/ui-lib//fonts/ui-lib.b3909f8.woff";虽然浏览器调试台里preview展示如下,但是Icon仍然没展示出来。(这里为什么展示出来,但是没生效我也没想明白)

项目是vue-cli搭建的,其实非常困惑的是 const imgRule = config.module.rule('images');这里的images是代表什么,又没定义过,只好去翻vue-cli的文档
这里忍不住想吐槽一下vue-cli,为了简化上手成本,它默认内置了常用的loader和plugin,但是没有暴露出来。webpack的配置进到@vue/cli-service的项目中都看不到webpack的配置。根据文档,vue inspect > output.js。可以把所有内置的webpack信息输出出来。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
➜  demo git: ✗ vue inspect --rules
[
'vue',
'images',
'svg',
'media',
'fonts',
'pug',
'css',
'postcss',
'scss',
'sass',
'less',
'stylus',
'js',
'eslint',
'Nameless Rule (*)'
]
➜ demo git: ✗ vue inspect --rule fonts
/* config.module.rule('fonts') */
{
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
use: [
{
loader: 'file-loader',
options: {
publicPath: '/',
name: 'fonts/[name].[hash:8].[ext]'
}
}
]
}

同上例的config.module.rule(‘fonts’)一样,images也是对图片适用的loader配置,这猜破了脑袋也猜不出来(小声比比)。这页文档太宝贵了,这个问题迟早得遇到,早遇到早明白。

能解决问题的配置

1
2
3
4
5
6
7
8
 config.module.rule('fonts')
.test(/\.(woff2?|eot|ttf|otf)(\?.*)?$/)
.use('url-loader')
.loader('file-loader')
.options({
publicPath,
name: 'fonts/[name].[hash:8].[ext]'
})

上边的配置强行解释一波,把fonts的规则,test改为/\.(woff2?|eot|ttf|otf)(\?.*)?$/,把原来fonts的url-loader改为带options的file-loader

顺手把woff文件刨了一下,扔到解析网站,发现它是如下的样子

具体为什么在content里写上对应的code,就展示出了对应的icon。我也没搞懂。