当前位置: 首页 > news >正文

【异常】记一次前端因资源无法加载导致白屏异常问题

一、背景

自从运维同事强烈要求前端的环境要使用多套的,参考文章
【项目】参考若依的前端框架去多环境
于是一番捣鼓与改造之后,看似已经顺利了
在这里插入图片描述
但运维说,前端还是有问题,需要他帮我改下,于是改了如下内容
在这里插入图片描述
什么嘛,为啥要帮我加上web?然后说还剩下最后一个问题,留给我慢慢改(自行解决)。
内心崩溃,为啥不一起改了呢??于是让我们来分析到底问题出在了哪里???

二、异常截图

2.1 页面:沙箱环境的前端页面显示了白屏

在这里插入图片描述

2.1 F12查看 控制台输出

F12一查看,错误的内容提示如下红色的部分,提示的意思是说以下JS的资源找不到
在这里插入图片描述
放大一点点看
在这里插入图片描述
在这里插入图片描述

这些文件都是哪里产生的呢?404就是提示找不到文件路径的报错嘛明显是~

前端大神说这个 web 目录,webpack 不会自动帮你生成的,需要自己在服务器创建 web 目录
然后把所有的资源文件,放在 web 目录下,其实是一个道理嘛。详细是以下代码进行dist的移动工作的
在这里插入图片描述

运维的很明白,因为加了web目录文件,前端打包完的dist文件是放在web目录下的。
因此,需要 解决的问题是 把这些JS等资源文件都要移动到 web路径,但是应该怎么实现呢?
在这里插入图片描述

三、问题排查与修复

3.1 定位错误代码, 查看configureWebpack

首先怀疑的是就是这个内容,发现以下的写法,我也看不懂啊。
在这里插入图片描述
这一段是对输出output进行配置,对文件名进行加version之类的吧?
version是一个变量,变量值的话,在前面有定义过
const version = new Date().getTime() + '-' + process.env.VERSION
原来写这一块的前端同事反馈,这个是因为某个项目出现过缓存没有及时更新的问题,于是需要加上这个配置
但是这里明显是有问题,从输出来看,web前缀,并没有帮我加上?那问题究竟出在哪?

一轮百度以及请教了前端大神之后发现,以下的写法确实是有问题的~大家的通用做法是这样的。
参考以下配置,我们开始了调试之旅

output: {
    filename: '[name].[chunkhash].js',
    chunkFilename: '[name].[chunkhash].js',
    publicPath: publishPath.publishPath + publishPath.prefix +'/'
  },

3.1.1 尝试1:加上前缀/web (无效)

试着加上前缀

        output: {
            filename: `/web/js/[name].${version}.js`,
            chunkFilename: `/web/js/[name].${version}.js`
        },

3.1.2 尝试2: 增加process.env.VUE_APP_CONTEXT_PATH前缀

        output: {
            filename: `${process.env.VUE_APP_CONTEXT_PATH}js/[name].${version}.js`,
            chunkFilename: `${process.env.VUE_APP_CONTEXT_PATH}js/[name].${version}.js`
        }

3.1.3 尝试3:注释掉output(无效)

        //output: {
            // filename: `${process.env.VUE_APP_CONTEXT_PATH}js/[name].${version}.js`,
            // chunkFilename: `${process.env.VUE_APP_CONTEXT_PATH}js/[name].${version}.js`
       //}

3.1.4 尝试4: 删除version (无效)

          output: {
            filename: `/web/js/[name].js`,
            chunkFilename: `/web/js/[name].js`
         },

3.1.5 尝试5:增加publishPath和path (无效)

         output: {
            filename: `/web/js/[name].js`,
            chunkFilename: `/web/js/[name].js`
            publishPath: 'web/',
            path: path.resolve(__dirname, "dist"), // string
         },

3.1.6 经过多轮尝试与请教后,最后的正确版本是

const isDev = process.env.ENV === 'development'
 output: {
            filename: isDev ? `[name].js` : `[name].[chunkhash].js`,
            chunkFilename:  isDev ? `[name].js` :`[name].[chunkhash].js`,
 },

看到这,你肯定会有以下的疑问?

  • (1)为啥要加上isDev
    参考一下文章:
    【异常】Cannot use [chunkhash] or [contenthash] for chunk in ‘[name].[chunkhash].js‘

  • (2)chunkhash的作用是啥?
    后面的文章会讲到, 反正最后是配置了这个,这个是请教了前端大佬给的建议

  • (3)为什么去掉了publishPath?
    因为vue对webpack进行重写了,publishPath提前写了。
    在这里插入图片描述
    在这里插入图片描述

