vue-cli项目打包结果优化

分析工具:webpack-bundle-analyzer

使用范围:对于打包结果进行分析;

使用方法:

下载:

npm install --save-dev webpack-bundle-analyzer;

引入:在vue.config.js文件中,

   调整 webpack 配置最简单的方式就是在 vue.config.js 中的 configureWebpack 选项提供一个对象:

const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;

module.exports = {
  configureWebpack:config=>{ //该配置会通过webpack-merge合并到webpack配置中
    if(process.env.NODE_ENV == 'production'){//判断执行环境,只有在生成环境中用到,开发环境中用不到分析工具,文档:https://cli.vuejs.org/zh/guide/webpack.html#%E7%AE%80%E5%8D%95%E7%9A%84%E9%85%8D%E7%BD%AE%E6%96%B9%E5%BC%8F
      return {
     devtool: 'none', plugins: [
new BundleAnalyzerPlugin() ] } } }, ... }

通过分析工具可以看出,打包结果分为两部分:node_modules和src,其中前者是引入的公共包,后者是自己写的。

前者分为:

1. mockjs/dist不需要打包进入,

2. vue. vue-router、vuex和axios不无法优化的固定代码:

  针对这部分可以采用cdn(content delivery network)方式引入公共的免费资源

  具体步骤:

(1)告诉webpack,不要对vue. vue-router、vuex和axios这些可以从cdn上免费获取的公共资源进行打包;

    externals 配置选项提供了「从输出的 bundle 中排除依赖」的方法。

