拥抱下一代前端工具链-Vue老项目迁移Vite探索

拥抱,下一代,前端,工具,vue,项目,迁移,vite,探索 · 浏览次数 : 449

小编点评

**前端迁移指南** **1.项目结构** - index.html - vite.config.js **2.配置文件** - vite.config.js **3.打包工具** - 两个打包工具,vue-cli 支持 **4.模块规范** - 许多问题,通过各种插件来兼容解决 **5.开发模式** - 页面首次加载时间比较缓慢,大约在5s左右,不过这也是可以理解的 **6.总结** - 整体迁移过程,丰富、优化了前端工具链的构建流程,极大的提升了开发人员的幸福感,以及开发体验

正文

作者:京东物流 邓道远

背景描述

随着项目的不断维护,代码越来越多,项目越来越大。调试代码的过程就变得极其痛苦,等待项目启动的时间也越来越长,尤其是需要处理紧急问题的时候,切换项目启动,等待的时间就会显得尤为的漫长。无法忍受这种开发效率的我,决定将老项目迁移至vite。

距离Vite工具发布到现在已经有了一些日子了,工具链与生态已经趋于稳定,最新版本已经更新到了3.0,既然念头已起,心动不如行动。

1、什么是Vite

vite 发音为/vit/ 法语中就是快的意思,“人”如其名,就是快

  • 一个开发服务器,它基于原生ES模块,提供了丰富的内建功能,如速度快到惊人的模块热更新(HRM)

  • 一套构建指令,它使用rollop来打包你的代码,并且是预配置的,可输出用于生产环境的高度优化过的静态资源。

2、为什么快

众所周知,当冷启动服务器时,基于打包器的启动必须优先抓取并构建你的整个应用,然后才能提供服务,这一抓取构建的过程随着文件越来越多,时间也会越来越长。

而Vite却通过将应用中的木块区分为依赖和源码两类,从而优化了大量的服务器启动时间。

  • 依赖大多为在开发时不会变动的纯 JavaScript。一些较大的依赖(例如有上百个模块的组件库)处理的代价也很高。依赖也通常会存在多种模块化格式(例如 ESM 或者 CommonJS)。

  • Vite 将会使用 esbuild预构建依赖。esbuild 使用 Go 编写,并且比以 JavaScript 编写的打包器预构建依赖快 10-100 倍。

  • 源码通常包含一些并非直接是 JavaScript 的文件,需要转换(例如 JSX,CSS 或者 Vue/Svelte 组件),时常会被编辑。同时,并不是所有的源码都需要同时被加载(例如基于路由拆分的代码模块)。

  • Vite 以原生 ESM方式提供源码。这实际上是让浏览器接管了打包程序的部分工作:Vite 只需要在浏览器请求源码时进行转换并按需提供源码。根据情景动态导入代码,即只在当前屏幕上实际使用时才会被处理。

3、如何完成老项目迁移

当前项目是Vue2.0,vue-cli4.0,node v14.18.2

3.1 首先我们需要先明确项目结构

与原来的Vue老项目相比,模板文件 index.html 需要从public挪到项目根目录中,Vite将 index.html 视为源码和模块图的一部分。由于我们只有一个入口文件,所以在index.html中需要引入main.ts

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

而且运行过程中可能会遇到下面写法引发的报错

<link rel="icon" href="<%= BASE_URL %>favicon.ico" />


[vite] Internal server error: URI malforme

解决办法是可以写一个简单的插件替换一下

res = code.replace(/<%=\s+BASE_URL\s+%>/g, baseDir);

与Vue-cli相同,需要一个配置文件 vite.cofnig.js, 与原来的vue.config.js同级

3.2 安装依赖

既然我们使用Vite,那么我们需要安装一个vite依赖。但是我们的老项目是Vue2.0,vite优先支持Vue3.0,所以我们还需要一个转换工具 "vite-plugin-vue2"

npm i vite vite-plugin-vue2 -S

3.3 修改配置文件

修改package.json中的scripts,启动和打包方式使用vite

  • "serve": "vite",

  • "build": "vite build",

修改vite.config.js,与vue.config.js相似

import { defineConfig } from 'vite'
import { createVuePlugin } from 'vite-plugin-vue2'
  
