vue实现的多页面项目如何优化打包的步骤详解


Posted in Javascript onJuly 19, 2020

遇到的问题

在多页面框架打包的过程中会,随着业务的增加页面越来越多,使用的三方包也会越来越多,但并不是所有页面都会使用到三方插件,使用webpack打包会让所有的三方包打包到一起,会导致vendor.js(三方包打包后的文件)越来越大,即使没使用过三方插件的页面也会引入,页面加载会越来越慢.

如何优化

  •  使用cdn引入,这种就每次新建一个页面的时候手动通过cdn的方式引入,但是并不是特别好的方式,还需要手动加入.
  • 就是使用splitChunks分割三方包,将三方包单独打包出来,根据页面的依赖情况自动注入,但是这种情况分离的三方包并不会自动注入到对应的页面中去,所以就写了个自动注入的插件,原理就是在html页面生成之后,根据页面所依赖的chunks找到对应的静态资源,然后将得到的静态资源注入到页面中去。

 自定义webpack插件

webpack 就像一条生产线,要经过一系列处理流程后才能将源文件转换成输出结果。 这条生产线上的每个处理流程的职责都是单一的,多个流程之间有存在依赖关系,只有完成当前处理后才能交给下一个流程去处理。插件就像是一个插入到生产线中的一个功能,在特定的时机对生产线上的资源做处理。webpack 通过 Tapable 来组织这条复杂的生产线。 webpack 在运行过程中会广播事件,插件只需要监听它所关心的事件,就能加入到这条生产线中,去改变生产线的运作。

webpack本身引入的有tapable插件来管理构建流程,在编译的时候会触发tapalbe的钩子事件,我们编写一个webpack插件就是找到对应的钩子,然后写入自己的业务,就是在钩子上注册自己的事件,和发布订阅模式是一样的,当webpack构建时插件注册的事件就会在钩子触发的时候执行。

每个 Webpack 插件都需要向外暴露一个 apply(compiler) 方法,在compiler上找到对应的钩子写入自己的业务处理。

目前这个插件处理的就是在生成了html页面之后把页面对应的js和css插入到html代码中,因此这个插件是依赖于 html-webpack-plugin 的,他会向 complation 中再注入一个钩子 htmlWebpackPluginAfterHtmlProcessing 当该钩子触发时,已经生成了一个html页面

compiler.hooks.compilation.tap(
  this.constructor.name,
  compilation => {
   let hook = compilation.hooks.htmlWebpackPluginAfterHtmlProcessing;

   hook.tapAsync(
     this.constructor.name,
     (htmlPluginData, callback) => {
      try {
       // 当htmlWebpackPluginAfterHtmlProcessing钩子触发后会调用addLinks方法,传入compilation和当前当html页面信息
       callback(null, this.addLinks(compilation, htmlPluginData));
      } catch (error) {
       callback(error);
      }
     }
   );
  }
);
// 将页面所依赖的js和css注入到页面中
addLinks(compilation, htmlPluginData){
 // 获取当前页面所依赖的chunk
 const extractedChunks = extractChunks({
  compilation,
  optionsInclude: Object.keys(htmlPluginData.assets.chunks),
 });

 ...
 // 获取所有chunks的files
 const allFiles = extractedChunks.reduce((accumulated, chunk) => {
  return accumulated.concat(chunk.files);
 }, []);

 // 这一步是将根据allFiles处理后的链接注入到html页面
 htmlPluginData.html = insertLinksIntoHtml({
  links,
  html: htmlPluginData.html,
 });

 return htmlPluginData;
}

具体例子如下:

