• 为什么我写了路由懒加载但代码却没有分割?


    事情的起因是这样的,最近有相当一部分的精力都在做项目的性能优化上,之前有一个项目出现了一个老大难的问题纠结很久了,一直没时间去看,正好一并解决一下。这个问题很简单:我用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);

    BAD

    require('@' + this.template.path);


    __EOF__

    本文作者Rain Watcher
    本文链接https://www.cnblogs.com/rain-watcher/p/16299664.html
    关于博主:评论和私信会在第一时间回复。或者直接私信我。
    版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
    声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
  • 相关阅读:
    GitHub最新发布 阿里十年架构师手写版spring全家桶笔记全新开源
    【数据结构】A : A DS图_传递信息
    Qt之天气预报实现(一)预备篇
    QGIS 捕捉
    黑马笔记---常见数据结构
    数据结构:二叉树(基本概念)
    【Django学习笔记(三)】BootStrap介绍
    题目0061-第K个最小码值的字母
    nacos简单使用
    STM32为什么不能跑Linux?
  • 原文地址:https://www.cnblogs.com/rain-watcher/p/16299664.html