3.2 尝试在本地进行prod脚本的构建

听前端大神的,可以先排除一下自己编译出来的文件有没有问题,那就本地先build起来啊!
本地能build,服务器也肯定能build的啊,然后看一下生成的 dist 目录里有啥先。

于是现在对本地进行调试吧 ,本地build一下先,但是本地遇到了不能build 情况, 如果本地都不能 build,那么部署是不会成功的

3.2.1 configuration.output.chunkFilen iame: A relative path is expected.

本地的构建过程中,得到过这个错误提示
什么相对路径的问题?看来还不能乱配置 斜杠啊。

 - configuration.output.chunkFilename: A relative path is expected. However, the provided value "/web/js/[name].1673275185922-1.0.0.js" is an absolute path!
   -> The filename of non-entry chunks as relative path inside the `output.path` directory.
WebpackOptionsValidationError: Invalid configuration object. Webpack has been initialised using a configuration object that does not match the API schema.

在这里插入图片描述
在这里插入图片描述

3.2.2 npm run build:prod的编写

以下这个是不会进行构建的npm run prod
正确的应该是npm run build:prod,因为里面必须要是有build
在这里插入图片描述
注意:要有类似于以下的输出,才算是真正的build了哦!

在这里插入图片描述
build后,会出现这个dist文件。
在这里插入图片描述
打开的index文件都带有web前缀。难怪找不到文件。。
在这里插入图片描述

什么情况,这个build:prod 的script竟然会写错了?
在这里插入图片描述
这个问题运维也没有发现,其实在Jenkins的构建日志中也是可以看到是没有输出结果的。
因为Jenkins只保留最近几次的构建,历史的已经很难看到了,无法截图输出了。
在这里插入图片描述

3.2.3 在开发环境的也试着加入web前缀

在这里插入图片描述
发现资源文件还是没有找,最后,要将dev的脚本改成如下,才能够正常访问业务。
在这里插入图片描述

四、 看看还有没有其他改动点?

4.1 终于不会白屏啦

终于,通过以上修改,至少不会白屏了。。。终于剩下最后一个问题了啦,这个问题好解决,之前解决过嘿嘿。
在这里插入图片描述

4.2 参考别的项目的配置

运维反馈,这个问题是因为环境配置里的 VUE_APP_BASE_API 没生效
说罢给了以下截图,让我参考
在这里插入图片描述
在这里插入图片描述

4.3 你确定你的Nginx配置没有问题?

于是先怀疑,Nginx的反向代理没有配置或者是配置有错?运维说, 不可能!

4.4 提示了不同的错误码了哦

于是我继续排查,试着加上了web作为前缀,发现还是不行,还是提示错误
不过!!!现在提示502了???有进展!
在这里插入图片描述

4.5 代码重定向的逻辑排查

从异常来看,是 直接进行了代码重定向
在这里插入图片描述
那是那段逻辑进行了重定向呢??于是,便利了代码后锁定以下代码
在这里插入图片描述
让我们详细看看,这一段代码逻辑

import { showSpin, hideSpin } from '@/utils/baseTool'
import axios from 'axios'
import store from '../store'
import { getToken, removeToken } from '../utils/cookie'

// 创建axios实例
const service = axios.create({
  // axios中请求配置有baseURL选项,表示请求URL公共部分
  baseURL: '/api/',
  // 超时
  timeout: 100000,
  headers: {
    get: {
      'Content-Type': 'application/json;charset=utf-8'
    }
  }
})

// request拦截器
service.interceptors.request.use(
  config => {
    // 登录界面
    if (config.url.indexOf('/login') !== -1) {
      config.headers['Content-Type'] = 'application/x-www-form-urlencoded;charset=utf-8'
      config.headers.Accept = 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9'
    } else if (getToken()) {
      config.headers.Authorization = 'Bearer ' + getToken() // 让每个请求携带自定义token 请根据实际情况自行修改
    }
    showSpin()
    return config
  },
  error => {
    return Promise.reject(error)
  }
)

// 响应拦截器
service.interceptors.response.use(
  res => {
    hideSpin()
    const code = res.data.resultCode
    if (code) {
      if (code === 401) {
        store.dispatch('LogOut').then(() => {
          location.href = '/#/login' // 为了重新实例化vue-router对象 避免bug
        })
      } else if (code === 1005) { // 用户未登录
        removeToken()
        location.href = '/#/login'
      } else if (code !== 0) {
        const errorMsg = res.data.resultDesc
        return Promise.reject(new Error(errorMsg))
      }
    } else {
      return res.data
    }
  },
  error => {
    hideSpin()
    return Promise.reject(error)
  }
)

