vue 2.x + @vue/cli 4.x开发阶段使用Vite

项目用的是vue 2.x + @vue/cli 4.x(webpack 4.x)。冷启动项目时耗时较长,达到了2分钟以上。热更新时间也达到了10s以上。严重影响了开发体验和效率。

解决问题的过程中遵循2个原则:

  1. 不对会影响原构建流程的代码进行改动,向原Webpack构建兼容。
  2. 只引入开发阶段的构建服务。

安装vite

vue需要2.7.X
vue-template-compiler需与vue版本一致

相关依赖

package.json对比
在这里插入图片描述
在这里插入图片描述
相关依赖

//package.json
  "scripts":{
    "serve:vite": "IS_IN_VITE=true vite",
  },
  "dependencies": {
    "vue": "2.7.16",
  },
  "devDependencies": {
    "@vitejs/plugin-vue2": "^2.3.1",
    "@vitejs/plugin-vue2-jsx": "^1.1.1",
    "speed-measure-webpack-plugin": "^1.5.0",
    "unplugin-auto-import": "^0.18.0",
    "vite": "^5.3.3",
    "vite-plugin-antdv-fix": "^1.0.3",
    "vite-plugin-commonjs": "^0.10.1",
    "vite-plugin-html": "^3.2.2",
    "vite-plugin-lang-jsx": "^1.5.3",
    "vite-plugin-require-transform": "^1.0.21",
    "vue-template-compiler": "2.7.16",
    "webpack-strip-block": "^0.3.0",
  }

新建vite.config.js

主要处理vue-cli的

//vite.config.js
import path from 'node:path'
import { defineConfig, loadEnv } from 'vite'
import vue from '@vitejs/plugin-vue2'
import { createHtmlPlugin } from 'vite-plugin-html'
import vueJsx from '@vitejs/plugin-vue2-jsx'
import langJsx from 'vite-plugin-lang-jsx'
import commonjs from 'vite-plugin-commonjs'
import antdvFix from 'vite-plugin-antdv-fix'

const assetsCDN = {
  // webpack build externals
  externals: {
    vue: 'Vue',
    'vue-router': 'VueRouter',
    vuex: 'Vuex',
    './cptable': 'var cptable',
    axios: 'axios'
  },
  css: [],
  js: [
    '/js/vue.min.js',
    '/js/vue-router.min.js',
    '/js/vuex.min.js',
    '/js/axios.min.js'
  ]
}

// https://vitejs.dev/config/
export default defineConfig(({ mode, command }) => {
  const env = loadEnv(mode, process.cwd())
  const isPro = mode === 'production'

  function getEnv(key) {
    return loadEnv(mode, process.cwd(), '')[key]
}
  return {
    // 部署生产环境和开发环境下的URL。
    // 默认情况下,vite 会假设你的应用是被部署在一个域名的根路径上
    // 例如 https://www.ruoyi.vip/。如果应用被部署在一个子路径上,你就需要用这个选项指定这个子路径。例如,如果你的应用被部署在 https://www.ruoyi.vip/admin/,则设置 baseUrl 为 /admin/。
    base: '/',
    define: {
      'process.env': process.env,
      IS_IN_VITE: true,
    },
    plugins: [
      langJsx(),
      vue(),
      vueJsx(),
      antdvFix(),//解决ant-design-vue的date-picker组件在使用时报错
      createHtmlPlugin({
        minify: true,
        /**
         * 在这里写entry后,你将不需要在`index.html`内添加 script 标签,原有标签需要删除
         * @default
         */
        entry: '/src/main.js',
        /**
         * 如果你想将 `index.html`存放在指定文件夹,可以修改它,否则不需要配置
         * @default index.html
         */
        template: 'public/index.html',
        inject: {
          data: {
            htmlWebpackPlugin: {
              options: {}
            }
          }
        },
      }),
      
      commonjs({
        filter(id) {
          // `node_modules` is exclude by default, so we need to include it explicitly
          // https://github.com/vite-plugin/vite-plugin-commonjs/blob/v0.7.0/src/index.ts#L125-L127
          if (
            id.includes('node_modules/@jiaminghi') ||
            id.includes('node_modules/viser') ||
            id.includes('node_modules/@antv')
            // id.includes('node_modules/@babel/runtime')
          ) {
            return true
          }
        },
        dynamic: {
          loose: false,
        }
      }),
    ],
    optimizeDeps: {
      // include: ['viser-vue'],
      // exclude: ['@jiaminghi/c-render'],
    },
    resolve: {
      // https://cn.vitejs.dev/config/#resolve-alias
      alias: [
        // 设置别名
        { find: /^~(?!@)/, replacement: '' }, // 将 ~ 替换为空字符串,以支持直接从 node_modules 导入
        { find: /^~@/, replacement: path.resolve(__dirname, './src') }, // 将 ~@ 替换为项目中的 src 目录
        { find: '@', replacement: path.resolve(__dirname, './src') }, // 将 @ 替换为项目中的 src 目录
      ],
      // https://cn.vitejs.dev/config/#resolve-extensions
      extensions: ['.mjs', '.js', '.ts', '.jsx', '.tsx', '.json', '.vue'],
    },
    // vite 相关配置 代理
    server: {
      port: 9001,
      host: true,
      open: true,
      proxy: {
        '/api': {
          target:getEnv('VUE_APP_API_BASE_URL'),
          ws: false,
          changeOrigin: true,
          pathRewrite: {
            // 需要rewrite的path
          }
        },
        '/epros': {
          target: 'http://dopeprostest.pipechina.com.cn:30080/api',
          ws: false,
          changeOrigin: true,
          pathRewrite: {
            '^/epros': ''
            // 需要rewrite的path
          }
        }
      }
    },
    // fix:error:stdin>:7356:1: warning: "@charset" must be the first rule in the file
    css: {
      preprocessorOptions: {
        less: {
          modifyVars: {
            'primary-color': '#1890FF',
            'layout-color': '#1890FF',
            'border-radius-base': '2px'
          },
          // DO NOT REMOVE THIS LINE
          javascriptEnabled: true
        }
      },
      postcss: {
        plugins: [
          {
            postcssPlugin: 'internal:charset-removal',
            AtRule: {
              charset: (atRule) => {
                if (atRule.name === 'charset') { atRule.remove() }
              },
            },
          },
        ],
      },
    },
  }
})

