美文网首页
真香!vue-cli-service项目升级vite

真香!vue-cli-service项目升级vite

作者: 月上秦少 | 来源:发表于2023-01-09 17:15 被阅读0次
    095afad2-2fff-4dc5-88bb-9366d8abcf01.png

    原文:真香!vue-cli-service项目升级vite

    1、项目概览

    image image image

    admin-web管理后台是我们业务的管理中心,开发、运营、产品等工作人员会频繁使用,是我们目前业务的核心配置中心,这个项目从建立之初一直更新迭代,迄今为止有655次commits,681
    次CI,可见更新次数还是很频繁的。随着日积月累,代码量越来越多,vue单页面已经有了100+ pages,30+ vuecomponents,因此启动速度越来越慢。

    2、vue-cli-service和vite启动速度对比

    将vue-cli-service升级切换到vite之后启动速度得到了巨幅提升,下面是对比结果:

    1.使用vue-cli-service serve启动:

    • 平均耗时:15s

    • 最大耗时:40s

    • 最小耗时:10s

    image

    2.使用vite启动:

    • 平均耗时:2s

    • 最大耗时:5s

    • 最小耗时:1s

    image

    可见启动速度提升差不多10倍,平均每次启动节省约13s。

    下面介绍项目改造过程:

    3、项目概览

    1、目录结构

    改造前的目录结构,使用tree -aL 3 -I "node_modules" > tree.txt输出:

    .
    ├── .editorconfig
    ├── .env.development
    ├── .env.production
    ├── .env.staging
    ├── .eslintignore
    ├── .eslintrc.js
    ├── .git
    ├── .gitignore
    ├── .gitlab-ci.yml
    ├── .idea
    ├── .travis.yml
    ├── Dockerfile.prod
    ├── Dockerfile.test
    ├── LICENSE
    ├── README.md
    ├── babel.config.js
    ├── build
    ├── dist
    ├── docker-compose.yml
    ├── jest.config.js
    ├── jsconfig.json
    ├── mock
    ├── nginx.conf
    ├── package.json
    ├── plopfile.js
    ├── postcss.config.js
    ├── public
    │     ├── favicon.ico
    │     └── index.html
    ├── scripts
    │     └── notify.sh
    ├── src
    │     ├── App.vue
    │     ├── api
    │     │   ├── activity.js
    │     │   ├── config.js
    │...      ...
    │     ├── assets
    │     ├── components
    │     │   └── VideoPlay
    │     ├── directive
    │     ├── clipboard
    │     ├── el-drag-dialog
    │     ├── permission
    │     ├── filters
    │     ├── icons
    │     │     ├── index.js
    │     │     ├── svgo.yml
    │           │           └── svg # 多个svg图标
    │     │             ├── 404.svg
    │...                    ...
    │     │                     └── zip.svg
    │     ├── layout
    │     ├── main.js
    │     ├── permission.js
    │     ├── router
    │     │     ├── activity.js
    │     │     ├── config.js
    │...         ...
    │     ├── settings.js
    │     ├── store
    │     │     ├── getters.js
    │     │     ├── index.js
    │           │           └── modules # 多个store
    │     │             ├── app.js
    │...                    ...
    │     │                     └── user.js
    │     ├── store
    │     ├── styles
    │     ├── utils
    │     └── views
    │           ├── activity
    │...         ...
    │           └── withdrawal
    ├── vue.config.js
    └── yarn.lock
    

    使用vite改造后的目录:

    .
    ├── .editorconfig
    ├── .env.development
    ├── .env.production
    ├── .env.staging
    ├── .eslintignore
    ├── .eslintrc.js
    ├── .git
    ├── .gitignore
    ├── .gitlab-ci.yml
    ├── .idea
    ├── .travis.yml
    ├── Dockerfile.prod
    ├── Dockerfile.test
    ├── LICENSE
    ├── README.md
    ├── babel.config.js
    ├── build
    ├── dist
    ├── docker-compose.yml
    ├── index.html  # 新增
    ├── jest.config.js
    ├── jsconfig.json
    ├── mock
    ├── nginx.conf
    ├── package.json
    ├── plopfile.js
    ├── postcss.config.js
    ├── public
    │     ├── favicon.ico
    │     └── index.html
    ├── scripts
    │     └── notify.sh
    ├── src
    │     ├── App.vue
    │     ├── api
    │     │   ├── activity.js
    │     │   ├── config.js
    │...      ...
    │     ├── assets
    │     ├── components
    │     │   └── VideoPlay
    │     ├── directive
    │     ├── clipboard
    │     ├── el-drag-dialog
    │     ├── permission
    │     ├── filters
    │     ├── icons
    │     │     ├── index.js
    │     │     ├── svgo.yml
    │           │           └── svg # 多个svg图标
    │     │             ├── 404.svg
    │...                    ...
    │     │                     └── zip.svg
    │     ├── layout
    │     ├── main.js
    │     ├── permission.js
    │     ├── router
    │     │     ├── activity.js
    │     │     ├── config.js
    │...         ...
    │     ├── settings.js
    │     ├── store
    │     │     ├── getters.js
    │     │     ├── index.js
    │           │           └── modules # 多个store
    │     │             ├── app.js
    │...                    ...
    │     │                     └── user.js
    │     ├── styles
    │     ├── utils
    │     └── views
    │           ├── activity
    │...         ...
    │           └── withdrawal
    ├── vite.config.js # 新增
    ├── vue.config.js
    └── yarn.lock
    

    新增了两个文件:vite.config.js和 index.html

    2、node package包

    改造前:package.json

    {
      "name": "admin-web",
      "version": "1.0.0",
      "description": "管理后台系统",
      "scripts": {
        "dev": "vue-cli-service serve",
        "lint": "eslint --ext .js,.vue src",
        "build:prod": "vue-cli-service build",
        "build:stage": "vue-cli-service build --mode staging",
        "preview": "node build/index.js --preview",
        "new": "plop",
        "svgo": "svgo -f src/icons/svg --config=src/icons/svgo.yml",
        "test:unit": "jest --clearCache && vue-cli-service test:unit",
        "test:ci": "npm run lint && npm run test:unit"
      },
      "dependencies": {
        "axios": "0.18.1",
        "clipboard": "2.0.4",
        "codemirror": "5.45.0",
        "core-js": "^3.6.5",
        "driver.js": "0.9.5",
        "dropzone": "5.5.1",
        "echarts": "4.2.1",
        "element-ui": "^2.15.7",
        "file-saver": "2.0.1",
        "fuse.js": "3.4.4",
        "js-cookie": "2.2.0",
        "jszip": "3.2.1",
        "md5": "2.2.1",
        "normalize.css": "7.0.0",
        "nprogress": "0.2.0",
        "path-to-regexp": "2.4.0",
        "screenfull": "4.2.0",
        "script-loader": "0.7.2",
        "sortablejs": "1.8.4",
        "tui-editor": "1.3.3",
        "v-viewer": "^1.6.4",
        "video.js": "^7.18.1", # 删除,使用cdn
        "videojs-contrib-hls": "^5.15.0",  # 删除,使用@videojs/http-streaming cdn代替
        "vue": "2.6.10",
        "vue-count-to": "1.0.13",
        "vue-router": "3.0.2",
        "vue-splitpane": "1.0.4",
        "vuedraggable": "2.20.0",
        "vuex": "3.1.0",
        "xlsx": "0.14.1"
      },
      "devDependencies": {
        "@vue/cli-plugin-babel": "4.4.4",
        "@vue/cli-plugin-eslint": "4.4.4",
        "@vue/cli-plugin-unit-jest": "4.4.4",
        "@vue/cli-service": "4.4.4",
        "@vue/test-utils": "1.0.0-beta.29",
        "autoprefixer": "9.5.1",
        "babel-eslint": "10.1.0",
        "babel-jest": "23.6.0",
        "babel-plugin-dynamic-import-node": "2.3.3",
        "chalk": "2.4.2",
        "chokidar": "2.1.5",
        "connect": "3.6.6",
        "eslint": "6.7.2",
        "eslint-plugin-vue": "6.2.2",
        "html-webpack-plugin": "3.2.0",
        "husky": "1.3.1",
        "lint-staged": "8.1.5",
        "mockjs": "1.0.1-beta3",
        "plop": "2.3.0",
        "runjs": "4.3.2",
        "sass": "1.33.0",
        "sass-loader": "8.0.2",
        "script-ext-html-webpack-plugin": "2.1.3",
        "serve-static": "1.13.2",
        "svg-sprite-loader": "4.1.3",
        "svgo": "1.2.0",
        "vue-template-compiler": "2.6.10"
      },
      "browserslist": [
        "> 1%",
        "last 2 versions"
      ],
      "engines": {
        "node": ">=8.9",
        "npm": ">= 3.0.0"
      },
      "lint-staged": {
        "src/**/*.{js,vue}": [
          "eslint --fix",
          "git add"
        ]
      },
      "husky": {
        "hooks": {
          "pre-commit": "lint-staged"
        }
      }
    }
    

    改造后:(针对vue2项目使用vite2.x版本

    {
      "name": "admin-web",
      "version": "2.0.0",
      "description": "管理后台系统",
      "scripts": {
        "dev": "vue-cli-service serve",
        "lint": "eslint --ext .js,.vue src",
        "lint:fix": "eslint --ext .js,.vue src --fix",
        "build:prod": "vue-cli-service build",
        "build:stage": "vue-cli-service build --mode staging",
        "preview": "node build/index.js --preview",
        "new": "plop",
        "svgo": "svgo -f src/icons/svg --config=src/icons/svgo.yml",
        "test:unit": "jest --clearCache && vue-cli-service test:unit",
        "test:ci": "npm run lint && npm run test:unit",
        "dev-vite": "vite", # 新增
        "build-vite": "vite build",  # 新增
        "preview-vite": "vite preview"  # 新增
      },
      "dependencies": {
        "axios": "0.18.1",
        "clipboard": "2.0.4",
        "codemirror": "5.45.0",
        "core-js": "^3.6.5",
        "driver.js": "0.9.5",
        "dropzone": "5.5.1",
        "echarts": "4.2.1",
        "element-ui": "^2.15.7",
        "file-saver": "2.0.1",
        "fuse.js": "3.4.4",
        "js-cookie": "2.2.0",
        "jszip": "3.2.1",
        "md5": "2.2.1",
        "normalize.css": "7.0.0",
        "nprogress": "0.2.0",
        "path-browserify": "^1.0.1",
        "path-to-regexp": "2.4.0",
        "screenfull": "4.2.0",
        "script-loader": "0.7.2",
        "sortablejs": "1.8.4",
        "tui-editor": "1.3.3",
        "v-viewer": "^1.6.4",
        "vue": "2.6.10",
        "vue-count-to": "1.0.13",
        "vue-router": "3.0.2",
        "vue-splitpane": "1.0.4",
        "vuedraggable": "2.20.0",
        "vuex": "3.1.0",
        "xlsx": "0.14.1"
      },
      "devDependencies": {
        "@babel/plugin-syntax-jsx": "^7.18.6", # 新增
        "@originjs/vite-plugin-require-context": "^1.0.9", # 新增
        "@vue/babel-helper-vue-jsx-merge-props": "^1.4.0", # 新增
        "@vue/babel-preset-jsx": "^1.4.0", # 新增
        "@vue/cli-plugin-babel": "4.4.4",
        "@vue/cli-plugin-eslint": "4.4.4",
        "@vue/cli-plugin-unit-jest": "4.4.4",
        "@vue/cli-service": "4.4.4",
        "@vue/test-utils": "1.0.0-beta.29",
        "autoprefixer": "9.5.1",
        "babel-eslint": "10.1.0",
        "babel-jest": "23.6.0",
        "babel-plugin-dynamic-import-node": "2.3.3",
        "chalk": "2.4.2",
        "chokidar": "2.1.5",
        "connect": "3.6.6",
        "eslint": "6.7.2",
        "eslint-plugin-vue": "6.2.2",
        "html-webpack-plugin": "3.2.0",
        "husky": "1.3.1",
        "lint-staged": "8.1.5",
        "mockjs": "1.0.1-beta3",
        "plop": "2.3.0",
        "progress-bar-webpack-plugin": "^2.1.0", # 新增(可忽略),查看vue-cli-service构建速度
        "runjs": "4.3.2",
        "sass": "1.33.0",
        "sass-loader": "8.0.2",
        "script-ext-html-webpack-plugin": "2.1.3",
        "serve-static": "1.13.2",
        "svg-sprite-loader": "4.1.3",
        "svgo": "1.2.0",
        "vite": "^2.9.15", # 新增
        "vite-plugin-commonjs": "^0.6.1", # 新增
        "vite-plugin-components": "^0.13.2", # 新增
        "vite-plugin-env-compatible": "^1.1.1", # 新增
        "vite-plugin-optimize-persist": "^0.1.2", # 新增
        "vite-plugin-package-config": "^0.1.1", # 新增
        "vite-plugin-svg-icons": "^2.0.1", # 新增
        "vite-plugin-vue2": "^2.0.3", # 新增
        "vue-template-compiler": "2.6.10"
      },
      "browserslist": [
        "> 1%",
        "last 2 versions"
      ],
      "bugs": {
        "url": "https://github.com/PanJiaChen/vue-element-admin/issues"
      },
      "engines": {
        "node": ">=8.9",
        "npm": ">= 3.0.0"
      },
      "lint-staged": {
        "src/**/*.{js,vue}": [
          "eslint --fix",
          "git add"
        ]
      },
      "husky": {
        "hooks": {
          "pre-commit": "lint-staged"
        }
      }
    }
    

    3、入口文件index.html

    1. 位置变换:

    root/public/index.htmlroot/index.html

    1. 内容变化:

    改造前:

    <!DOCTYPE html>
    <html>
    <head>
      <meta charset="utf-8">
      <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
      <meta name="renderer" content="webkit">
      <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
      <link rel="icon" href="<%= BASE_URL %>favicon.ico">
      <title><%= webpackConfig.name %></title>
    </head>
    <body>
    <div id="app"></div>
    <!-- built files will be auto injected -->
    </body>
    </html>
    

    改造后:

    <!DOCTYPE html>
    <html>
    <head>
      <meta charset="utf-8">
      <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
      <meta name="renderer" content="webkit">
      <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
      <link rel="icon" href="/favicon.ico"/>
      <link href="https://unpkg.com/video.js/dist/video-js.css" rel="stylesheet">
      <title>melon admin</title>
    </head>
    <body>
    <div id="app"></div>
    <!-- built files will be auto injected -->
    <script type="module" src="/src/main.js"></script>
    <script src="https://unpkg.com/video.js/dist/video.js"></script>
    <script src="https://unpkg.com/@videojs/http-streaming/dist/videojs-http-streaming.js"></script>
    </body>
    </html>
    

    4.新增vite配置文件

    vite.config.js

    import {defineConfig} from 'vite'
    import commonjs from 'vite-plugin-commonjs'
    import ViteRequireContext from '@originjs/vite-plugin-require-context'
    import viteComponents, {
      VuetifyResolver
    } from 'vite-plugin-components'
    import envCompatible from 'vite-plugin-env-compatible'
    import OptimizationPersist from 'vite-plugin-optimize-persist'
    import PkgConfig from 'vite-plugin-package-config'
    import {createSvgIconsPlugin} from 'vite-plugin-svg-icons'
    import {createVuePlugin} from 'vite-plugin-vue2'
    
    import path from 'path'
    
    // const { createVuePlugin } = require('vite-plugin-vue2')
    // const path = require('path')
    const REPLACEMENT = `${path.resolve(__dirname, './src')}/`
    export default defineConfig({
        server: {
          host: '0.0.0.0',
          https: false,
          port: 8088,
          proxy: {
            '/melon.admin.s': {
              // 路径中有 /api 的请求都会走这个代理 , 可以自己定义一个,下面移除即可
              target: 'https://xxx.xxx.com', // 目标代理接口地址,实际跨域要访问的接口,这个地址会替换掉 axios.defaults.baseURL
              // target: 'http://localhost:9000', // 目标代理接口地址,实际跨域要访问的接口,这个地址会替换掉 axios.defaults.baseURL
              secure: false,
              changeOrigin: true, // 开启代理,在本地创建一个虚拟服务端
              ws: true //,       // 是否启用  websockets;
            }
          }
        },
        resolve: {
          alias: [
            {
              find: '@/',
              replacement: REPLACEMENT
            },
            {
              find: 'src/',
              replacement: REPLACEMENT
            },
            {
              find: /^~@\//,
              replacement: REPLACEMENT
            }
          ],
          extensions: ['.vue', '.js', '.jsx', '.mjs', '.ts', '.tsx', '.json', '.css', '.scss']
        },
        plugins: [
          createVuePlugin({jsx: true}),
          viteComponents({
            customComponentResolvers: [
              VuetifyResolver()
            ]
          }),
          createSvgIconsPlugin({
            iconDirs: [path.resolve(__dirname, './src/icons/svg')],
            symbolId: 'icon-[dir]-[name]'
          }),
          commonjs(/* options */),
          ViteRequireContext(/* options */),
          envCompatible(),
          PkgConfig(),
          OptimizationPersist()
        ]
      }
    )
    

    至于为什么要这样配置,当然是一步步踩坑,填坑至此,说多了都是泪啊

    5、切换vite问题汇总

    1.页面显示:找不到此 localhost 页面

    需要把index.html从public文件夹移动到root目录下

    2.'URI malformed'报错,标题显示<%= webpackConfig.name %>

    <!DOCTYPE html>
    <html>
    <head>
      <meta charset="utf-8">
      <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
      <meta name="renderer" content="webkit">
      <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
      <link rel="icon" href="<%= BASE_URL %>favicon.ico">
      <link href="https://unpkg.com/video.js/dist/video-js.css" rel="stylesheet">
      <title><%= webpackConfig.name %></title>
    </head>
    <body>
    <div id="app"></div>
    <!-- built files will be auto injected -->
    </body>
    </html>
    

    需要切换路径,<%= webpackConfig.name %>和<%= BASE_URL %>webpack能识别,vite识别不了,修改如下:

    <!DOCTYPE html>
    <html>
    <head>
      <meta charset="utf-8">
      <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
      <meta name="renderer" content="webkit">
      <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
      <!--    public下的文件使用路径即可-->
      <link rel="icon" href="/favicon.ico"/>
      <!--    标题直接配置在儿-->
      <title>admin web</title>
    </head>
    <body>
    <div id="app"></div>
    <!-- built files will be auto injected -->
    </body>
    </html>
    

    3.访问成功,单页面空白,控制台无任何信息

    vite以esm的形式加载js文件,需要手动引入一下。

    <!DOCTYPE html>
    <html>
    <head>
      <meta charset="utf-8">
      <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
      <meta name="renderer" content="webkit">
      <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
      <!--    public下的文件使用路径即可-->
      <link rel="icon" href="/favicon.ico"/>
      <link href="https://unpkg.com/video.js/dist/video-js.css" rel="stylesheet">
      <!--    标题直接配置在儿-->
      <title>melon admin</title>
    </head>
    <body>
    <div id="app"></div>
    <!-- built files will be auto injected -->
    <!--    以module的模式加载main.js-->
    <script type="module" src="/src/main.js"></script>
    </body>
    </html>
    

    如果继续空白,先把报错的代码注释掉,面向谷歌编程,一个个解决就完事了

    4.vite无法识别alias路径

    [plugin:vite:import-analysis] Failed to resolve import "@/styles/index.scss" from "src\main.js". Does the file exist?
    

    加载alias文件路径失败,需要配置alias,vite才能识别

    import {defineConfig} from 'vite'
    
    import path from 'path'
    
    const REPLACEMENT = `${path.resolve(__dirname, './src')}/`
    export default defineConfig({
      resolve: {
        alias: [
          {
            find: '@/',
            replacement: REPLACEMENT
          }
        ]
      }
    })
    
    

    5.vite无法自动查询文件后缀名,文件Not Found

    GET http://localhost:8089/src/layout net::ERR_ABORTED 404 (Not Found)
    
    import Layout from '/src/layout
    

    直接导入某个目录下的index.js、index.css、index.json时可以省略具体的文件名,让webpack自动查找,vite无法识别,需要配置****extensions:

    import {defineConfig} from 'vite'
    
    import path from 'path'
    
    const REPLACEMENT = `${path.resolve(__dirname, './src')}/`
    export default defineConfig({
      resolve: {
        alias: [
          {
            find: '@/',
            replacement: REPLACEMENT
          }
        ],
        extensions: ['.vue', '.js', '.jsx', '.mjs', '.ts', '.tsx', '.json', '.css', '.scss']
      }
    })
    
    

    6.vite识别不了 jsx, Uncaught ReferenceError: React is not defined

    需要配置jsx插件:

    import {defineConfig} from 'vite'
    import {createVuePlugin} from 'vite-plugin-vue2'
    
    export default defineConfig({
      plugins: [
        createVuePlugin({jsx: true}),
      ]
    })
    
    

    7.jsx语法未注明:[plugin:vite-plugin-commonjs] Unexpected token

    if (icon) {
    19 |        if (icon.includes('el-icon')) {
    20 |          vnodes.push(<i class={[icon, 'sub-el-icon']} />)
       |                      ^
    21 |        } else {
    22 |          vnodes.push(<svg-icon icon-class={icon}/>)}
    

    <script>标签下的js中包含jsx的语法需要注明:<script lang="jsx">

    9.vite无法识别require: Uncaught ReferenceError: require is not defined

    commonjs使用require来加载js,vite直接加载esm,vite无法识别require,解决方式有二:

    1. 把commonjs的require方式改为esm的import方式

    2. 使用插件使vite支持require:

    import {defineConfig} from 'vite'
    import commonjs from 'vite-plugin-commonjs'
    
    export default defineConfig({
      plugins: [
        createVuePlugin({jsx: true}),
        commonjs(/* options */),
        // ...  ...
      ]
    })
    
    

    当然****module.exports****定义的js文件强烈建议修改为****export default****拥抱ESM吧

    8.动态加载require无法识别:Uncaught ReferenceError: require is not defined at index.js:8:22

    1.store/index.js

    import Vue from 'vue'
    import Vuex from 'vuex'
    import getters from './getters'
    
    Vue.use(Vuex)
    
    // https://webpack.js.org/guides/dependency-management/#requirecontext
    const modulesFiles = require.context('./modules', true, /\.js$/)
    
    // you do not need `import app from './modules/app'`
    // it will auto require all vuex module from modules file
    const modules = modulesFiles.keys().reduce((modules, modulePath) => {
      // set './app.js' => 'app'
      const moduleName = modulePath.replace(/^\.\/(.*)\.\w+$/, '$1')
      const value = modulesFiles(modulePath)
      modules[moduleName] = value.default
      return modules
    }, {})
    
    const store = new Vuex.Store({
      modules,
      getters
    })
    
    export default store
    

    这里使用了webpack的requirecontext来读取store/modules目录下的多个store,否则需要一行行手动引入。

    2.icons/index.js

    import Vue from 'vue'
    import SvgIcon from '@/components/SvgIcon'// svg component
    
    // register globally
    Vue.component('svg-icon', SvgIcon)
    
    const req = require.context('./svg', false, /\.svg$/)
    const requireAll = requireContext => requireContext.keys().map(requireContext)
    requireAll(req)
    

    这里使用了webpack的requirecontext来读取icons/svg目录下的多个icon,否则需要一行行手动引入。

    1.解决方式一:require.context相关代码删除,然后手动一个个引入import testIcon from "./svg/test.svg",但是太过于繁琐,增加好多代码量。

    2.解决方式二:使用vite插件@originjs/vite-plugin-require-context,让vite可以使用识别require.context

    import {defineConfig} from 'vite'
    import ViteRequireContext from '@originjs/vite-plugin-require-context'
    
    export default defineConfig({
      plugins: [
        createVuePlugin({jsx: true}),
        ViteRequireContext(/* options */)
        // ...  ...
      ]
    })
    

    9.svgo图标无法显示

    切换vite前,正常显示:

    image

    使用vite后图标不见了:

    image

    这里是我解决requirerequire.context之后正常加载时的页面,这个两个问题如果没有解决的话,页面是直接进入不了的。所以前提是把这两个问题解决了才行。

    打开控制台发现js并没有报错,只是svg没有成功显示的问题。

    
    <div data-v-4441ce11="">
      <div data-v-4441ce11="" class="el-tooltip icon-item" aria-describedby="el-tooltip-8235" tabindex="0">
        <svg data-v-c8a70580="" data-v-4441ce11="" aria-hidden="true" class="svg-icon disabled">
          <use data-v-c8a70580="" xlink:href="#icon-404"></use>
        </svg>
        <span data-v-4441ce11="">404</span>
      </div>
    </div>
    

    可以看到这里使用了svg<use> - SVG: Scalable Vector Graphics | MDN (mozilla.org)

    搜索svg:use vite,找到解决方案在vite中使用svg(vue) - 掘金 (juejin.cn)

    借助vite插件vite-plugin-svg-icons使vite可以完美支持svg:use:

    import {defineConfig} from 'vite'
    import {createSvgIconsPlugin} from 'vite-plugin-svg-icons'
    
    export default defineConfig({
        plugins: [
          createVuePlugin({jsx: true}),
          createSvgIconsPlugin({
            iconDirs: [path.resolve(__dirname, './src/icons/svg')],
            symbolId: 'icon-[dir]-[name]'
          }),
          // ...    ...
        ]
      }
    )
    

    10.vite无法识别scss变量导入

    报错error和代码:

        [plugin:vite:import-analysis] Cannot read properties of undefined (reading 'url')
        D:/work/gitlab/admin-web/src/styles/element-variables.scss
        
        import variables from '@/styles/element-variables.scss'
        @import "~element-ui/packages/theme-chalk/src/index";
    

    这里需要修改为*.module.scss功能 | Vite 官方中文文档 (vitejs.dev)

    其实在解决这个问题之前,页面的主题配置还有一些和变量相关的样式都是混乱的,修复这个问题之后瞬间一片清明!!!

    11.videojs报错导致Maximum call stack size exceeded

    1.使用vite之后videojs-contrib-hls(用来播放m3u8视频的videojs插件)报错:

    image

    2.注释掉videojs-contrib-hls,只要打开引入了videojs组件的页面就卡住了:

    image

    3.然后我尝试使用CDN的方式引入,视频可以成功播放了,但是还是有error

    image

    index.html增加cdn

    <!DOCTYPE html>
    <html>
    <head>
      <meta charset="utf-8">
      <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
      <meta name="renderer" content="webkit">
      <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
      <link rel="icon" href="/favicon.ico"/>
      <!-- 新增 -->
      <link href="https://cdnjs.cloudflare.com/ajax/libs/video.js/7.21.1/alt/video-js-cdn.min.css" rel="stylesheet"/>
      <title>melon admin</title>
    </head>
    <body>
    <div id="app"></div>
    <!-- built files will be auto injected -->
    <script type="module" src="/src/main.js"></script>
    <!-- 新增 -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/video.js/7.21.1/video.min.js"></script>
    <!-- 新增 -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/videojs-contrib-hls/5.15.0/videojs-contrib-hls.min.js"></script>
    </body>
    </html>
    

    VideoPlay.vue

    
    <template>
      <div>
        <div class="VideoPlay">
          <video
              :id="`video-${videoId}`"
              ref="videoRef"
              class="video-js vjs-default-skin vjs-big-play-centered"
              muted
              plays-inline
              controls
              preload="auto"
              height="400px"
              width="100%"
          />
        </div>
      </div>
    </template>
    
    <script>
    // 注释掉videojs npm导入
    // import videojs from 'video.js'
    // import 'video.js/dist/video-js.css'
    // import 'videojs-contrib-hls'
    
    const config = {
      bigPlayButton: true,
      textTrackDisplay: false,
      posterImage: true,
      errorDisplay: false,
      controlBar: {
        currentTimeDisplay: true, // 当前时间
        timeDivider: true, // 时间分割线
        durationDisplay: true, // 总时间
        progressControl: true, // 进度条
        remainingTimeDisplay: {
          displayNegative: true
        }, //
        fullscreenToggle: true // 全屏按钮
      },
      playbackRates: [0.8, 1, 1.25, 1.5, 2],
      html5: {
        vhs: {
          withCredentials: false
        }
      }
    }
    
    export default {
      name: 'VideoPlay',
      props: {
        videoId: {
          default: Math.random().toString().slice(2, 6),
          type: [String, Number]
        },
        videoSrc: {
          default: '',
          type: String
        }
      },
      data() {
        return {
          videoPlayerInstance: null,
        }
      },
      mounted() {
        try {
          this.videoSrc && this.getVideoPlayInstance()
        } catch (e) {
          console.error('init video')
        }
      },
      destroyed() {
        try {
          this.videoPlayerInstance && this.videoPlayerInstance.dispose()
        } catch (e) {
          console.error('destroyed video', e)
        }
      },
      methods: {
        setVideo(id, source) {
          try {
            config.sources = [{
              type: 'application/x-mpegURL',
              src: source
            }]
            // const instance = videojs(
            // 使用全局window.videojs
            const instance = window.videojs(
                id,
                config,
                () => {
                  instance.play()
                })
            return instance
          } catch (e) {
            console.error('setVideo', e)
          }
        },
        getVideoPlayInstance() {
          if (!this.videoPlayerInstance) {
            this.videoPlayerInstance = this.setVideo(`video-${this.videoId}`, this.videoSrc)
          }
        }
      }
    }
    </script>
    
    <style lang="scss" scoped>
    .VideoPlay {
      width: 100%;
      height: 500px;
    
      .video-js {
        width: 100%;
        height: 100%;
      }
    }
    
    .audioPlay {
      width: 100%;
      height: 30px;
    
      .video-js {
        width: 100%;
        height: 100%;
        background: transparent;
      }
    }
    </style>
    

    4.解决第3步的报错,切换了其他版本还是有这个错误,于是打算把videojs-contrib-hls源码clone一份看看报错的地方能不能修改下源码,发现README.md

    image

    Video.js Blog | Video.js (videojs.com)博客显示videojs7使用videojs/http-streaming插件来替代videojs-contrib-hls

    videojs/http-streaming: HLS, DASH, and future HTTP streaming protocols library for video.js

    刚巧项目中的videojs也是7.x版本,于是我切换了videojs/http-streamingCDN,看了官方DEMO,需要把标签video替换为video-js,成功解决error,但是多了一个warning,
    问题不大

    image

    这个就先忍了吧_

    image

    最终的index.html

    <!DOCTYPE html>
    <html>
    <head>
      <meta charset="utf-8">
      <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
      <meta name="renderer" content="webkit">
      <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
      <link rel="icon" href="/favicon.ico"/>
      <link href="https://unpkg.com/video.js/dist/video-js.css" rel="stylesheet">
      <title>melon admin</title>
    </head>
    <body>
    <div id="app"></div>
    <!-- built files will be auto injected -->
    <script type="module" src="/src/main.js"></script>
    <script src="https://unpkg.com/video.js/dist/video.js"></script>
    <script src="https://unpkg.com/@videojs/http-streaming/dist/videojs-http-streaming.js"></script>
    </body>
    </html>
    

    在解决这个问题之前,我内心是崩溃的,找了诸多方式都无法解决,就差一点儿就放弃了,行百里者半九十,我坚持找解决方案,最终终于成功了,点个赞!

    为了渐进升级,目前保留`vue-cli-service`和`vite`共存,两者都可以使用,后续可以把`vue-cli-service`相关的依赖和代码删除即可

    6.参考文档

    相关文章

      网友评论

          本文标题:真香!vue-cli-service项目升级vite

          本文链接:https://www.haomeiwen.com/subject/jnzpcdtx.html