// vue.config.js
const { resolve } = require('path')
const getEntries = require('./build/getEntries')
const WebpackBundleAnalyzer = require('webpack-bundle-analyzer')
const AutoInjectPlugin = require('auto-inject-plugin')
const pages = getEntries(resolve(__dirname, 'src/features/*/index.js'))
module.exports = {
 pages,
 productionSourceMap: false,
 assetsDir: 'static',
 publicPath: '/',
 chainWebpack: config => {
  config.resolve.alias.set('vue$', 'vue/dist/vue.esm.js')
  if(process.env.NODE_ENV === 'production'){
   // 分离第三方包
   config.optimization.splitChunks({
    chunks: 'all',
    cacheGroups: {
     libs: {
      name: 'chunk-libs',
      test: /[\\/]node_modules[\\/]/,
      priority: 10,
      chunks: 'initial'
     },
     elementUI: {
      name: 'chunk-elementUI',
      priority: 20,
      test: /[\\/]node_modules[\\/]_?element-ui(.*)/,
     },
     swiper: {
      name: 'chunk-swiper',
      priority: 20,
      test: /[\\/]node_modules[\\/]_?swiper(.*)/,
     }
    }
   })
   // 将依赖自动注入到对应页面中
   config.plugin('AutoInjectPlugin').use(AutoInjectPlugin)
   config.optimization.runtimeChunk({name: 'manifest'})
  }

  if(process.env.npm_config_report){
   config.plugin('analyzer').use(WebpackBundleAnalyzer.BundleAnalyzerPlugin)
  }
  config
   .plugin('copy')
   .tap(args => {
    const { toType } = args[0][0]
    args[0] = []
    args[0].push({
     from: resolve(__dirname, 'public'),
     to: resolve(__dirname, 'dist/static/js'),
     toType
    })
    return args
   })
 }
}

抽离第三方包后的前后对比:

抽离前

vue实现的多页面项目如何优化打包的步骤详解

抽离后

vue实现的多页面项目如何优化打包的步骤详解

使用自动注入插件前后生成的html页面:

使用前:

<!DOCTYPE html>
<html lang=en>

<head>
 <meta charset=UTF-8>
 <meta name=viewport content="width=device-width,initial-scale=1">
 <title>Document</title>
 <link href=/bk_static/css/chunk-elementUI.ad4ace96.css rel=preload as=style>
 <link href=/bk_static/css/home.340fe3f2.css rel=preload as=style>
 <link href=/bk_static/js/chunk-elementUI.1ea80d29.js rel=preload as=script>
 <link href=/bk_static/js/chunk-libs.89fd9e1d.js rel=preload as=script>
 <link href=/bk_static/js/home.12708c2b.js rel=preload as=script>
 <link href=/bk_static/js/manifest.1dcac3f8.js rel=preload as=script>
 <link href=/bk_static/css/home.340fe3f2.css rel=stylesheet>
</head>

<body>
 <div id=root></div>
 <script src=/bk_static/js/home.12708c2b.js></script>
</body>

</html>

所依赖的代码并未自动引入进来

使用后:

<!DOCTYPE html>
<html lang=en>

<head>
 <meta charset=UTF-8>
 <meta name=viewport content="width=device-width,initial-scale=1">
 <title>Document</title>
 <link href=/bk_static/css/chunk-elementUI.ad4ace96.css rel=preload as=style>
 <link href=/bk_static/css/home.340fe3f2.css rel=preload as=style>
 <link href=/bk_static/js/chunk-elementUI.1ea80d29.js rel=preload as=script>
 <link href=/bk_static/js/chunk-libs.89fd9e1d.js rel=preload as=script>
 <link href=/bk_static/js/home.aa83744c.js rel=preload as=script>
 <link href=/bk_static/js/manifest.1dcac3f8.js rel=preload as=script>
 <link href=/bk_static/css/home.340fe3f2.css rel=stylesheet>
 <link href="/bk_static/css/chunk-elementUI.ad4ace96.css" rel="external nofollow" rel=stylesheet>
</head>

<body>
 <div id=root></div>
 <script src=/bk_static/js/home.aa83744c.js></script>
 <script src=/bk_static/js/chunk-elementUI.1ea80d29.js></script>
 <script src=/bk_static/js/chunk-libs.89fd9e1d.js></script>
 <script src=/bk_static/js/manifest.1dcac3f8.js></script>
</body>

</html>

所依赖的代码已经自动注入html页面中.

插件地址: auto-inject-plugin

Demo地址: vue-multipage

