为你的Vue2.x老项目安装Vite发动机吧!

我心飞翔 分类:vue

天下苦webpack久矣,相信作为前端开发者一定经历过在项目迭代时间较长的时候经历漫长等待的这一过程,每一次保存都会浪费掉大量时间,这是webpack这种机制所带来的问题。

于是,尤大为我们带来了新一代前端构建工具vite

说起这个工具,相信各位也不会陌生了,因为vite已经出现很久时间了,现在已经出现了v4版本,查看其git仓库,发现其迭代变更速度很快,也侧面说明了这一工具在前端圈的火热,其突出的特点就是快,快在什么地方呢,就是我们的开发阶段,使用vite构建的项目在开发阶段可以为我们节约大量时间,但是对于我们没有接触过这一技术栈的同学,存在一个比较尴尬的问题。

目前vite主要默认是支持给vue3使用的,并且如果使用官方的cli创建的项目一样会默认使用vue3去构建项目,此时对于一些vue2的老项目就显得不友好了,那么我们如何针对于vue2

的项目进行构建工具的升级呢,在将webpack升级到vite的过程中,你会遇到哪些坑呢,让我来带你跨过去吧,在此之前,我们去简单了解下什么是vite,有什么优势。

什么是Vite

Vite下一代的前端工具链

官方只有这么一句话,我们就可以明确其是一个前端工具链,其出现的时间已经很久了,到现在的v4版本已经经历了很多变动,在我升级公司的项目的时候还是v3,没想到只是过了一个周末打开官网已经到v4了,这迭代速度是蒸滴快啊。

这么长的时间,其实众多同学都知道其是一个打包构建工具,我们就不过多废话,直接进入进入主题,我们先了解这几个点:

Vite为什么之前不出来?

在浏览器支持 ES 模块之前,JavaScript 并没有提供的原生机制让开发者以模块化的方式进行开发。这也正是我们对 “打包” 这个概念熟悉的原因:使用工具抓取、处理并将我们的源码模块串联成可以在浏览器中运行的文件,这就是webpack这类工具的工作原理,他们需要通过解析目录树拿到所有资源文件然后转化为浏览器可以识别的文件才能最终输出供浏览器使用,这个过程所需要的时候,不论是在初期编译阶段还是修改文件的热更新阶段都不可避免,当开发的项目越来越大的时候,所需要的编译时间也就越来越长了,我们也就遇到了性能瓶颈,往往单单启动项目就需要花费很多的时间,甚至是数分钟。

Vite 旨在利用生态系统中的新进展解决上述问题:浏览器开始原生支持 ES 模块,且越来越多 JavaScript 工具使用编译型语言编写。

也正是因为浏览器原生支持了es模块,才让vite这类工具得以出现。

什么是Es模块

所以我们也顺带了解下什么是es模块,浏览器原生支持了对前端有什么影响,有何用处呢?

其实我们所说的es模块就是我们常说的ESMESM是一种规范,在早期,我们的浏览器只支持script标签引入,这样的使用方式在很多场景下就会显得很麻烦,在NodeJs出来之时携带了CommonJS规范也就是我们所说的CJS规范,但是其只适用于服务端,所以为了迎合客户端的需求,主要是针对浏览器,便有了针对于客户端的规范Asynchronous Module Definition,简称AMD规范的出现,但是这些规范出现的仓促并且也只是为了解决当时的一小部分问题,这些社区提出的规范终究只是为了解决一时的需求,随着历史的发展,新的模块化规范不断涌入、消亡。

直到ESM规范被提出。ESM规范是ES标准的模块化规范,他的早期讨论可以追溯到2019年。到此为了,ESM的出现自身有诸多的优点,这里就不概述了,有兴趣的朋友可以自己去查阅,我们在此只需要了解这些规范出现的原因和历史背景即可,ESM虽然好,但是由于CJS规范已经存在较长时间了,所以市面上已经有了非常多的CJS规范的包,让这些所有包从CJS切换到ESM显然不太现实,于是便出现了这样的场景,ESM与CJS共存,并且这将是一个长期趋势。

