Webpack 是一个前端资源加载/打包工具。它将根据模块的依赖关系进行静态分析,然后将这些模块按照指定的规则生成对应的静态资源。

它的异步加载原理是,事先将编译好后的静态文件,通过js对象映射,硬编码进打包后的 manifest.xxxx.js 文件中,然后通过JSONP原理按需加载每个chunk。

每个子模块加载完毕之后,浏览器将会进行本地缓存,从而节省了网络带宽。

  Webpack编译后的目录结构如下:

从结构目录来看,整个项目的入口就是index.html,我们来看看index.html的内容:

<!DOCTYPE html>
<html>
<head>
<meta charset=utf-8>
<title>www.phpdragon.com</title>
<script></script>
<link href=/static/css/app.4a4f13cfbe19aa22b83c451c96f49338.css rel=stylesheet>
</head>
<body>
<div id=app>
<transition :name=transitionName>
<router-view></router-view>
</transition>
</div>
<script type=text/javascript src=/static/js/manifest.f726e03ee32bcdee633a.js></script>
<script type=text/javascript src=/static/js/vendor.fa5ac3dc9fb740bb48c5.js></script>
<script type=text/javascript src=/static/js/app.af822fb16a16ef70005b.js></script>
</body>
</html>

其中引入了3个js文件,和一个css样式文件。

我们看看manifest.f726e03ee32bcdee633a.js这个js加载器。

找到这段代码:

是不是发现很熟悉!这一段jsonp代码,这就是用来实现按需加载js资源文件的加载器。

讲到了这,从上述代码就引出了一个问题:

当前端脚本重新编译了以后,项目发布采用的是删除重置发布,由于静态文件只加载一次的缘故,会导致按需加载模块时报错:Loading chunk " + e + " failed.

原因是浏览器已经缓存了manifest.f726e03ee32bcdee633a.js这个加载器,然后访问新的导航栏的时候,服务器端已经不存在旧版本的JS静态资源文件了,从而导致系统异常。

解决方法:

方案一:每次都加载项目入口文件 index.html。也就是说服务器端设置index.html文件不缓存、或者通过URL后缀添加随机字符串来解决。

这个方案适合入口URL可变更的系统。但对于ERP这种内部系统来说,可行性不是很好。

由于入口只加载一次,导致点击系统的其他导航栏URL操作,无法做到再次加载index.html文件,刷新浏览器缓存的JS。

第一种方案可以放弃了!

方案二:给每个导航栏路由URL添加随机数。

这个也不行,并不会导致index.html被重新加载。具体原因,请详看源码解析:vue-router源码分析-整体流程

方案三: 系统内部通过ajax请求获取版本信息从而提示更新。

这个可行,但对后端系统有侵入性,需要后端同学配合。对与跨工种跨部门来说,这种方式属于下策。

方案四:

方案二提到了路由,那么vue的路由是否提供了钩子机制,从而进行拦截呢?

官方是提供的,详看官方文档:vue导航钩子

通过如下这段代码,我们就能实现我们想要的功能了。一、确保了检测的频率。同时也对系统内部的AJAX请求减少侵入性代码。

router.beforeEach((to, from, next) => {
// ...
})

1.最终解决如下:在 main.js 中添加如下代码:

router.beforeEach((to, from, next) => {
axios.get('../static/version.json?_=' + Math.random()).then(response => {
if (200 == response.status) {
if (process.env.VERSION !== response.data.version) { var message = "系统版本有更新,点击确认加载最新,或按【CTRL + F5】!"
Vue.prototype.$alert(message, '系统提示', {
confirmButtonText: '确定',
callback: function(){
window.location.reload(true);
}
}); return;
}
next();
}
}).catch(err => {
console.error(err);
next();
});
});

2.添加版本变量:

3.给编译环境添加env变量:

4.通过Webpack的编译插件机制,引入 diy-plugin.js 自定义插件脚本,生成版本信息:

'use strict';

