事情的起因是这样的,最近有相当一部分的精力都在做项目的性能优化上,之前有一个项目出现了一个老大难的问题纠结很久了,一直没时间去看,正好一并解决一下。这个问题很简单:我用vue-cli创建的项目,按照vue的路由懒加载写法,打包后却发现代码并没有分割,全部都打包到app.js中了,导致app.js体积过大,且没有路由的按需加载了。

找出问题的原因

我开始思考问题原因可能是以下几点造成的:

  1. 路由懒加载写法不对;
  2. vue-cli版本问题;
  3. vue-cli的配置问题。

但是这三个可能得原因很快排除了,因为有一个项目上面三个都一样,代码分割正常,那只能是代码问题了。但是那么多文件总不能全部review一遍吧,毫无头绪之下只能采用朴素但实用二分法的方式定位问题文件了。一番体力活下来终于让我找到了两个罪魁祸首,通过观察这两个文件发现都用了同一种的文件引用方式,类似代码如下:

let form = null;
let cpnName = this.template.name;
this.$options.components[cpnName] = require('@/' + this.template.path).default;
form = <cpnName />
return (
	<div>{form}</div>
)

组件通过拼接入参的路径来动态引入组件,其实看到这里我心里大概就知道什么原因了,因为是动态路径,webpack打包时是静态解析依赖,根本无法确认文件的具体地址,所以导致代码全部都打到app.js中。为了证明我的想法,我到webpack的github issue中也找到了跟我类似的场景:

这个老哥是想根据传入的图片名称来动态引入图片,但是打包时候发现其他目录的图片也都被打包进来了,webpack的维护者也回答了说,这就是require的工作机制,它不知道你会用哪个资源,它就把它们全部都打包了。

验证问题

为了验证这个问题,我创建了一个项目,来复现一下问题:

动态引入的组件代码如下:

// src/components/common/DynamicRequireCpn.vue
<script>
export default {
    name: 'DynamicRequireCpn',
    props: {
        template: Object
    },
    render () {
        let form = null;
        let cpnName = this.template.name;
        this.$options.components[cpnName] = require('@/' + this.template.path).default;
        form = <cpnName />
        return (
            <div>{form}</div>
        )
    }
}
</script>

路由代码如下:

// src/router/index.js
const routes = [
  {
    path: '/',
    name: 'home',
    component: HomeView
  },
  {
    path: '/about',
    name: 'about',
    component: () => import(/* webpackChunkName: "about" */ '../views/AboutView.vue')
  }
];

打包结果如下:

发现代码还是都打包到一起了,about组件并没有分割出来。而且我还在app.js中发现了没有引用的代码。也就是说这种情况下,webpack把src目录下所有的文件都打包了。

解决问题的方案

按照上面的实验和require的工作原理,我想通过缩小require的查到范围是不是能解决问题呢?

<script>
export default {
    name: 'DynamicRequireCpn',
    props: {
        template: Object
    },
    render () {
        let form = null;
        let cpnName = this.template.name;
        this.$options.components[cpnName] = require('@/components/common/' + this.template.path).default;
        form = <cpnName />
        return (
            <div>{form}</div>
        )
    }
}
</script>

这下我把require的动态路径精确到@/components/common/,重新打包看看:

Bingo!看到了about组件对应的分割文件,而且搜索app.js文件,也没有发现未引用的代码了,问题解决了!

总结

在使用webpack时,应该尽量减少资源的动态路径引入,如果必须这样引入的话,那也要尽量传入更短的文件路径,或者将要动态引入的文件放到一个目录下面,防止webpack找到非目标目录下面。

GOOD

require('@/components/common/' + this.template.path);

作者:|rain_watcher|,原文链接: https://www.cnblogs.com/rain-watcher/p/16299664.html

文章推荐

算法链与管道(上):建立管道

聊聊OOP中的设计原则以及访问者模式

Kafka 消费者解析

Spring大事务到底如何优化?

break、continue、return中选择一个,我们结束掉它

聊聊如何验证线上的版本是符合预期的版本

面试官:RocketMQ是什么,它有什么特性与使用场景?

【Java 数据结构及算法实战】系列 013:Java队列07——双端

python 实现超快窗口截图,自动获取当前活动窗口并展示截图

Java 处理 Exception 的 9 个最佳实践,你做对了吗?

Spring Boot 整合流程引擎 Flowable,so easy

软件项目管理 1.3.敏捷项目管理概念