如何解决这一痛点?

  1. 两种规范的不同我们很好理解,简单来讲,我们目前开发的项目有的属于nodejs项目,有的属于前端项目,两边的包的规范明显不同,但是有的工具的包很明显我们都可以用,那么我们一般如何去做呢?比如在babel中使用babel-plugin-transform-commonjs可以将CJS规范的代码转换为ESM规范,在vite或者webpack中都有不同的工具可以转换,一般这一任务都会交给这些工具。所以日常开发中,开发者对这些规范的感知并不明显。
  2. 第二种,为了一刀切解决当前ESMCJS、浏览器script标签导入这3种规范互相不兼容的情况,提出了兼容三者格式的UMD(Universal Module Definition)规范,在使用打包工具打包类库的时候往往会有一个打包类型的选项,很多包都会选择UMD就是这个原因。

但是很显然这些方式是一定存在痛点的,虽然看起来将不同规范在工具集上进行了抹平差异,但是由于一些兼容性的问题,这些差异就会被放大,所以当多个工具出现在一个项目的时候,实际是就是为了抹平这些差异化的存在。

上面的这些规范是一些题外话了,和本文关系不大,但是值得每一位前端开发去了解,正是因为ESM规范的优秀,才使得浏览器会去原生支持他,当然对于这些规范一般都是先定义后实现,这个定义在前期已经被定义了,只是浏览器的支持是慢慢跟上的,总而言之,在现在,我们已经可以去使用这一特性了。

浏览器原生支持ESM有什么用?

这里的东西也相对较多,我们就长话短说,在之前,我们都是通过script标签进行引入的。

这个标签引入的脚本负责交互。

但是一个大型的项目当然不仅仅只有一个js文件,对于繁多的文件,我们想要很好的管理就显得有些难度,于是我们借助webpack这类工具,其将我们的文件打包为bundle.js,再将文件。这意味着我们的前端开发工作流从“石器时代”跨越到了“工业时代”,但是对浏览器来说并没有质的改变,它所加载的代码依然一个 bundle.js ,整体引入到我们的项目当中。

但是随着浏览器对 ES Module 标准的原生支持,改变了这种情况。目前大多数浏览器已经支持通过 <script type="module"> 的方式加载标准的 ES 模块。这也就意味着类似我们之前在webpack当中的这些引入不需要再进行打包编译了,浏览器可以原生去支持,去通过module引入,而一旦浏览器帮我们做了这些事,我们就可以省掉这最耗时的打包编译阶段了。

当然这里的总结还不是很全面,但是我们需要了解到其这些最为直观鲜明的优势,在了解完这些特性之后,我们直接进入进入今天的主题。

使用vite来构建你的Vue2项目

目前许许多多的文章都是支持vue3的,包括官方也是默认支持vue3版本,但是实际情况来看,很多公司并不会过早的将vue版本从2切换到3,我们公司就是这样,所以想要使用vite去开发vue2的项目就需要去解决很多兼容问题,碰巧本人需要去重构一个vue2的项目,所以就直接使用上了vite+vue2的组合,在实际使用下来来看,我觉得目前vite已经完全是可以支持vue2的使用了,在此期间,也踩了很多坑,把这些经验分享给大家,让大家少走弯路。

webpack升级vite项目搭建指南

单纯的升级会由于不同的项目区分让人迷惑,我们直接从零开始去构建一个项目,方便大小理解以及切换自己项目的时候更加轻松。

目前官方默认的脚手架工具创建的项目都是默认vue3的版本,所以,如果想要自己去创建项目,要么自己使用vue-cli搭建完项目之后修改,要么就直接自己从0开始,这里我们直接使用后者,我们开始来搭建一个项目

直接使用npm初始化一个项目

mkdir vue2vite
npm init  -y

我们需要一个入口文件和一个模板创建两个文件

touch main.js
touch index.html

这个index.html文件类似webpack的模板文件,我们需要手动引入我们的main.js文件,并且需要注意的是,我们需要对script声明type=module

