当webpack有了vite的速度你会喜欢吗?

6,132 阅读5分钟

前言

本文主旨意义是在于和大家分享自己的脚手架,以及在开发过程中受到的一些心得。

首先阅读此文可以当作为仅仅了解一个新的工具,同时由于进行了webpack和vite双向的说明,中间会参杂了一定的vite和webpack的内容解析。(主要进行思路分析不涉及具体源码,感兴趣的可以自己去阅读源码)

对于分析不感兴趣的大佬可以直接进入v5-run小结

#老规矩打一波推广
vue组件平台服务器最近搞了新的服务器了,欢迎大家去进行尝试!
同时如果有大佬希望能利用搭建公司的组件分析平台也可以找我。
项目采用docker部署,可以很方便搭建公司内部的一个平台。
线上访问地址:http://assemble.everbeon.top/assemble/#/Show/index
注:嫌背景粒子动画卡的可以点击右上角的小图标就可以关闭背景动画

如何让webpack有vite的速度

webpack vs vite

首先这一个问题我们要先将进行两段分析,webpack慢和vite快的原因是什么?

webpack bundle everything

是的,这就是webpack慢的原因,由于webpack对于所有运行资源进行了提前编译处理,对依赖模块进行了语法分析转义,最终的结果就是模块被打包到内存中。

vite Bundleless esbuild esmodule

在vite中就出现相反的情况了,遵循着打包少、预处理的方式,让vite只有在运行第一次的时候进行依赖的打包处理(package.json不变)。并且在运行中由于依赖着esmodule可以将文件采用import方式直接引入,这样就不用把文件打包到一起,而且采用esbuild对于语法的解析转换(如:ts、jsx等)这样就不用进行js解析ast语法树后再重新构建,这样第一可以节省大量的cpu以及内存空间、第二可以减少语法解析的大量时间,基本上可以达到时效性不用提前进行语法解析。

why webpack

在webpack的开发中,大家或多或少的都在利用着webpack的“方言”带来的便利。比如以下代码:

// require.context Api
require.context(directory, useSubdirectories, regExp)
...
// css导出变量给js
:export {
    theme: $--color-primary;
}
...
// 各种魔幻的路径
import App from 'App'
...
// 以及svg引入
<use :xlink:href="iconName" />

可以说,webpack在给我们带来方便的时候也同时把我们给惯坏了!越来越脱离标准的es规范了,给我们开了越来越多的后门可走,甚至我们可以在我们的页面中写一些node api一样给我们搞定。(期待再多点这种方便的后门)在这种情况下我们进行webpack迁移到vite就会出现一系列的报错,并且由于配置文件不熟悉rollup也同时给我们的项目带来了不确定性,那么我不想动我原本的项目就像体验一下vite飞一般的感觉就是我的初始目标了。

how to do

把大象放进冰箱分几步?

  • 把冰箱门打开
  • 把大象放进去
  • 关闭冰箱门

是的我们的原理也如果放大象一样非常的简单,任何复杂的问题都可以简单化处理,且不要把问题想的过于复杂才是解决问题的最快途径

我们主要内容也分为三步

构建url以及语法解析服务

这一步主要是为了让我们的脚手架支持webpack特有的路径预处理判断,并且可以正常的解析我们的vue文件。

三方依赖处理

这步作为依赖的收集处理,并且让其支持import方式导入,相当于webpack中的vender处理

webpack方言api实现

实现webpack的特殊api,如::export {}、require.context

这样就实现了我们整个目标路径。当然如果简单列一下架构的话,估计就需要这样的一张图来实现。

image.png

当然处理webpack方言实现之外(没法进行整合到这上面,那个算具体需求),会发现三方依赖并没有在设计中,接下来我们就重点讲一下这个三方依赖(涉及到vite的一定原理解析,可以了解到面试吹牛皮)。

why first node_modules

为什么在vite中需要提前构建第三方依赖?官网给的解释有以下两点:

  • CommonJS 和 UMD 兼容性
  • 性能 但是!利用esbuild去构建达到兼容性和性能似乎也不是问题,并且不进行预构建其实有一个隐性的好处就是可以减少运行时的node_modules依赖性,比如我们可以手动实现一个类似yarn的包集中管理,这样我们就可以完美的实现项目中无node_modules了,想想都激动呢。那么问题点在哪呢?

esbuild中有一个选项为bundle: true

这个选项会将需要打包的入口文件的依赖进行全部打包,比如:我导入elementui,那么他就会将所有element需要的依赖统统打入到内部。(重要!请记住)

这个时候当我们引入了elementui后,elementui内部使用的vue和项目中本身的vue是不是同一个呢?

答案:不是,因为elementui引入的是自己内部的vue,而项目中是通过单独引入的vue

webpack引入到底是怎样引入?

在我们的node_modules中大家可以去找一下这个现象,会发现element-ui中明明就需要很多依赖,但是他却没有或者只有很少的依赖,这些依赖往往都是在node_modules中的第一层。这样的结果是怎么样的呢?

在同一项目中,不同工程依赖同一个npm,他们引入是相同的,并且是属于引用值相当于他们共享了这个npm的导出。比如a.js引入了 xxx.js将原本的导出的ceshi这个值修改成了2,那么当b.js引入的时候获取到ceshi这个值也是2而不是最开始的值了。

到这我们就发现了最大的问题,在运行时去加载依赖没办法分析他们之间的引用关系,这样会导致最大的隐患问题!!!

