vue2+webpack to vue2+vite改造记录

开个头

vite跑一个项目的确要快得多,不过因为是新玩意儿,打包的时候还是webpack比较稳妥,现在vite只用在开发环境用以提高开发效率。
下面我会记录我将一个vue2工程移植到vite并兼容webpack打包功能的全过程。

第一步:想办法白嫖一个配置文件

从头开始写配置文件也行,但是总是没有白嫖香的。
这里使用了一个库https://github.com/originjs/webpack-to-vite/blob/main/README-zh.md
1.下载:

npm install @originjs/webpack-to-vite -g

2.使用:项目目录下输入命令

webpack-to-vite -d ./

3.效果:
在这里插入图片描述

可以看到更目录下多出三个文件,conversion.log,index.html,vite.config.js。
前两个都不重要,重点是vite.config.js,为我们提供了一个vite配置文件的基础模板,虽然还有些问题,不过再进行改造就好了。
除此之外,package.json也有了改动,
在这里插入图片描述

在这里插入图片描述

第二步:试着跑一下,然后解决报错

serve-vite

项目更目录下执行

npm run serve-vite

很快,且很顺利的跑出来了
在这里插入图片描述

但是事情并没有这么简单,打开页面后并没有看到想要的页面,而是一个大大的报错。
为什么会这样?因为vite和webpack有所不同,它不需要先打包,而是先启动web server,等到浏览器请求文件的时候再进行编译,更加详细的相关知识在第五步会有提到。在这里插入图片描述

可以预见,后面还会有很多的报错,想要看到页面,需要一个一个的把这些报错解决掉才行。

variable @xxxxxx is undefined

@main_color是我们自己用less定义的全局变量,vite找不到这个变量,需要我们把自定义的全局变量从外部注入。
这一点就和webpack配置中使用style-resources-loader添加less的全局变量有点类似。
解决:在vite.config.js添加以下代码

css: {
    preprocessorOptions: {
        less: {
            modifyVars: {
                hack: `true; @import (reference) "${path.resolve('src/assets/styles/resources.less')}";`,
            },
            javascriptEnabled: true,
        },
    },
},

注意这里的src/assets/styles/resources.less指的是项目的less变量声明文件路径,并非一定要和我的一样。

Failed to parse source for import analysis…

在这里插入图片描述

具体原因不明,不过从现象上来看,是viteCommonjs将lodash.js被解析出了毛病。
人家的源码是正常的在这里插入图片描述

猜测是因为解析过程中吧字符串中的//识别成了注释,所以发生了这种诡异的事情。毕竟很多vite的扩展还在快速的更新当中,还不够成熟,有这样的问题我们只能暂时放弃使用某些扩展。
解决:
vite.config.js中viteCommonjs扩展先删除(同时其余几个暂时用不到的也一并删除)

import envCompatible from 'vite-plugin-env-compatible';
import { injectHtml } from 'vite-plugin-html';
import { viteCommonjs } from '@originjs/vite-plugin-commonjs';

Uncaught ReferenceError: require is not defined

vite不支持require,能import引入的尽量用import吧,因为viteCommonjs造成了上一个报错还无法使用,又暂时还没有找到其他的扩展可以很好的处理这个问题。
注:不过require.context不用手动做处理,有ViteRequireContext帮我们解决。
解决:
将源代码中的require替换为import。
例如本项目中的

const Base64 = require('js-base64').Base64;

替换为

import { Base64 } from 'js-base64';

Uncaught ReferenceError: process is not defined

vite打出来折后无法直接通过process.env访问环境变量,秉持着尽量不动源码的原则,有了下面的解决方法:
在vite.config.js中添加以下配置

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

SyntaxError: The requested module ‘xxx/xxx’ does not provide an export named ‘xxx’

如果我们使用的包都在node_modiles里应该不会有这个问题,但是如果不是的话,就可能会遇到这个报错。
报错的原因是因为这些包没有ESM的导出方式,当我们使用import的方式引入,就会报错。
那为什么node_modiles里的包我们使用import不会出现这种问题?在vite的官方文档上给我们解释了:
在这里插入图片描述

虽然我们没有对这个属性进行配置,不过vite会自行的去抓取依赖项的入口点,并进行预构建。
那么只要让我们自己的包也进行与构建,就不会有问题了。
解决:
在vite.config.js中添加下面这段代码

// 依赖优化选项
    optimizeDeps: {
        // 默认情况下,不在 node_modules 中的,链接的包不会被预构建。使用此选项可强制预构建链接的包。
        include: ['@/assets/js/fabric.min.js'],
    },

到这里,我已经可以看到我的页面了,当然如果你尝试复刻这个过程又遇到了其他我没有记录的问题,欢迎在这里补充解决方法。

第三步:页面上到处点点,完善一些细节

icon-font没有正确显示

在这里插入图片描述

还记得webpack-to-vite在根路径下生成的那个index.html吗,造成这个问题的原因就是在这个文件中没有引入iconfont.css等资源。

解决:
①将public/index.html拷贝到根目录下,覆盖掉webpack-to-vite生成的index.html。
②文件中添加一句

<script type="module" src="/src/main.js"></script>

③修改一些资源的路径,因为文件路径不同了,可能会找不到导致报错。
有<%= BASE_URL %>之类的代码直接改为/即可。

一些图片404

并非所有的图片404,而是采用

 url('~@/assets/images/czjl.png')

这种方式引入的图片会报错。
vite不认识这样的路径,我们需要特殊处理一下。
在vite.config.js中添加配置