<!DOCTYPE html>
<html lang="en">
 <head>
   <meta charset="UTF-8" />
   <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
   <meta name="viewport" content="width=device-width, initial-scale=1.0" />
   <title>vue2vite</title>
 </head>
 <body>
   <div id="app"></div>
   <script type="module" src="./main.js"></script>
 </body>
</html>

此时我们需要下载我们的工具vite,因为我在使用的时候还是v3版本,此时已经更新到v4了,这里我还是用v3来演示,大家使用时请注意版本。

pnpm add vite@3.2.3 -D

下载完成之后就去package.json中加上三个脚本命令,这些步骤可以看官网,都是些基础步骤就不过多讲解了:

"scripts": {
   "dev": "vite",
   "build": "vite build",
   "preview": "vite preview"
 },

此时我们执行npm run dev就会默认启动一个端口为5173的服务了,此时我们就像是使用webpack一样没有任何区别,同时修改index.html也会同步刷新。简单的一个项目就启动了。

此时这一串内容都应该是关于vue基础项目搭建的,大概分为这几步,下载vue依赖,创建app.vue,在main.js入口文件注册引入app.vue并且挂载到**#app**节点上。

import Vue from 'vue';
import App from './App.vue';

new Vue({ render: h => h(App) }).$mount('#app');

8. 完成这几步我们启动项目,此时就会出现错误告诉我们,没办法识别**vue**文件,当然,这很合理,类似**webpack**一样,很多文件都需要用**loader**去翻译,所以在这里也是同理,我们需要使用一个插件**vite-plugin-vue2**,这是一个专门针对**vue2**项目的插件,如何使用呢,我们知道**vue**的配置文件是**vue.config,js**,**vite**也是类似,我们创建一个**vite.config.js**,并且引入插件并注册他,这里的使用api可以参考官网,非常简单,不做特殊说明,在配置完插件之后再启动会报错`Cannot find module 'vue-template-compiler'`编译器错误,我们需要下载和**vue**版本匹配的编译器,可以在**npmjs**上查看匹配版本,我这里的**vue版本是2.6.11**,对应的版本就是**vue-template-compiler@2.6.11**