vue 动态路由vite处理

let route_modules = null
/* develblock:start */
if (window.IS_IN_VITE) {
  route_modules = import.meta.glob('@/views/**/*.vue')
  let _routeModules = {}
  Object.keys(route_modules).forEach(key => {
    const dir = key.split('views/')[1].split('.vue')[0];
    _routeModules[dir] = route_modules[key]
  })
  route_modules = _routeModules
}
/* develblock:end */
/**
 * 将后台返回的动态路由配置组件字符串,转换为动态导入语句
 * 用于本地开发环境使用Vite打包的动态路由
 */
export const loadView = (view) => {
  let res;
  for (const path in route_modules) {
    // const dir = path.split('views/')[1].split('.vue')[0];
    if (path === view) {
      res = () => route_modules[path]();
    }
  }
  return res;
}
// 格式化菜单数据
export const generator = (routerMap, parent) => {
  return routerMap.map(item => {
    // eslint-disable-next-line no-unused-vars
    const { title, show, hideChildren, hiddenHeaderContent, target, icon, link } = item.meta || {}
    const menuComponent = item.component
    const currentRouter = {
      path: item.path || `${(parent && parent.path) || ''}/${item.key}`,
      // 路由名称,建议唯一
      name: item.name || item.key || '',
      // 该路由对应页面的 组件 :方案2 (动态加载)
      component: constantRouterComponents[item.component || item.key] || (route_modules ? loadView(item.component) : (() => import(`@/views/${item.component}`))),
      // meta: 页面标题, 菜单图标, 页面权限(供指令权限用,可去掉)
      meta: {
        title: title,
        icon: icon || undefined,
        // hiddenHeaderContent: hiddenHeaderContent,
        target: target,
        link: link
      }
    }
    ....

由于在Webpack编译时import.meta.glob语法无效会导致编译出错,所以引入webpack-strip-block,在Webpack编译时删除掉模块中指定注释块中的代码,避免编译错误。

//vue.config.js

  chainWebpack: config => {
    config.module.rule('strip-block')
      .test(/\.js$/)
      .pre()
      .exclude.add(/(node_modules|bower_components|\.spec\.js)/)
      .end()
      .use('webpack-strip-block')
      .loader('webpack-strip-block')
      ....
      }

~@assets处理

 <img src="~@/assets/index/refresh.svg">
 改为
  <img src="@/assets/index/refresh.svg">

诡异报错

报错1

[图片]

解决方法:
[图片]

报错2

在这里插入图片描述
解决方法:

  @import "../index";

运行

vite和vue/cli均支持,页面正常加载
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

高高i

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值