//vue.config.js文件
module.exports = { configureWebpack:config=>{ if(process.env.NODE_ENV == 'production'){ return { devtool: 'none', plugins: [ new BundleAnalyzerPlugin() ], externals:{ vue: 'Vue',//引入cdn上的资源后,将会生成全局变量Vue vuex: 'Vuex', 'vue-router': 'VueRouter', axios: 'axios' } } } },

 (2).在public目录下的index.html中,手动从cdn引入这几项,(注意用到了模板语法,这是html-webpack-plugin插件的语法)

<!DOCTYPE html>
<html lang="">

<head>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width,initial-scale=1.0">
</head>

<body>
  <noscript>
    <strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled.
        Please enable it to continue.</strong>
  </noscript>
  <div id="app"></div>
  <!-- ref cdn 开发环境不需要,生成环境需要,这是html-webpack-plugin的模板语法,当环境是生成环境时候,不需要引入cdn -->
  <% if( NODE_ENV === 'production' ){ %>
    <script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.13/vue.min.js"></script>
    <script src="https://cdn.bootcdn.net/ajax/libs/vuex/3.6.2/vuex.min.js"></script>
    <script src="https://cdn.bootcdn.net/ajax/libs/vue-router/3.2.0/vue-router.min.js"></script>
    <script src="https://cdn.bootcdn.net/ajax/libs/axios/0.21.1/axios.min.js"></script>
  <% } %>
</body>

</html>

此时,打包的文件没有了这四项公共的模块。

(3)由于用cdn方式引入,模块化引入的方式是不能写的,比如Vue.use(Vuex),Vue.use(VueRouter)

import Vue from 'vue';
import VueRouter from 'vue-router';
import routes from './routes';
import setTitle  from '@/utils/setSiteTitle';
//在production的条件下,由于vue.config.js中用了external, //把VueRouter暴露到全局,所以会存在,就不能用这种方式加载VueRouter了 if(!VueRouter){ Vue.use(VueRouter); } const router = new VueRouter({ mode: 'history', // base: process.env.BASE_URL, routes, })

core-js是浏览器兼容的代码,

它在babel.config.js文件的兼容要求基础上,模拟新的api
module.exports = {
  presets: [
    '@vue/cli-plugin-babel/preset'
  ]
}

这个corejs是按需引入的,所以不需要我们在做处理。

如果兼容的是新版本浏览器,可以不需要考虑兼容性,直接把babel.config.js里的preset值去掉就可以了。

用npm run modern modern命令,打包出两种不同兼容性的代码;

这篇博客挺好的:https://blog.csdn.net/weixin_34321753/article/details/89701992

Vue CLI 构建两个版本的 js 包:一个面向支持现代浏览器的原生 ES2015+ 包,以及一个针对其他旧浏览器的包。

但最酷的部分是没有特殊的部署要求。生成的HTML文件中自动适配。 这个方式采用了Phillip Walton 文章中讨论的技术方案

  • 在支持原生 ES2015+ 的浏览器中,js会通过 <script type="module"> 加载,并且可以使用 <link rel="modulepreload"> 预加载。

  • 在不支持的浏览器中使用 <script nomodule> 来加载编译版本,并且这会被支持ES模块的浏览器所忽略。

<!DOCTYPE html>
<html lang="">

<head>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width,initial-scale=1">
  <link href="/css/chunk-249149b2.bc811261.css" rel="prefetch"> //perfeth和preload都是懒加载,但preload的优先级要高
  <link href="/css/chunk-3de993f6.c13ff11f.css" rel="prefetch">
  <link href="/css/chunk-5d499e19.25e41ee9.css" rel="prefetch">
  <link href="/css/chunk-61542f76.899679a2.css" rel="prefetch">
  <link href="/css/chunk-71cb7586.eb46b54a.css" rel="prefetch">
  <link href="/js/chunk-249149b2.9522a5e5.js" rel="prefetch">
  <link href="/js/chunk-3de993f6.e812e81e.js" rel="prefetch">
  <link href="/js/chunk-5d499e19.b2738f79.js" rel="prefetch">
  <link href="/js/chunk-61542f76.62cfd7c4.js" rel="prefetch">
  <link href="/js/chunk-71cb7586.8a1a4a95.js" rel="prefetch">
  <link href="/css/app.ac0c3dd2.css" rel="preload" as="style">
  <link href="/js/app.cedc65b7.js" rel="modulepreload" as="script">
  <link href="/js/chunk-vendors.f5d25c35.js" rel="modulepreload" as="script">
  <link href="/css/app.ac0c3dd2.css" rel="stylesheet">
</head>

<body><noscript><strong>We're sorry but my-site doesn't work properly without JavaScript enabled. Please enable it to
      continue.</strong></noscript>
  <div id="app"></div>
  <script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.13/vue.min.js"></script>
  <script src="https://cdn.bootcdn.net/ajax/libs/vuex/3.6.2/vuex.min.js"></script>
  <script src="https://cdn.bootcdn.net/ajax/libs/vue-router/3.2.0/vue-router.min.js"></script>
  <script src="https://cdn.bootcdn.net/ajax/libs/axios/0.21.1/axios.min.js"></script>
  <script type="module" src="/js/chunk-vendors.f5d25c35.js"></script> //非现代浏览器会忽略type=module的引入
  <script type="module" src="/js/app.cedc65b7.js"></script>
  <script>!function () { var e = document, t = e.createElement("script"); if (!("noModule" in t) && "onbeforeload" in t) { var n = !1; e.addEventListener("beforeload", function (e) { if (e.target === t) n = !0; else if (!e.target.hasAttribute("nomodule") || !n) return; e.preventDefault() }, !0), t.type = "module", t.src = ".", e.head.appendChild(t), t.remove() } }();</script>
  <script src="/js/chunk-vendors-legacy.f5d25c35.js" nomodule></script> //现代浏览器会忽略nomodule属性的标签
  <script src="/js/app-legacy.6a3f1c73.js" nomodule></script>
</body>

</html>

对自己写的代码的优化

路由懒加载:函数返回promise,结果是组件。打包后进行了分包

import Home from '@/views/Home/index.vue'

const routes = [
  {
    path: '/',
    name: 'Home',
    component: Home,
    meta:{
      subTitle: '主页'
    }
  },
  {
    path: '/about',
    name: 'About',
    // route level code-splitting
    // this generates a separate chunk (about.[hash].js) for this route
    // which is lazy-loaded when the route is visited.
    component: () => import( '@/views/About/'),
    meta:{
      subTitle: '关于'
    }
  },

刚打开网站的白屏处理:

处理方法有多种:

1.在#app元素中插入一张加载动画,

  如果vue没加载出来,#app中的内容不会消失,一旦new Vue()执行,因为有render函数介入,#app的内容会render的内容被覆盖。

注意:该动画图片的路径必须是public目录下,因为该目录下,会经过copy-webpack-plugin的插件,原封不动的复制到dist目录。而不是和assets目录下的图片,会经过loader解析,成为新文件。

静态文件分为static和asset文件,,static是纯静态文件,而assets是经过loader处理的文件,在vue-cli中,static文件放在public目录中

   

 2.在异步组件中加载中添加进度条  

(1)懒加载---异步组件

Vue 允许你以一个工厂函数的方式定义你的组件,这个工厂函数会异步解析你的组件定义。Vue 只有在这个组件需要被渲染的时候才会触发该工厂函数,且会把结果缓存起来供未来重渲染。例如:

Vue.component('async-example', function (resolve, reject) {
  setTimeout(function () {
    // 向 `resolve` 回调传递组件定义,就是resolve的参数是组件,也可以用引入的组件传递进去
    resolve({
      template: '<div>I am async!</div>'  
    })
  }, 1000)
})
以上代码页可以写成
import Home from '@/views/Home/index.vue'
const routes = [
  {
    path: '/',
    name: 'Home',
    component: function (resolve, reject) {
      setTimeout(function () {
        // 向 `resolve` 回调传递组件定义
        resolve(Home)
      }, 1000)
    }
  },
...
}


const routes = [
{
    path: '/project',
    name: 'Project',
    component: () => import('@/views/Project'),
    meta: {
      subTitle: '项目'
    }
  },
    ...
]

import() 动态加载:

当前import xx from xx这是静态导入。但出于性能原因(在可能使用之前不加载代码),或出于健壮性原因(无法加载非关键模块),需要按需加载,

,import('xxx')返回的是一个promise

 process.env.NODE_ENV

在vue-cli中,可以直接在代码中判断当前的环境是开发还是生产环境。 

------------恢复内容结束------------

原文地址:https://www.cnblogs.com/dangdanghepingping/p/14900046.html