一、背景

作为前端开发人员,在开发的时候,生产环境中会把js,css,图片等压缩,尽量减少文件的大小,从而提升响应速度,尤其是移动端。
在我们使用vue-cli3打包项目的时候,我们的js/css文件都是会根据依赖关系自动打包压缩的,但是项目比较大的时候,引入的外部库很多,往往打出来的包vender.js会很大,导致首屏加载很慢。

二、作用

这时候用webpack提供的externals属性,像vue.js 、vuex.js 、vue-router.js 等这些外部库,基本不会变的,如果将它们独立出来单独加载就能利于浏览器的缓存机制,不用每次都重新加载这些库js,并且大大的减少了打包的vendor.js文件。

三、基本用法

这时候用webpack提供的externals属性,像vue.js 、vuex.js 、vue-router.js 等这些外部库,基本不会变的,如果将它们独立出来单独加载就能利于浏览器的缓存机制,不用每次都重新加载这些库js,并且大大的减少了打包的vendor.js文件。
下面我们以vue-cli3项目为例进行说明:

第一步:vue.config.js中配置externals

首先我们看看我们的main.js文件示例:

import 'Vue' from 'vue'
import 'VueRouter' from 'vue-router'
import * as BABYLON from 'babylonjs'

然后我们新建vue.config.js文件

module.exports = {
	// ...
	externals: {
		// 我们挂载在全局的变量名称:引入的模块名称
		'vue': 'Vue',
		'vue-router': 'VueRouter',
		'babylonjs': 'BABYLON',
	}

这样配置之后,我们在main.js中引入的相关模块就不会打包至js文件中,而是会去找html中找我们使用script引入的文件,所以接下来,我们要在html中引入文件。

第二步:html中引入静态资源

<script src="https://cdn.jsdelivr.net/npm/vue@2.6.11"></script>
<script src="https://unpkg.com/vue-router@3.1.6/dist/vue-router.js"></script>
<script src="https://cdn.babylonjs.com/babylon.js"></script>

注意:引入cdn的时候最好使用官方的,不然挂了就…

配置完成

我们来查看一下效果:
优化前:优化前
优化后:优化后
由此可见,第三方包被我们抽离出来之后,chunk和vendor体积大大减小了。


四、区分生产环境和开发环境

之所以区分两个环境主要原因是,当我们在开发环境的时候,使用cdn引入js文件会比我们直接模块引入要慢,不是很方便。所以我们想要配置,只在生产环境下才使用externals。
那么,配置的思路就是对当前环境进行判定,如果是生产环境,我们就使用externals;如果是开发环境,就不使用。

第一步:vue.config.js中配置externals

vue.config.js代码修改为:

module.exports = {
    // ...
    configureWebpack: config => {
        const plugins = [];
        // 利用环境变量进行判断是否是生产环境production
        if (process.env.NODE_ENV === 'production') { 
            config.externals = {
                'vue': 'Vue',
                'vue-router': 'VueRouter',
                'babylonjs': 'BABYLON'
            }
        }
        // 然后将新增externals选项合并至plugins配置中
        config.plugins = [
            ...config.plugins,
            ...plugins
        ]
    },
    chainWebpack: config => {
        if (process.env.NODE_ENV === 'production') {
            // 生产环境下注入一个变量cdn 变量可以在html中通过htmlWebpackPlugin.options进行获取 
            config.plugin('html')
                .tap(args => {
                    args[0].cdn = 'prod';
                    return args;
                })
        }
    }
}

第二步:html中引入静态资源

既然要在区分两个环境,自然在html中也要进行区分,这个时候就要用到我们在vue.config.js中注入的cdn变量来进行判断了。
html修改为:

 <!-- ...-->
 <% if(htmlWebpackPlugin.options.cdn == 'prod'){ %>
  <script src="https://cdn.jsdelivr.net/npm/vue@2.6.11"></script>
  <script src="https://unpkg.com/vue-router@3.1.6/dist/vue-router.js"></script>
  <script src="https://cdn.babylonjs.com/babylon.js"></script>
  <% } %>

完成配置

运行项目,当在开发的时候没有引用cdn, 生产环境下使用了cdn,这就算是完成配置啦~
你以为这就结束了吗?哈哈哈没有,我们还可以继续优化配置一下。

五、进一步优化

vue.config.js配置

// vue.config.js
const isProduction = process.env.NODE_ENV === 'production';
const cdn = {
    css: [],
    js: [
        'https://cdn.jsdelivr.net/npm/vue@2.6.11',
        'https://unpkg.com/vue-router@3.1.6/dist/vue-router.js',
        'https://cdn.babylonjs.com/babylon.js'
    ]
}

module.exports = {
    configureWebpack: config => {
        if (isProduction) {
            // 用cdn方式引入,分离第三方插件
            config.externals = {
               'vue': 'Vue',
               'vue-router': 'VueRouter',
               'babylonjs': 'BABYLON'
            }
        } 
    },
	chainWebpack: config => {
		if (isProduction) {
            config.plugin('html')
                .tap(args => {
                    args[0].cdn = cdn;
                    return args;
                })
        }
    }
}

html配置

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

<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">
  <link rel="icon" href="<%= BASE_URL %>static/favicon.ico" type="image/x-icon" />
  <link rel="shortcut icon" href="<%= BASE_URL %>static/favicon.ico" type="image/x-icon" />
  <title>my-project</title>
  <!-- 使用CDN的CSS文件 -->
  <% for (var i in htmlWebpackPlugin.options.cdn && htmlWebpackPlugin.options.cdn.css) { %>
    <link href="<%= htmlWebpackPlugin.options.cdn.css[i] %>" rel="preload" as="style">
    <link href="<%= htmlWebpackPlugin.options.cdn.css[i] %>" rel="stylesheet">
  <% } %>
  <!-- 使用CDN的JS文件 -->
  <% for (var i in htmlWebpackPlugin.options.cdn && htmlWebpackPlugin.options.cdn.js) { %>
    <link href="<%= htmlWebpackPlugin.options.cdn.js[i] %>" rel="preload" as="script">
  <% } %>
</head>

<body>
  <noscript>
    <strong>We're sorry but eye-admin doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
  </noscript>
  <div id="app"></div>
  <!-- built files will be auto injected -->
  <% for (var i in htmlWebpackPlugin.options.cdn && htmlWebpackPlugin.options.cdn.js) { %>
    <script src="<%= htmlWebpackPlugin.options.cdn.js[i] %>"></script>
  <% } %>
</body>

</html>

不过使用externals属性要注意的是,虽然可以优化首屏加载速度,但是由于静态资源分离,也会增加http请求数量。所以如果是小项目,最好就不要用externals属性,因为小项目打包的出来的vender.js体积不大,建议项目体量较大的项目再用比较合适。


参考文章

真是要加油学习呢~
[1]: vue-cli3项目打包优化配置要点
[2]: vue-cli@3.0使用及配置说明
[3]: webpack使用HtmlWebpackPlugin进行cdn配置

Logo

前往低代码交流专区

更多推荐