var FStream = require('fs');
var Archiver = require('archiver'); //npm install archiver /**
* 版本信息生成插件
* @author phpdragon@qq.com
* @param options
* @constructor
*/
function DiyPlugin(options) {
this.options = options || {};
this.options.outZipFile = this.options.path + '/front.zip'; !this.options.versionDirectory && (this.options.versionDirectory = 'static');
} //apply方法是必须要有的,因为当我们使用一个插件时(new somePlugins({})),webpack会去寻找插件的apply方法并执行
DiyPlugin.prototype.apply = function (compiler) {
var self = this; compiler.plugin("compile", function (params) {
var dir_path = this.options.context + '/' + self.options.versionDirectory;
var version_file = dir_path + '/version.json';
var content = '{"version":' + self.options.env.VERSION + '}'; FStream.exists(dir_path, function (exist) {
if (exist) {
writeVersion(self, version_file, content);
return;
} FStream.mkdir(dir_path, function (err) {
if (err) throw err;
console.log('\n创建目录[' + dir_path + ']成功'); writeVersion(self, version_file, content);
});
});
}); //编译器'对'所有任务已经完成'这个事件的监听
compiler.plugin("done", function (stats) {
console.log("开始打包压缩编译文件..."); var output = FStream.createWriteStream(self.options.outZipFile);
var archiveZip = Archiver('zip', {zlib: {level: 9}}); archiveZip.on('error', function (err) {
throw err;
}); archiveZip.pipe(output);
archiveZip.directory(self.options.path + '/' + self.options.versionDirectory, self.options.versionDirectory);
archiveZip.file(self.options.path + '/index.html', {name: 'index.html'});
//archive.glob(self.options.path + '/*.*');
archiveZip.finalize();
});
}; const writeVersion = (self, versionFile, content) => {
console.log("\n当前版本号:" + self.options.env.VERSION);
console.log("开始写入版本信息..."); //写入文件
FStream.writeFile(versionFile, content, function (err) {
if (err) throw err;
console.log("版本信息写入成功!");
}); //删除之前的压缩包
FStream.exists(self.options.outZipFile, function (exists) {
if (exists) {
FStream.unlinkSync(self.options.outZipFile);
}
});
} module.exports = DiyPlugin;

5.在webpack配置文件中添加 diy-plugin.js 编译钩子:

6. ok,至此结束。 执行编译:

npm run build

7. 访问项目,再次编译版本,打开之前的项目界面,点击其他导航菜单,效果如下:

以上,日常的一些开发点滴。

PS:

Webpack插件开发

vue-router源码分析-整体流程

Vue.js——vue-router 60分钟快速入门

webpack + vue 项目 自定义 插件 解决 前端 JS 版本 更新 问题的更多相关文章

  1. webpack+vue项目实战(四,前端与后端的数据交互和前端展示数据)

    地址:https://segmentfault.com/a/1190000010063757 1.前言 今天要做的,就是在上一篇文章的基础上,进行功能页面的开发.简单点说呢,就是与后端的数据交互和怎么 ...

  2. vue新手入门之使用vue框架搭建用户登录注册案例,手动搭建webpack+Vue项目(附源码,图文详解,亲测有效)

    前言 本篇随笔主要写了手动搭建一个webpack+Vue项目,掌握相关loader的安装与使用,包括css-loader.style-loader.vue-loader.url-loader.sass ...

  3. 浅析vue封装自定义插件

    在使用vue的过程中,经常会用到Vue.use,但是大部分对它一知半解,不了解在调用的时候具体做了什么,因此,本文简要概述下在vue中,如何封装自定义插件. 在开始之前,先补充一句,其实利用vue封装 ...

  4. 解决webpack vue 项目打包生成的文件,资源文件均404问题

    最近在使用webpack + vue做个人娱乐项目时,发现npm run build后,css js img静态资源文件均找不到路径,报404错误...网上查找了一堆解决办法,总结如下 一.首先修改c ...

  5. vue-cli的webpack模版项目配置解析-build/dev-server.js

    我们在使用vue-cli搭建vuejs项目(Vuejs实例-01使用vue-cli脚手架搭建Vue.js项目)的时候,会自动生成一系列文件,其中就包含webpack配置文件.我们现在来看下,这些配置到 ...

  6. 手动搭建webpack + vue项目之初体验

    在使用vue做开发时,大部分人只会使用官方提供的脚手架搭建项目,脚手架虽然很好用,但想要成为一名优秀的前端开发者,webpack这一道坎是绕不开的,所以我们要学会脱离脚手架,利用webpack手动搭建 ...

  7. 为 VUE 项目添加 PWA 解决发布后刷新报错问题

    为什么要给 VUE 项目添加 PWA 为什么要添加?因为不管是部署在 IIS,还是 nginx,每次应用部署后,再次访问因为旧的 js 已经不存在,所以页面访问的时候会整个报错,报错的结果就是一个白屏 ...

  8. vue项目及插件

    vue项目的创建 方法1: cmd中执行 vue ui vue会创建一个socket,方便快捷 方法2: 命令行建立 vue create v-proj //创建项目名为v-proj的项目文件 > ...

  9. vue之自定义插件

    1.插件的作用 插件通常会为 Vue 添加全局功能,一般是添加全局方法/全局指令/过滤器等 Vue 插件有一个公开方法 install ,通过 install 方法给 Vue 添加全局功能 通过全局方 ...

