现象

刷新单页应用时,vue报错resource interpreted as Stylesheet but transferred with MIME type text/html
vue.png

解决步骤

1. nginx类型匹配配置

  • 根据错误提示,这是服务端无法正确解析css的MIME类型造成的。
  • 因此首先想到的是nginx配置是否正确,检查发现nginx配置没问题,与文件类型有关的配置如下:
http { include mime.types; #文件扩展名与文件类型映射表 default_type application/octet-stream; #默认文件类型,默认为text/plain }

排除该原因。

2. 单页面应用history模式nginx配置

  • 由于所做vue项目是单页面应用,因此刷新失败无法加载,考虑是否是配置404没有返回index页导致,根据官网配置,也没有问题
location / { try_files $uri $uri/ /index.html; }
  • 注释掉vue-router中的mode:'history’再构建项目也可以排除history模式404配置问题

3. css引入方式改写

默认的css引入方式为:

<link rel="stylesheet" href="//xxx.css">

增加可识别类型:

<link rel="stylesheet" type='text/css' href="//xxx.css">

无法解决问题。默认css引入方式都已经支持,不大可能因此报错,排除该原因。

4. vue/cli@3构建配置

上述报错的css路径形式为:

https://blog.feroad.com/admin/css/index.hash.css

怀疑路径不对,手动尝试更改为:

https://blog.feroad.com/css/index.hash.css

可以访问到压缩混淆后的css,这说明是路径错误。即vue/cli构建工具构建相对路径生成css导致的错误。检查vue.config.js发现:

module.exports = { baseUrl: process.env.NODE_ENV === 'production' ? './' : '/', // ./表示相对目录 /表示绝对目录 }

这段代码删掉即可解决问题。

问题反思

以下代码是手动加入vue.config.js文件中,使得yarn build后的项目能够直接在本地打开,它是自己每个vue项目初始化时使用的“小聪明”,它只在简单项目中没有问题。

baseUrl: process.env.NODE_ENV === 'production' ? './' : '/', // ./表示相对目录 /表示绝对目录

但在router中存在嵌套路由或者动态路由等“两层”以上的路由时,相对路径生成最终css包将导致路径错误。如下子路由:

<!--router.js--> { path: '/admin', name: 'admin', component: Admin, children: [{ path: '/admin/delete', name: 'delete', component: AdminDelete }, { path: '/admin/release', name: 'release', component: AdminRelease }] }

将造成AdminRelease组件中的css构建相对于host/admin的文件路径时候,生成的可访问css的路径错误,生成:

https://blog.feroad.com/admin/css/index.hash.css

而实际上/admin/这层并不应该出现。这个错误不容易发现。

结论与引申

因此,不要轻易改变vue工具的默认配置,除非明确了解修改配置造成的副作用。

  1. 尽管build后的文件不能本地打开,但可以使用本地node服务或者测试服务器去验证,不建议直接打开本地文件

  2. 在axios使用时,用到拦截器功能,请求拦截器将请求想JSON.stringify(data)再发送。这造成了使用FormData对象上传文件时无法发送file对象。因此需要判断request.data是否是FormData的实例再考虑是否stringify。

axios.interceptors.request.use( request => { if (request.method === 'post' && !(request.data instanceof FormData)) { request.data = Qs.stringify(request.data); return request; } return request; }, error => { return Promise.reject(error); } );
  1. 将vue渐进式引入老项目,逐步替换为vue模块的学习方法存在问题。应直接按照vue的思想去实践,上全家桶。
    • 如vue在构建单页面应用很成熟,而使用单页面与多页面混合应用来解决加载速度的问题,并且共用了vuex和router时,加载速度问题没解决,反而造成了每个单页加载内容过多,项目整体不规范的后果
    • 使用vue单页+nuxt服务端渲染这样规范的方案来解决加载速度和SEO的问题,不要“发明轮子”。