```shell
pnpm add vite-plugin-vue2 -D
pnpm add vue-template-compiler@2.6.11 -D
import { defineConfig } from 'vite';
import { createVuePlugin } from 'vite-plugin-vue2';

export default () => {
    return defineConfig({
        plugins: [createVuePlugin()],
   })
}

关于vue的部分就省略了,因为和webpack去构建vue是没有任何区别的,着重想分享给大家的是在使用过程中我们会遇到的这些问题以及如何去处理它,如果你有疑问,可以在评论区留言。 通过如上操作,我们就可以通过vite启动一个没有任何额外配置的简单vue项目了

webpack升级vite踩坑指南

如果你已经构建好了一个由vite驱动的vue2的项目,如果你没有添加任何全家桶,相信你也不会有什么问题,因为基础的项目vite的默认支持已经足够了,但是如果你照搬老项目过来,你就会源源不断的出现新问题了,在下面我为你总结了这些错误,如果你有更多的错误,欢迎留言。

在学习错误之前请保证你已经经过了上述的配置,我们来开始进行接下来的升级指南吧。

常见错误处理

全局变量获取错误

在 升级为vite之后,我们的环境变量用process.env是获取不到的,我们需要在vite.config.js中添加下面这项配置:

define: {
  'process.env': {}
},

环境变量命名规范

  • 我们在vue-cli中对于环境的区分是通过env.xxx来区分环境,在vite中也是一样,不同的是,变量命名需要由前者的VUE_APP改变为VITE_APP,这里是一些小小的命名规范可全局替换不是什么大问题。

require引入错误

由于webpackcjs规范,所以很多场景我们可以使用require这种语法去加载,但是我们在vite中是esm规范,所以这个语法就会报错,如果想要使用这种语法,我们需要使用一个插件,这里面会有很多插件,我们选择一个vite-plugin-require,在开始的时候我尝试过一个插件是vite-plugin-require-transform,后面发现打包非常多错误,暂时没有去查看具体原因,这里建议不要使用,或者有错误的时候可以考虑避开这个插件。

import vitePluginRequire from 'vite-plugin-require';
plugins: [vitePluginRequire()],

代理配置问题

webpack中,我们一般很多接口会以api作为prefix,所以一次可以匹配很多,但是在vite中,需要注意的是,如果你的文件命名也包含api,就会在你访问你本地文件的时候被代理走,从而找不到文件,所以在配置proxy配置的时候需要注意不要和本地冲突,因为vite的加载文件方式都是通过直接加载本地文件来实现的,每一次的加载都是网络请求,所以可能会被你的代理配置影响到,如果出现404错误,可以看看是不是这个原因。

如果你的项目用到了websocket或者socket-io这类服务,我们需要在vite.config.js中配置以下选项,因为这可能和本地的hmr热更新发生冲突。我们需要手动变更下hmr的端口

hmr: {
  prot: 3888
}

全局less|scss变量配置

我们有时可能会用到全局变量,在webpack中,我们只需要使用一个包style-resources-loader,然后进行配置,相信很多人都使用过,在vite中更加简单,我们只需要直接配置即可,在vite.config.js中配置例如如下:

css: {
      preprocessorOptions: {
        less: {
          charset: false,
          additionalData: '@import "./src/style/common/common.less";'
        }
      }
    },

将其指向你的定义地址即可。

require.context()失效

webpack中我们经常需要批量注册,比如一次注册文件下所有的图标,store下面的所有模块等等都可以用到这个方法,但是他是由webpack提供的,所以现在不能用了,vite为我们提供了替代方法:import.meta.globEager,比如store的模块注册可以下面这样批量注册:

const modulesFiles = import.meta.globEager('./modules/*.js');
const modules = Object.keys(modulesFiles).reduce((modules, modulePath) => {
  const moduleName = modulePath.replace(/(./modules/)|(.js)/g, '');
  const value = modulesFiles[modulePath];
  modules[moduleName] = value.default;
  return modules;
}, {});

图片引用失败

当我们引入图片的时候很可能告诉你路径不正确,我们可以试想一下,每次在加载图片的时候像你的项目询问获取图片,这个时候的路径不是你本地项目的路径,而是静态服务器的路径,通过相对路径去获取就会404,所以我们可以直接使用绝对路径绑定src/xxx这样的形式,当然这只是其中一种方法。

我们也可以通过new URL的方式去得到一个完整连接,这种方法类似于path的拼接路径,可以抽离成公共方法:

new URL(`../assets/blogPhotos/${name}.jpg`, import.meta.url).href;

public目录与ico图标

  • 这个目录和vue-cli生成的项目是大同小异,放入这个文件夹的图片资源也不会被打包编译,而是直接引用,所以,我们想要设置网站图标就可以把图标直接放在当中,最简单的方式就是将图标转为svg图标放入,然后在index.html模板当中引入即可。

缓存文件

vite的缓存是比较重的,如果下载了某个依赖之后,依然提示你找不到包的问题,可以尝试去清除缓存,或者删掉node_modules重新下载,不要纠结一直找不到问题,可能有时候就是他本身的问题

"clear:cache": "# 清除项目缓存 \n    rimraf node_modules/.cache/ rimraf node_modules/.vite",

总结

  • 本文主要是为大家分享vue2项目配置vite工作所遇到的部分坑,很多东西可能忘记了,如果你也遇到了没法解约的文件,欢迎留言,可以追更到文章当中。
  • awesome-vite 中我们可以找到目前主流我们需要的插件,遇到不能解决的问题,可以在这里看看。
  • 总体来看,vite是完全可以放在vue2当中使用的,期间可能会遇到很多问题,目前市面上都是有解决方案的,如果你的项目也是启动花费大量的时间,不如尝试切换到vite试试看吧,目前来看是可行的。

回复

我来回复
  • 暂无回复内容