export default service

在创建 创建axios实例的时候,使用了baseURL: '/api/',

这是不是就是我要的呢?我希望在所有的请求前面都加上/web的前缀 啊。

4.6 代码逻辑调整

于是做了如下代码的调整

(1)定义前缀变量

const prefix = process.env.VUE_APP_CONTEXT_PATH

(2)baseURL的修改

// 创建axios实例
const service = axios.create({
    // axios中请求配置有baseURL选项,表示请求URL公共部分
    baseURL: process.env.VUE_APP_BASE_API,
    // 超时
    timeout: 100000,
    headers: {
        get: {
            'Content-Type': 'application/json;charset=utf-8'
        }
    }
})

(3)使用前缀变量

           if (code === 401) {
                store.dispatch('LogOut').then(() => {
                    location.href = prefix + '#/login' // 为了重新实例化vue-router对象 避免bug
                })
            } else if (code === 1005) { // 用户未登录
                removeToken()
                location.href = prefix + '#/login'
            } else if (code !== 0) {
                const errorMsg = res.data.resultDesc
                return Promise.reject(new Error(errorMsg))
            }

5、验证

最后,终于是可以进入了,总结为啥会有这此问题吧,

(1)对npm的构建不熟悉,导致了scripts脚本都会写错。
(2)对webpack不熟悉,不懂构建webpack是如何控制构建结果的。

相关文章:

  • 基于卷积神经网络的疲劳驾驶检测识别系统源码,含数据集和权重文件
  • springboot多项目结构
  • 对认定为奉贤区单项冠军企业的给予一次性30万奖励
  • 一辈子干好一件事,你就了不起
  • 前端基础(十)_Dom自定义属性(带案例)
  • CSDN编程竞赛 ——— 第二十一期
  • java笔记(十二)重新理解java基本特性
  • 【BP靶场portswigger-服务端8】文件上传漏洞-7个实验(全)
  • STM32常用开发案例,STM32开发方案含USB升级、Fatfs存储、软件定时器、数据结构、按键处理库、解析单行带空格的字符串
  • kettle简单的ETL抽取同步两个库之间的数据
  • C语言常用字符串函数
  • 基于 js 制作一个贪吃蛇小游戏
  • 你知道猜凶手和猜名次如何利用编程实现吗?
  • SpringBoot动态生成接口
  • 一图读懂mybatis 查询接口的源码流程
  • eclipse的离线汉化
  • express如何解决request entity too large问题
  • GitUp, 你不可错过的秀外慧中的git工具
  • HTML中设置input等文本框为不可操作
  • Javascript编码规范
  • javascript从右向左截取指定位数字符的3种方法
  • JavaScript设计模式与开发实践系列之策略模式
  • Java方法详解
  • jdbc就是这么简单
  • Magento 1.x 中文订单打印乱码
  • MySQL主从复制读写分离及奇怪的问题
  • Spark VS Hadoop:两大大数据分析系统深度解读
  • text-decoration与color属性
  • 初识 beanstalkd
  • 基于Vue2全家桶的移动端AppDEMO实现
  • 设计模式 开闭原则
  • 使用 Docker 部署 Spring Boot项目
  • 微信端页面使用-webkit-box和绝对定位时,元素上移的问题
  • 一个项目push到多个远程Git仓库
  • 一加3T解锁OEM、刷入TWRP、第三方ROM以及ROOT
  • 字符串匹配基础上
  • UI设计初学者应该如何入门?
  • 说说我为什么看好Spring Cloud Alibaba
  • ​马来语翻译中文去哪比较好?
  • ###51单片机学习(1)-----单片机烧录软件的使用,以及如何建立一个工程项目
  • (安全基本功)磁盘MBR,分区表,活动分区,引导扇区。。。详解与区别
  • (附源码)springboot优课在线教学系统 毕业设计 081251
  • (附源码)ssm基于微信小程序的疫苗管理系统 毕业设计 092354
  • (一)VirtualBox安装增强功能
  • (转)Sql Server 保留几位小数的两种做法
  • (转)Sublime Text3配置Lua运行环境
  • ... fatal error LINK1120:1个无法解析的外部命令 的解决办法
  • .NET Core 2.1路线图
  • .net core 6 redis操作类
  • .net core 客户端缓存、服务器端响应缓存、服务器内存缓存
  • .NET运行机制
  • .set 数据导入matlab,设置变量导入选项 - MATLAB setvaropts - MathWorks 中国
  • .sys文件乱码_python vscode输出乱码
  • /etc/motd and /etc/issue
  • /etc/sudoer文件配置简析