当前位置: 首页 > Web前端 > vue.js

vue-cli3vue2retainwebpack支持vite成功实践

时间:2023-04-01 00:58:21 vue.js

大家好!文为提高开发效率和体验实践而生。项目背景:脚手架:vue-cli3,具体为"@vue/cli-service":"^3.4.1"库:vue2,具体为:"vue":"2.6.12"备注:无typescript,非ssr痛点:随着时间的推移和业务的不断迭代,依赖、功能、代码越来越多。项目本地启动比较慢,开发热更新比较慢。改进目标:保留原有的webpack,支持vite。并尽可能减少改动以降低维护成本。考虑:vite生产环境使用rollup,更适合打包库。vite打包的效率并没有太大的提升。保留原有的webpack方法,尽可能保证生产的稳定性和安全性。实践主要涉及三个方面:配置文件需要根据vue.config.js添加vite.config.js入口文件index.html,以支持vite的方式配置vite。vite的启动命令可能需要路由懒加载,vite需要特殊处理解决commonjs和esModule的引入和混合问题添加vite.config.js在项目根目录下创建一个vite.config.js要求为安装npmivitevite-plugin-vue2-D根据vue.config.js在vite.config.js中添加相应的配置//如果改变这个文件的逻辑,请将vue.config.jsimportpathfrom'path'从'fs'导入{defineConfig}从'vite'导入配置从'./config'导入{createVuePlugin}从'vite-plugin-vue2'导入{injectHtml}从'vite-plugin-html'constresolve=dir=>路径。join(__dirname,dir)constalias={vue:'vue/dist/vue.esm.js','@':resolve('src'),}constpublicPath='/'constmode='development'//https://vitejs.dev/config/exportdefaultdefineConfig({base:publicPath,plugins:[createVuePlugin(),],//这些是项目中注入的变量,如果有process开头的变量,需要这里要注入,Vite默认不会注入进程相关的变量和值),},resolve:{//配置别名,//导入时要省略的扩展列表,必须加上.vue,因为vite默认不支持省略.vue后缀extensions:['.mjs','.js','.ts','.jsx','.tsx','.json','.vue']},server:{//允许跨域cors:true,proxy:{//可以直接复制vue.config.js中对应的proxy}}})sass相关配置特别说明:如果项目中有用到sass预处理器,并且用到变量,需要安装sass@1.32.13,并且你无法安装高于1.32的版本。版本有这个问题Sasserror:Using/fordivisionisdeprecatednpmisass@1.32.13-DexportdefaultdefineConfig({...css:{//passoptionstosasspreprocessorOptions:{scss:{charset:false,//latestOnlyversionsasssupportsadditionalData:`@import"src/sass/common/var.scss";`,}},},...})备注:如果生产环境用vite打包,使用sass@1.32。13会遇到这个问题,vite2打包的时候有警告,"@charset"mustbethefirst,怎么消除?,但是sass@1.32.13不支持文档中的配置。所以这也算是生产环境没有使用vite的原因之一。还需要全局替换/deep/为::v-deep入口文件index.html来支持vite,因为vite项目要求index.html文件在根目录下,并且有入口文件配置。所以将index.html从public目录移动到根目录。并添加<%if(typeofisVite==='boolean'&&isVite){%><%}%>这个配置是为了同时支持webpack和vite方法,共享一个文件,为了将isVite变量注入到index.html文件中,你需要安装npmivite-plugin-html-D并在vite.config.js中配置它...从'vite-plugin-html'导入{injectHtml}导出默认defineConfig({...plugins:[...injectHtml({data:{title:'vite-plugin-html-example',isVite:true},}),],define:{'process.env.isVite':JSON.stringify(true)},...})配置vite启动命令,最后在package.json中添加脚本"scripts":{"vite-start":"vite"}路由延迟加载,vite需要对vue进行特殊处理。懒路由的实现方式是这样constHome=import(/*webpackChunkName:"[home]"*/`@/page/home.vue`)constroutes=[{path:`/home`,name:'home',component:Home},]但是vite不支持,解决constmodules=import.meta.glob('@/page/*.vue')constHome=modules['@/page/home.vue']constmodules=import.meta.glob('@/page/*.vue')//vite将生成代码constmodules={'@/page/home.vue':()=>import('@/page/home.vue'),'@/page/page1.vue':()=>import('@/page/page1.vue'),'@/page/page2.vue':()=>import('@/page/page2.vue'),...}参考:vite-Globimport所以可以这样封装:functionloadPage(view){if(process.env.isVite){constmodules=import.meta.glob('../pages/*.vue')returnmodules[`../pages/${view}.vue`]}return()=>import(/*webpackChunkName:"[request]"*/`@/pages/${view}`)}//使用:constroutes=[{path:`/home`,name:'home',component:loadPage('home'),},{path:`/404`,name:'404',component:loadPage('404'),},]但webpack不支持import.meta,需要loader处理解决方案:在本地建一个文件webpack-import-meta-loader.js。//来源:https://github.com/KmjKoishi/webpack-import-meta-loader-fixed//是对@open-wc/webpack-import-meta-loader的修复//主要是当这个。rootContext不存在的判断处理。构建产品环境时不存在/*eslint-disable*///@ts-nocheckconstpath=require('path');functiontoBrowserPath(filePath,_path=path){returnfilePath.replace(newRegExp(_path.sep==='\\'?'\\\\':_path.sep,'g'),'/');};constregex=/import\.meta/g;/***重写`将带有url数据的模块中的import.meta导入到源代码文件位置。**@example*返回import.meta;*//变成:return({url:`${window.location.protocol}//${window.location.host}/relative/path/to/file.js`});**返回import.meta.url;*//变成:return({url:`${window.location.protocol}//${window.location.host}/relative/path/to/file.js`}).url;*/module.exports=function(source){constpath=require('path');constrelativePath=this.context.substring(this.context.indexOf(this.rootContext)+(this.rootContext&&this.rootContext.length>=0?(this.rootContext.length+1):0),this.resource.lastIndexOf(path.sep)+1,);常量浏览rPath=toBrowserPath(相对路径);constfileName=this.resource.substring(this.resource.lastIndexOf(path.sep)+1);让发现=假;让rewrittenSource=source.replace(regex,()=>{found=true;return`({url:getAbsoluteUrl('${browserPath}/${fileName}')})`;});if(found){return`functiongetAbsoluteUrl(relativeUrl){constpublicPath=__webpack_public_path__;让url='';如果(!publicPath||publicPath.indexOf('://')<0){url+=window.location.protocol+'//'+window.location.host;}if(publicPath){url+=publicPath;}else{url+='/';}返回url+relativeUrl;}${rewrittenSource}`;}else{返回源代码;}};vue.config.js修改配置:constresolve=dir=>require('path').join(__dirname,dir)module.exports={...configureWebpack:{...module:{rules:{...{测试:/index.js$/,使用:[resolve('webpack-import-meta-loader'),'babel-loader'],include:[resolve('src/router')]}}}}...}resolvecommonjs和esModule的引入和混用在webpack混用的方式下,如果你的src工程源码中存在commonjs和esModule的混用解决方案一:不改源码,在vite.config.js中添加配置,转换commonjstoesModuleinstallnpmicjs2esmodule-D在vite.config.js中添加exportdefaultdefineConfig({plugins:[cjs2esmVitePlugin()]})如果这个方案可以让你的项目正常运行。否则,可能需要选项二。方案二:手动将src代码中的commonjs语法改成esModule导入即可。如果你的项目有一个config.js,它在vue.config.js中使用。那么你可能需要处理这个问题。vue.config.js必须是commonjs语法文件才可以使用,否则会报错。vite.config.js可以是esModule语法或commonjs语法。默认是esModule语法。如果以上混合使用,你使用的是第二个选项,src代码中也使用了config.js。那只能把config.js改成esModule了。此时不支持vue.config.js,采用的方案是在config.js的基础上自动生成一个config-cjs.js。目的是减少后期维护成本。//transformConfig2cjs.js//运行项目时,会根据config.js自动生成文件:config-cjs.js,这样vue-config.js可以直接使用const{transformAsync}=require('@babel/核心');constplugin=require('@babel/plugin-transform-modules-commonjs')constfs=require('fs')constresolve=dir=>require('path').join(__dirname,dir)asyncfunctiontransfrom(){constinputPath=resolve('config.js')constinput=fs.readFileSync(inputPath,'utf-8')const{code}=awaittransformAsync(input,{sourceType:'module',插件:[插件]});fs.writeFileSync(resolve('./config-cjs.js'),code);}transfrom()然后改成config-cjs其中vue.config.js原来引入了config.js。最后,更改package.json中的脚本以每次重新生成最新的配置。“脚本”:{“transformConfig2cjs”:“节点transformConfig2cjs.js”,“服务”:“npmruntransformConfig2cjs&&vue-cli-serviceserve”,“build”:“npmruntransformConfig2cjs&&vue-cli-servicebuild”,}总结遇到了很多坑,都和语法有关,终于在11解决了!我还尝试了其他一些解决方案,但它们没有用。我的项目没有生效:wp2vite支持后,开发真高效!希望这篇文章对有需要的人有所帮助。