resolve: {
    alias: [
        {
            find: '~@',
            replacement: path.resolve(__dirname, 'src'),
        },
        {
            find: /^~/,
            replacement: '',
        },
        {
            find: '@',
            replacement: path.resolve(__dirname, 'src'),
        },
    ],
},

第四步:继续完善

webpack版本我们在eslint和stylelint报错的时候是会在页面上有提示的,不过现在vite跑出来的页面还没有这样的功能,我们需要一些扩展。
试用了很多之后最终选用以下两个
vite-plugin-eslint,@frsource/vite-plugin-stylelint
操作步骤
下载:

npm install @frsource/vite-plugin-stylelint --save-dev
npm install vite-plugin-eslint --save-dev

引入:
在vite.config.js中

import eslintPlugin from 'vite-plugin-eslint';
import stylelintPlugin from '@frsource/vite-plugin-stylelint';

使用:

plugins: [
    createVuePlugin(),
    ViteRequireContext(),
    stylelintPlugin(),
    eslintPlugin(),
],

第五步:重新认识一下vite

兼容性

需要node12或以上版本。

你就说快不快吧

冷启动

webpack
webpack执行build的时候会从入口文件开始,将整个项目的文件编译成一个或多个单独的 js 文件到内存中,然后再启动开发server。
当项目大了之后,冷启动很慢的问题就暴露出来了,因为打包这一步会因为项目文件太多而消耗大量的时间。
在这里插入图片描述

vite
vite启动开发server的时候,不会去提前打包所有文件,而是执行预构建依赖,然后启动服务。
因为使用esbuild 预构建依赖,据说比以 JavaScript 编写的打包器预构建依赖快 10-100 倍。
当浏览器访问某个路由的时候,再在服务器端编译相应源码文件,以 原生 ESM 方式提供源码。
所以可以看到,vite启动服务是很快的;不过同时他第一次打开页面的速度会相对较慢,因为通过上面的描述可以知道,与webpack相比,vite让浏览器承担了一定的打包任务。
在这里插入图片描述

热更新

webpack
Webpack 的热更新会以当前修改的文件为入口重新 build 打包,所有涉及到的依赖也都会被重新加载一次。项目越大,依赖越多,时间越久。
vite
每个文件通过 http 头缓存在浏览器端,当编辑完一个文件,只需让此文件缓存失效。当基于 ES module 进行热更新时,仅需更新失效的模块,这使得更新时间不随包的增大而增大。
当然如果修改的文件不再缓存中,那就更方便了,你完全感受不到任何卡顿,因为vite根本不会去处理这个文件。

总结

所以vite较webpack,有以下几个优点
1.快速冷启动
2.按需编译
3.模块热更新

缺点

1.因为按需编译,所以切换到一个从来没进入过的路由时会感觉到一个明显卡顿。
2.因为尚且年轻,与webpack相比,缺少很多可以稳定使用的扩展。
3.vite本身只支持esm,对一些年龄较大的依赖包可能不能非常好的支持,同时对不支持esm的浏览器也不友好。

啥是esm,啥又是cjs、amd、umd呀

先停止联想,esm和ems没有关系,这个amd也和显卡无关,他们都是javascript模块化的方法。
可能这些名称看着有些懵,不过你肯定是用过import * from,require,这些方法的,这里简单地去介绍一下他们,方便你更清晰的理解vite。

esm

即ESModule,是ECMAScript自己的模块体系,在ES6引入,目前大部分浏览器都支持。
一般这么用:

// 导出:export命令
export const obj = {name: 'E1e'}// 默认导出 export default命令
export default {name: 'E1e'};

// 引入接口:import命令
// 引入普通导出
import { obj } from './test.js';
// 引入默认导出
import obj from './test.js';
cjs

即CommonJS,浏览器无法直接运行,需要编译,一般使用方法:

// importing 
const doSomething = require('./doSomething.js'); 
// exporting
module.exports = function doSomething(n) {
  // do something
}

有时候会看到直接exports=xxx,你可以理解为node在上方自带了一行var exports = module.exports;

amd

即asynchronously,一般使用方法:

define(['dep1', 'dep2'], function (dep1, dep2) {
    //Define the module value by returning a value.
    return function () {};
});
//
define(function (require) {
    var dep1 = require('dep1'),
        dep2 = require('dep2');
    return function () {};
});
umd

即Universal Module Definition,这是一种通用方法,其中既有cjs的身影,也有amd的影子,用来解决多平台的兼容问题,在依赖包中会很常见,一般会是这样:

(function (window, factory) {
    if (typeof exports === 'object') {
        module.exports = factory();
    } else if (typeof define === 'function' && define.amd) {
        define(factory);
    } else {
        window.eventUtil = factory();
    }
})(this, function () {
    //module ...
});

现在你知道为什么require方法在vite中无法使用了,因为vite只支持esm。
同时之前被我们放弃使用的viteCommonjs扩展,你光看名字应该也能才出他的用途了,就是为了让vite能够兼用cjs,但是很明显这个插件目前看来还不够成熟,无法投入实际使用,只能期待他尽快更新版本。

其他问题

1.为什么proxy的配置好像和vue.config.js中一样?

因为两者实现代理用的都是http-proxy,两者配置基本上可以通用。

2.define可以用来自定义全局变量吗?

不可以,官方文档写了,它是用来定义全局变量替换方式。是用来替换本来就有的变量的,自定义变量无法实现。

3.modifyVars是个啥?

这是一个less的设置选项,可以粗暴地理解为覆盖less全局变量。
@import (reference)则是将文件当做样式库引入的意思。

  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值