随机推荐

  1. python图片和分形树

    链接: 这10个Python项目很有趣! Python 绘制分形图(曼德勃罗集.分形树叶.科赫曲线.分形龙.谢尔宾斯基三角等)附代码 使用Python生成树形图案 神奇的代码:用 Python 生成分 ...

  2. 数据结构C语言版--静态顺序表的基本功能实现(一)

    /* * 功能:创建一个线性表,并输出 * 静态分配内存 */ #include<stdio.h> //stdio.h是C的标准I/O库 //#include<iostream> ...

  3. 什么是SASS

    一.什么是SASS SASS是一种CSS的开发工具,提供了许多便利的写法,大大节省了设计者的时间,使得CSS的开发,变得简单和可维护. 本文总结了SASS的主要用法.我的目标是,有了这篇文章,日常的一 ...

  4. Tomcat热部署SpringMVC项目出错

    一.问题 项目照常跑,没有什么大的影响,但是在控制台却出现了错误,具体信息如下图所示 二.解决方法 原因分析:很多人已经说的很明白了,这大概是因为项目文件很多,在tomcat重启的时候,之前的tomc ...

  5. SpringMVC+Thymeleaf +HTML的简单框架

    一.问题 项目中需要公众号开发,移动端使用的是H5,但是如果不用前端框架的话,只能考虑JS前端用ajax解析JSON字符串了.今天我们就简单的说下前端框架Thymeleaf如何解决这个问题的: 二.开 ...

  6. SqlSession介绍

    SqlSession是MyBatis的关键对象,是执行持久化操作的对象,类似于JDBC中的Connection.它是应用程序与持久存储层之间执行交互操作的一个单线程对象,也是MyBatis执行持久化操 ...

  7. top命令详析及排查问题使用演示

    1. top基本使用 top命令运行图 第一行:基本信息 第二行:任务信息 第三行:CPU使用情况 第四行:物理内存使用情况 buff/cache: buffers 和 cache 都是内存中存放的数 ...

  8. 美化你的GRUB,全面支持中文(菜单、提示、帮助)适用7.04-9.04

    本文根据网络资料整理而成,在此鸣谢各位作者. 本方法适合 7.04-9.04版本,9.10使用了grub2,请看这里. http://forum.ubuntu.org.cn/viewtopic.php ...

  9. Mysql INSERT、REPLACE、UPDATE的区别

    用于操作数据库的SQL一般分为两种,一种是查询语句,也就是我们所说的SELECT语句,另外一种就是更新语句,也叫做数据操作语句.言外之意,就是对数据进行修改.在标准的SQL中有3个语句,它们是INSE ...

  10. 基于Centos搭建Maven 安装与使用

    CentOS 7.2 64 位操作系统 安装 Maven Maven 简介 Apache Maven 是一个软件项目管理及自动构建工具,由 Apache 软件基金会所提供.基于项目对象模型(缩写:PO ...