// https://vitejs.dev/config/   这一行可以增加编辑器代码提示
export default defineConfig({
     plugins: [
       createVuePlugin({
 jsx: true, // 兼容项目中的jsx组件
      vueTemplateOptions: {}
    }),
     ],
     resolve: {
  extensions: ['.vue', '.js', '.ts', '.jsx', '.tsx', '.json'],
       alias: [
{
        find: '@',
        replacement: '/src'
}
]
     },
server: {
    open: true, // 控制台直接打开浏览器
    host: 'xxxx.jd.com', // 本地host
    allowedHosts: ['.jd.com', '.jdwl.com', '.jd.co.th', '.jd.id'],
    port: 80,
    cors: true,
    proxy: {
      '/api': {
        target: 'https://xxx.jd.com',
        changeOrigin: true,
        rewrite: path => path.replace(/^\/api/, '/api')
      }
    }
  },
 })

3.4 剔除原来的webpack相关依赖

可以手动剔除 也可以重新启动一个vite项目再将所需代码移动到vite项目中

3.5 启动应用

这个时候我们就可以启动应用了,不出意外的话,会有许多的报错信息,不过不要慌,我们一个一个的解决

4、遇见的问题汇总

4.1 环境变量

webpackl里的环境变量是默认存储在process.env里的,而vite是存储在import.meta.env里的

import.meta.env.MODE: {string} 应用运行的模式。

import.meta.env.BASE_URL: {string} 部署应用时的基本 URL。他由base 配置项决定。

import.meta.env.PROD: {boolean} 应用是否运行在生产环境。

import.meta.env.DEV: {boolean} 应用是否运行在开发环境 (永远与 import.meta.env.PROD相反)。

当然,既然是老项目,这种调用位置会有很多,我们可以使用比较简单的做法来兼容

export default defineConfig({
  define: {
    'process.env': {}
  },
})

4.2 global 变量

因为VIte 是 ESM机制,有些包内部使用了 node 的 global对象,解决此问题可以通过自建pollfill, 然后在main.ts顶部引入

// polyfills
if (typeof (window as any).global === 'undefined') {
  ;(window as any).global = window
}

4.3 Scss全局变量报错

这一点是vite与vue-cli 配置方式不同引发,而且如果使用了环境变量也需要适配vite的写法兼容

export default defineConfig({
  css: {
    preprocessorOptions: {
      scss: {
        additionalData: '$ossHostVariable: \'import.meta\u200b.env.VUE_APP_OSS_HOST\';'
      }
    }
  }
})


4.4 path 报错

Vite 是 ESM机制 path是node的包,所以需要兼容浏览器的引入方式,需要安装依赖 “path-broswserfiy”

只需要将引入的包替换即可

import path from 'path' 
// 替换成
import path from 'path-broswserfiy' 

4.5 Require报错

问题的引发与上面一致 都是模块加载方式的不同导致的,可以通过"
vite-plugin-require-transform"插件来解决

import requireTransform from 'vite-plugin-require-transform'
export default defineConfig({
  plugins: [
requireTransform({})
]
})

4.6 vue组件的动态导入

vue的组件导入方式有很多,vite可以支持 () => import('/.vue')的方式导入,不过与webpack的区别在于需要补全文件的后缀,动态导入需要 import.meta.glob的方式

const load = import.meta.glob('@/views/**/index.vue');


export const constantRoutes: any = [
  {
    path: '/404',
    component: load['404']
  },
]

4.7 编译时的分包策略

const SPLIT_CHUNK_CONFIG = [
  {
    match: /[\\/]src[\\/]_?common(.*)/,
    output: 'chunk-common',
  },
  {
    match: /[\\/]src[\\/]_?component(.*)/,
    output: 'chunk-component',
  },
];


const rollupOptions = {
  output: {
    chunkFileNames: 'assets/js/[name]-[hash].js',
    entryFileNames: 'assets/js/[name]-[hash].js',
    assetFileNames: 'assets/static/[name]-[hash].[ext]',
    manualChunks(id) {
      for (const item of SPLIT_CHUNK_CONFIG) {
        const { match, output } = item;


        if (match.test(id)) {
          return output;
        }
      }


      if (id.includes('node_modules')) {
        return id.toString().split('node_modules/')[1].split('/')[0].toString();
      }
    },
  },
}

5、启动时间

不多说了 上图

不过还会有一些问题,开发模式下比如页面首次加载时间比较缓慢,大约在5s左右,不过这也是可以理解的,毕竟编译过程都交给了浏览器,相比于老项目冷启动动辄2 3分钟的体验,已经是天大的提升了。

6、总结

最后再来回顾一下,整体的迁移过程。

首先,明确项目结构,index.html模板文件 提到根目录下,统计增加vite.config.js文件。

