1、bug 起因
昨天在 vue 项目中编写 element-ui 的树形结构的表格,发现项目中无法生效,定位问题之后发现项目使用的 element-ui 的版本是 2.4.11 。看了官方最新版本是 2.15.14,然后得知 2.4.11 版本是不支持表格树形结构的。于是决定升级 element-ui 的版本,方便后续的开发。
升级之后本地简单的过了一遍系统功能,并没有发现有什么不妥,于是就部署到公司的蓝鲸环境。然而早上却收到同事的报障,说是测试环境的下拉框不能够正常显示,我看了一下,样式如下:
于是开始排查原因,F12 之后看到图标的 content 值:
并没有出现乱码,也就排除了乱码的可能性了。于是继续排查问题,发现刷新系统页面的时候,有两个请求是 404.
查看请求 URL:
然后再查看我本地正常情况下的请求 URL:
可以看到,测试环境下的 URL 明显比我本地正常请求的 URL 多了 /static/css/,查看前端工程 /build/webpack.base.conf.js
文件可以发现,woff 和 ttf 这些字体会经由 url-loader 处理后在 static/fonts 目录下生成相应的文件。
2、打包前端工程
由于测试环境每次都要部署才能看到效果太过麻烦了,于是模拟测试环境的打包过程,将项目打包到本地,然后配置 nginx 配置文件使之能够正常访问,操作步骤如下:
- 进入 PC 路径,执行打包命令:
- 打包完成之后在 PC 目录下可以看到 dist 文件,这个文件就是打包的结果:
- 打包文件所在目录,将里面的内容拷贝到 ngxin 下的 html 目录下:
D:\Jungle\work\env\nginx-1.17.2-dev\html
- 修改 ng 配置,使之能够转发请求(不同 ng 转发原理的自行百度,这里只是贴出部分转发配置):
server {
listen 24695;
server_name localhost;
# 访问本地PC前端
location / {
root html; # 访问根目录 nginx-1.17.2-dev/html/PC
index index.html; # 入口文件,可以接受index、index.html、index.htm文件
}
}
- 之后访问:localhost:24695/PC 即可访问到打包后的服务
3、庖丁解牛,小菜一碟
再回顾一次我们的问题:
实际应该通过 /static/fonts/**
路径来获取字体图标,而实际却是请求 /static/css/static/fonts/**
,自然报 404 错误。
3.1、为什么我们实际请求的路径是:/static/css/static/fonts/**
呢?
让我们来看一下打包工程之后的文件目录结构:
可以看到,渲染的小图标和字体样式存放在 fonts 中,正确的加载路径自然是 /static/fonts/**
。那为什么会多了 /static/css 呢?
进入webpack.prod.conf.js
(prod 是我本次打包的环境,可能你的项目是叫 dev,sit 等等,这里需要找到对应的文件)
这个 BASE_URL 是样式渲染的根目录,通过拼接可以看出来,BASE_URL = ‘/static’,也就是说,在渲染样式的时候,定位到 /static 目录下。让我们在 webpack.prod.conf.js
继续往下,可以看到:
可以看到构建的文件路径是以 css/(文件名)/.css 开头的。因此在渲染样式的时候,扫描的文件路径是:/static/css/[name].[contenthash:8].css
。而在 element-ui-2.15.14 版本下,系统还会加载 font 目录下的两个文件,由于我所在项目配置问题,所以扫描的路径是基于当前路径/static/css
,所以拼接之后得到:/static/css/static/fonts/**
,这也就解释了为什么正确请求的路径是/static/fonts/**
,而实际发起的却是/static/css/static/fonts/**
了。
3.2、如何解决
在我的打包目录下:/build/utils.js
中,有这样一段代码:
// generate loader string to be used with extract text plugin
function generateLoaders(loader, loaderOptions) {
const loaders = []
// Extract CSS when that option is specified
// (which is the case during production build)
if (options.extract) {
loaders.push(MiniCssExtractPlugin.loader)
} else {
loaders.push('vue-style-loader')
}
loaders.push(cssLoader)
if (options.usePostCSS) {
loaders.push(postcssLoader)
}
if (loader) {
loaders.push({
loader: loader + '-loader',
options: Object.assign({}, loaderOptions, {
sourceMap: options.sourceMap
})
})
}
return loaders
}
只需要添加 publicPath: "../../"
即可
// generate loader string to be used with extract text plugin
function generateLoaders(loader, loaderOptions) {
const loaders = []
// Extract CSS when that option is specified
// (which is the case during production build)
if (options.extract) {
loaders.push({
loader: MiniCssExtractPlugin.loader,
options: {
publicPath: '../../' // 调整资源路径,确保从正确的目录加载字体
}
})
} else {
loaders.push('vue-style-loader')
}
loaders.push(cssLoader)
if (options.usePostCSS) {
loaders.push(postcssLoader)
}
if (loader) {
loaders.push({
loader: loader + '-loader',
options: Object.assign({}, loaderOptions, {
sourceMap: options.sourceMap
})
})
}
return loaders
}
publicPath
设置为'../../'
,webpack 会将所有资源的路径相对调整到父目录。例如原本资源拼接的目录为/static/css/static/fonts/
将会变成../../static/fonts/
。因此才能够正确加载我们的文件。
3.3、为什么升级之前没问题呢?
针对这个问题,我对比了刷新系统时,资源的请求:
发现在 element-ui-2.4.11 版本下,资源并没有去请求 /static/fonts/
下的文件。只加载了 css 文件(这一点我不清楚为什么,可能是 element-ui 的机制问题??有知道的请评论区告诉我)。所以在老版本下,即使不指定 publicPath: '../../'
,页面渲染也完全没有问题。
加上publicPath: '../../'
之后,重新打包
可以看到问题解决了。
参考文章:
https://github.com/vuejs-templates/webpack/issues/166
Vue.js - 解决部署到服务器后Element UI图标不显示问题(404错误)_element-icons.ttf和woff乱码-CSDN博客
vue-elementui-admin项目 woff,tff字体 404处理_element .woff 404-CSDN博客