到此这篇关于vue实现的多页面项目如何优化打包的步骤详解的文章就介绍到这了,更多相关vue多页面优化打包内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Javascript 相关文章推荐
JQuery.uploadify 上传文件插件的使用详解 for ASP.NET
Jan 22 Javascript
JavaScript中URL编码函数代码
Jan 11 Javascript
javascript函数中参数传递问题示例探讨
Jul 31 Javascript
jquery结合html实现中英文页面切换
Nov 29 Javascript
利用HTML5+Socket.io实现摇一摇控制PC端歌曲切换
Jan 13 Javascript
为什么我们要做三份 Webpack 配置文件
Sep 18 Javascript
深入浅出webpack之externals的使用
Dec 04 Javascript
详解React之key的使用和实践
Sep 29 Javascript
layui框架与SSM前后台交互的方法
Sep 12 Javascript
javascript实现的图片预览和上传功能示例【兼容IE 9】
May 01 Javascript
基于小程序请求接口wx.request封装的类axios请求
Jul 02 Javascript
Node.js 深度调试方法解析
Jul 28 Javascript
vue tab切换,解决echartst图表宽度只有100px的问题
Jul 19 #Javascript
vue中echarts图表大小适应窗口大小且不需要刷新案例
Jul 19 #Javascript
完美解决vue 中多个echarts图表自适应的问题
Jul 19 #Javascript
vue实现多个echarts根据屏幕大小变化而变化实例
Jul 19 #Javascript
解决vue一个页面中复用同一个echarts组件的问题
Jul 19 #Javascript
浅谈vue单页面中有多个echarts图表时的公用代码写法
Jul 19 #Javascript
echarts.js 动态生成多个图表 使用vue封装组件操作
Jul 19 #Javascript
You might like
深入php之规范编程命名小结
2013/05/15 PHP
php将gd生成的图片缓存到memcache的小例子
2013/06/05 PHP
ajax返回值中有回车换行、空格的解决方法分享
2013/10/24 PHP
php ci框架中加载css和js文件失败的解决方法
2014/03/03 PHP
PHP基于CURL进行POST数据上传实例
2014/11/10 PHP
浅谈Laravel中的三种中间件的作用
2019/10/13 PHP
jQuery-Easyui 1.2 实现多层菜单效果的代码
2012/01/13 Javascript
jquery中加载图片自适应大小主要实现代码
2013/08/23 Javascript
Javascript 按位与赋值运算符 (&amp;=)使用介绍
2014/02/04 Javascript
JavaScript支持的最大递归调用次数分析
2014/06/24 Javascript
jquery中EasyUI实现同步树
2015/03/01 Javascript
javascript异步处理工作机制详解
2015/04/13 Javascript
JavaScript编写点击查看大图的页面半透明遮罩层效果实例
2016/05/09 Javascript
JS简单随机数生成方法
2016/09/05 Javascript
JavaScript微信定位功能实现方法
2016/11/29 Javascript
微信小程序实现登录页云层漂浮的动画效果
2017/05/05 Javascript
微信小程序 按钮滑动的实现方法
2017/09/27 Javascript
vue element-ui 绑定@keyup事件无效的解决方法
2018/03/09 Javascript
详解如何在Angular优雅编写HTTP请求
2018/12/05 Javascript
[01:08]DOTA2次级职业联赛 - Shield战队宣传片
2014/12/01 DOTA
[02:17]DOTA2亚洲邀请赛 RAVE战队出场宣传片
2015/02/07 DOTA
[41:05]Serenity vs Pain 2018国际邀请赛小组赛BO2 第二场 8.19
2018/08/21 DOTA
浅谈Python2.6和Python3.0中八进制数字表示的区别
2017/04/28 Python
详解python多线程之间的同步(一)
2019/04/03 Python
Django Docker容器化部署之Django-Docker本地部署
2019/10/09 Python
Python3 shutil(高级文件操作模块)实例用法总结
2020/02/19 Python
Python日志处理模块logging用法解析
2020/05/19 Python
django 将自带的数据库sqlite3改成mysql实例
2020/07/09 Python
芭比波朗加拿大官方网站:Bobbi Brown Cosmetics CA
2020/11/05 全球购物
思想品德课教学反思
2014/02/10 职场文书
消防安全员岗位职责
2014/03/10 职场文书
四查四看整改措施
2014/09/19 职场文书
民用住房租房协议书
2014/10/29 职场文书
公务员政审材料
2014/12/23 职场文书
绿色环保倡议书
2015/04/28 职场文书
Python趣味挑战之教你用pygame画进度条
2021/05/31 Python