然后,编写配置文件 vite.config.js 注意与 vue.config.js上的语法区别,注意兼容写法。

最后,处理项目中两种打包工具的不兼容写法。大部分还是模块规范的区别,node环境的变量以及语法所引发,可以通过各种各样的插件来兼容解决。

以上即为本次迁移的全部过程,丰富、优化了前端工具链的构建流程,极大的提升了开发人员的幸福感,以及开发体验,项目冷启动时间更是提升了百分之99%。虽然前期遇到了许多的坑,但是成功后的感受就是一个字,"真香"。

与拥抱下一代前端工具链-Vue老项目迁移Vite探索相似的内容:

拥抱下一代前端工具链-Vue老项目迁移Vite探索

随着项目的不断维护,代码越来越多,项目越来越大,决定将老项目迁移至vite。本文介绍了Vue老项目像Vite迁移的过程、遇到的问题以及经验总结。

[转帖]内存管理干货推荐:巨页HugePage

https://zhuanlan.zhihu.com/p/542132384 前言: 巨页的提出初衷是提供对内存使用量大的进程在某些场合下能拥有更好的性能的一种策略。巨页的定义有些含糊,按照最初提出patchset的人的意思,只要大于系统默认PAGE_SIZE的页,都可以称之为巨页。巨页从2.6发展

11个Python循环技巧

本文分享自华为云社区《Python中的循环技巧指南》,作者:柠檬味拥抱。 当我们处理数据时,有时候需要创建多个列表以存储不同类型或不同条件下的数据。在Python中,我们可以利用循环来快速、高效地创建这些列表。本文将介绍如何使用循环在Python中创建多个列表,并提供代码实例。 python用循环新

解密Prompt系列16. LLM对齐经验之数据越少越好?LTD & LIMA & AlpaGasus

总结下指令微调、对齐样本筛选相关的方案包括LIMA,LTD等。论文都是以优化指令样本为核心,提出对齐阶段的数据质量优于数量,少量+多样+高质量的对齐数据,就能让你快速拥有效果杠杠的模型

联邦学习:联邦异构知识图谱数据划分

在联邦场景下,C个知识图谱位于不同的客户端上。知识图谱拥的实体集合之间可能会存在重叠,而其关系集合和元组集合之间则不会重叠。我们联系一下现实场景看这是合理的,比如在不同客户端对应不同银行的情况下,由于不同银行都有着自己的业务流程,所以关系集合不重叠。本文我们来看具体在实验环节怎么去划分联邦异构知识图谱数据。

如何在微服务下保证事务的一致性

微服务架构是将单个服务拆分成一系列小服务,且这些小服务都拥有独立的进程,彼此独立,很好地解决了传统单体应用的上述问题,但是在微服务架构下如何保证事务的一致性呢?

AR Engine毫秒级平面检测,带来更准确的呈现效果

近年来,AR版块成为时下大热,这是一种将现实环境中不存在的虚拟物体融合到真实环境里的技术,用户借助显示设备可以拥有真实的感官体验。AR的应用场景十分广泛,涉及娱乐、社交、广告、购物、教育等领域:AR可以让游戏更具互动性;商品通过AR展示更真实;使用AR进行教育教学让抽象事物更形象等,可以说AR技术已

[转帖]什么情况下适合用UDP协议,什么情况下适合用TCP协议?

TCP与UDP基本区别 基于连接与无连接TCP要求系统资源较多,UDP较少;UDP程序结构较简单流模式(TCP)与数据报模式(UDP);TCP保证数据正确性,UDP可能丢包TCP保证数据顺序,UDP不保证 UDP应用场景: 面向数据报方式网络数据大多为短消息拥有大量Client对数据安全性无特殊要求

[转帖]什么情况下适合用UDP协议,什么情况下适合用TCP协议?

TCP与UDP基本区别 基于连接与无连接TCP要求系统资源较多,UDP较少;UDP程序结构较简单流模式(TCP)与数据报模式(UDP);TCP保证数据正确性,UDP可能丢包TCP保证数据顺序,UDP不保证 UDP应用场景: 面向数据报方式网络数据大多为短消息拥有大量Client对数据安全性无特殊要求

[转帖]Linux中的用户和用户组

https://www.jianshu.com/p/76700505cac4 1,Linux中的用户分类 超级用户:拥有对系统的最高管理权限,默认是root用户。 普通用户:只能对自己目录下的文件进行访问和修改,具有登录到系统的权限。 虚拟用户:这类用户最大的特点就是不能登录系统,他们的存在主要是方