vue脚手架打包排除第三方依赖(项目瘦身)- externals

方法

首先在 vue.config.js 中加入如下内容


module.exports = { // 主体
	......
    configureWebpack: config => {
        config.plugins.forEach((val) => {
        	// 这里加这个判断主要目的是获取到脚手架中的插件 HtmlWebpackPlugin
            if (JSON.stringify(val).indexOf('"filename":"index.html"') !== -1) {
                if (process.env.NODE_ENV === 'production') {
                    console.log('生产环境');
                    val.options.cdnConfig = {
                        js: resources.js,
                        headerJs: resources.headerJs,
                        css: resources.css
                    };
                }
                val.options.env = process.env.NODE_ENV
            }
            if (process.env.NODE_ENV === 'production') {
                config.externals = resources.externals
            }
        })
    }
}

val.options.env 这个配置十分关键,用于在模板中判断当前环境,如果是开发环境,则不能使用 CDN 引用,否则会报错,在开发环境直接使用平时写法即可,在生产环境才会在模板中写入CDN链接。

下面贴出 vue脚手架所含的插件 HtmlWebpackPlugin 所拥有的值

HtmlWebpackPlugin {
  options: {
    template: 'E:\\Project\\LIMS-laboratory-management\\bamboo-frame-front-admin\\public\\index.html',
    templateParameters: [Function: templateParameters],
    filename: 'index.html',
    hash: false,
    inject: true,
    compile: true,
    favicon: false,
    minify: false,
    cache: true,
    showErrors: true,
    chunks: 'all',
    excludeChunks: [],
    chunksSortMode: 'auto',
    meta: {},
    title: 'bamboo-front-admin',
    xhtml: false
  }
}

我只要使用了这个对象中的 filename: 'index.html', 进行判断当前是不是插件 HtmlWebpackPlugin,如果是的话,加入自定义配置对象 cdnConfig

主要操作是将需要DNS引入的资源声明成数组然后使模板index.html编译出来引用,同时打包时排除到需要第三方引用的资源

从第一步可以看到有一个变量 resources,其内容如下:

const enums = require('../application/resources/enums');

module.exports = [
    enums.vue
];

const externals = {};
const js = [];
const headerJs = [];
const css = [];

res.forEach(item => {
    if (externals[item.key] === undefined) {
        externals[item.key] = item.constant
        if (item.js) {
            js.push(...item.js);
        }
        if (item.css) {
            css.push(...item.css);
        }
        if (item.headerJs) {
            css.push(...item.headerJs);
        }
    }
});

module.exports = {
    externals,
    js,
    headerJs,
    css
};

这里我模拟了一个枚举,用来统一管理第三方资源,内容如下

module.exports = {
    vue: {
        key: 'vue',
        constant: 'Vue',
        js: [
            '/cdn/vue@2.6.12/vue.js'
        ],
    },
}

修改模板:

<!DOCTYPE html>
<html lang="">
<head>
    ......
    <% if (htmlWebpackPlugin.options.env == 'production') { htmlWebpackPlugin.options.cdnConfig.css.forEach(function(item){ if(item){ %>
    <link href="<%= item %>" rel="stylesheet" />
    <% }})} %>
</head>
<body>
......
<div id="app"></div>
<% if (htmlWebpackPlugin.options.env == 'production') { htmlWebpackPlugin.options.cdnConfig.js.forEach(function(item){ if(item){ %>
<script type="text/javascript" src="<%= item %>"></script>
<% }}) } %>
<!-- built files will be auto injected -->
</body>
</html>

模板从 插件配置 htmlWebpackPlugin.options.cdnConfig 中读取并渲染,最终构建效果如下

在这里插入图片描述

代码到这里就全部贴完了,下面对这些配置进行一些简单说明

externals 的说明直接查看官方文档:https://webpack.docschina.org/configuration/externals/,这里不进行说明

需要注意的是,externals 是一个 Object,其结构类似于一个 map,由 keyvalue 构成

其中 key 是第三方资源的包名称:即importfrom的名称,以 ElementUI为例,key 就是下面的 element-ui

import ElementUI from 'element-ui';

其中 value 的值是 当资源以CDN方式引入到页面中后,资源注册到 window 对象上的名称,以 ElementUI 为例,value就是 ELEMENT

在这里插入图片描述
这个值必须是可以在window对象上能获取到的对象名称,否则打包后访问即使CND正确也会报错

踩坑

百度有人说 externals 键值对中的值是 import 时写的那个名字,这是不对的,这种说法坑死人,且无法排查问题

一旦写错,报错信息如下:
在这里插入图片描述
点进去之后它是这么个东西:
在这里插入图片描述
它无法从window对象中获取到 ElementUI 对象,因为 ElementUI 在 window 对象上绑定时并不是使用的这个名字。

Logo

前往低代码交流专区

更多推荐