所以vite进行了预处理的问题最大点是在于三方包之间的依赖关系问题。

vite为什么可以预处理分析

这个答案其实很简单了,因为vite需要在入口的html中添加type="module"的script导入,然后将匹配script引入的导入作为esbuild的入口文件,这样esbuild就通过入口文件寻找各种依赖关系然后再加入插件分析依赖引入状态,就实现了感觉高大上智能的预处理分析了。

v5-run

这就是让webpack有vite速度的神奇指令了,实现就是依照着上面所属完成的。

因此这里主要就讲解脚手架的使用以及配置。(暂时只能用于vue2开发)

地址合集

npm: www.npmjs.com/package/@se…

gitee: gitee.com/beon/v5-vue…

npm安装: npm i @seeyon-v5-vue/cli-run -g

运行指令: v5-run

配置文件

类似与各种配置文件,你需要在项目根路径下创建v5-run.config.js文件,并将其进行配置对象的导出。

module.exports = {
    // 服务运行的配置
    server: {
        // 和webpack proxy一样
        proxy: {
            [url: string]: {
		target: string,
		host?: string,
		headers?: {[key: string]: string}
		changOrigin?: boolean
            }
        },
        // 是否开启http2模式(不稳定,尝鲜使用)
        http2:Boolean,
        // 重要,自动获取html路径为根路径和public路径,如果html不在需要手动添加如:['src/html/']
        enter: string[]
    },
    // 各种设置的配置
    config:{
        // 配置svg引入到html中
        svgLoader: {
            // 引入svg文件夹路径
            path: string,
            // svg引入名称配置如:my-svg-[name],引入名称则为(svg文件名为app.svg):my-svg-app
            symbolId: string
        },
        // 全局导入less、scss等
        styleLoader: {
            // 前面为引入类型如less、scss,数组为引入文件如['src/assets/index.scss']
            [loadStyle: string]: string[]
        },
        // 全局变量配置如:_(loadsh)
        global: {
            // 前面为全局名称如: _,后面为引入方式比如loadsh,数组则为某一项比如[loadsh, map],那么就会获得loadsh.map的对象引入
            [name: string]: string | string[]
        }
    }
}

使用教程

第一步配置v5-run.config.文件

基础配置文件,可以按照需求改就可以了

module.exports = {
    server: {
        enter: ['./src'],
        http2: true,
	proxy: {
            "/dev-api": {
		target: 'http://localhost',
		changOrigin: true
            }
        }
    },
    config: {
        svgLoader: {
            path: 'src/icons',
            symbolId: 'icon-[name]'
        },
        global: {
            _: "lodash",
            $: "jquery",
            jQuery: "jquery"
        },
        styleLoader: {
            less: [path.resolve(__dirname, "./src/assets/styles/variable.less")]
        }
    }
};

第二步执行v5-run指令

看到服务开启成功后为成功开启

image.png

第三步访问网页(注意)

在网页访问路径需要手动输入到你的入口文件,比如:http://localhost:3000/src/html/index.html 其次,最好加入index.html路径,否则有可能会出现某些路径解析少一层的问题。访问错误的时候会出现提示,并且有问题也会出现提示页面,可以双击错误请求页点进去查看错误原因

image.png

问题点

那这一块作为单独说明主要是强调现阶段该实现而没有实现的重要功能点。

没有热更新

暂时没有做热更新,虽然有现有实例,但是仅仅作为本人使用而言,热更新暂时意义不大(项目较为特殊)。

webpack兼容性

作为兼容性只是做了几个常用的设置以及配置,能够满足大多数标准的项目而已,特殊项目需要特殊处理,暂时无法解决,如果有问题可以直接联系我,可以查看脚手架问题缺点(说不定下个版本就修复了呢)。

三方依赖每次开启都会处理

其实这个是个比较好处理的问题,但是本人在使用的时候发现处理时间较短,所以暂时未作处理(就是懒)。

css文件中的路径处理

比如element中scss就有这样$--font-path: "~element-ui/lib/theme-chalk/fonts"一句,需要在其上面进行注释//v5-run-style-path,就会处理这个路径参数。(只有参数需要添加,@import、正常url都不需要 )

image.png

结尾

大家感兴趣去看gitee的话也可以看到,本项目只是整个脚手架项目的一块,剩下的内容都还没加上去,后期会将处理方式、代理方式、管理三方包方式全部抽出来,做成一个完整的脚手架项目。现在只是进行项目可行性的制作。整体项目使用了ts进行开发,但是由于没有具体拆分所以还没有上单元测试。

作为一个新的脚手架内容,我认为提高开发效率以及项目稳定性是最重要的,这也是为什么没有一昧的进行强行替换vite作为生产,当出现问题的时候可以直接使用webpack进行处理。(比如:ie情况、兼容性测试等问题)所以项目不失为我们在切换到使用esmodule上的一个尝试阶段,让我们去变相性的让webpack拥有着和vite一样的速度。

本项目中的三方依赖处理,有一定程度借鉴vite,所以现阶段代码较为相似,这也是为什么我没有急着做初始化缓存信息的原因,因为将来目标不一样,所以后期会进行修改该块内容。

这就是本文全部内容了,欢迎各位大佬进行讨论,本人微信为:Dawn_web,qq为:962717593,有任何问题都可以联系本人。

我是BEON,一个想方设法帮助团队提高效率的前端工程师