在Vue2的多页应用中应用vite2开发

1,713 阅读4分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

vite发展到现在,整个生态规模已经有了一定的基础,本来想对工作中用到的项目从vue2多页应用直接升级为vue3+ts的技术架构,但调研后发现vue3不支持Android5,着实让人头秃。还好经过调研发现vite是可以支持vue2项目的开发的,而开发环境不用考虑浏览器兼容性,于是开搞。

需要用到的vite插件:

vite-plugin-imp !项目中用到组件库往往需要,用于配置自动引入组件库的样式文件

vite-plugin-eslint !非必需,是为了方便代码格式统一引入的插件

vite-plugin-virtual-html !多页仓库需要的包,可以在保持目录不变的情况下跟用webpack开发用同样的路径。

vite-plugin-vue2 !这个是必须用的插件,是vite打包Vue2组件的工具

vite基础

vite原理相关的文章很多,我也不再把别的解释搬运过来了,可以在掘金上输入相关的关键字搜索。这里我只想强调已有的Vue2项目改造vite开发所需要注意的关键几个点:

  1. vite项目开发,整个项目中引用的外部包格式必须是esm的,如果有些库没有导出esm格式,可能要先行解决下。
  2. 使用vite开发,注意老项目里面如果有 process.env 相关的写法,要注意改一下,会报错,原因是vite的开发环境并没有对这类变量做替换,这个运行时变量替换的事情是之前webpack做的。
  3. 如果是vite开发,webpack打包的话,需要注意开发完成后尽量早的打包尝试,避免工具不一致导致预料之外的问题。

改造步骤

比如现在已经有一个vue2的仓库,是多页应用的那种,入口文件在 src/pages/**/*.html, 需要改造成vite开发,要怎么做呢?莫慌,跟着下面的步骤来:

  • 使用yarn安装 vite 和前面提到的4个vite插件
  • 在package.json中声明vite启动命令, 如: vite: "cross-env vite"
  • 在项目根目录添加 vite.config.js, 配置上四个插件的config,然后把webpack devserver 相关项迁移配置一下(如开发端口/proxy的接口等等)
  • yarn vite 愉快开发

重点说一下vite-plugin-virtual-html这个插件,这个插件的功能是通过vite server中间件做了一些事情,用于复写资源请求路径并对html文件做了预处理,核心是判断html文件里面是否有js引入的标签,如果没有则在vite开发启动前自动注入与html文件同路径下的 js|ts 文件的module引入,这里存在个问题是,我的html文件模板里面很可能有引入一些外部sdk的script语句,这样会让注入失效。

为了解决这个问题,我对插件做了点修改,判断html文件是否有script标签这里加上了对 type="module" 的限制,因为平时我们写html模板里面的引用语句肯定不会用esm的格式引入。这样一个改动之后就可以保证模板在webpack打包和vite开发上都是完全兼容的,完美~

针对环境变量 process.env.MODE 之类的环境判断变量,我这里是这么改造的:

import online from './online'
import test from './test'
import dev from './dev'

let ENV = ''
try {
  ENV = process.env.WINDOW_ENV
} catch (e) {
  ENV = 'dev'
}

const config = (() => {
  switch (ENV) {
    case 'online':
    case 'wechat_test':
      return online
    case 'test':
      return test
    case 'dev':
      return dev
    default:
      return dev
  }
})()

主要思路就是通过try...catch..来保证运行时不报错,由于vite只用于开发环境,所以在catch中就不再另行用import.meta 下的变量进行判断了。

听起来很简单是不是,不过第三步其实远没有描述的这么简单,我下面准备简单贴一下配置(业务相关的已隐藏),并对一些关键配置写注释解释一下,每一项配置都是踩坑踩过来。

vite配置详解

// vite.config.js
import path from 'path'
import glob from 'glob'

import { defineConfig } from 'vite'
import { createVuePlugin } from 'vite-plugin-vue2'
import vitePluginImp from 'vite-plugin-imp'
import eslintPlugin from 'vite-plugin-eslint';
import virtualHtml from './buildPlugin/vite-plugin-virtual-html'

// 常量配置
const VITE_APP_PORT = 3000
const VITE_APP_HOST = 'localhost'
const VITE_APP_PATH = './'
const TEMPLATE_PATH = './src/pages/**/*.html'

// 生成多页page入口配置
function getHtmls() {
  const entries = {}
  glob.sync(TEMPLATE_PATH).forEach(function(entry) {
    const basename = path.basename(entry, path.extname(entry))
    entries[basename] = entry.slice(1) // 相对路径改成绝对路径
  })
  return entries
}

const plugins = [
    createVuePlugin(/* options */),
    virtualHtml({
        pages: getHtmls(),
        indexPage: 'index'
    }),
    vitePluginImp(
        [{
          libName: 'vant',
          style(name) {
            if (/CompWithoutStyleFile/i.test(name)) {
              // This will not import any style file 
              return false
            }
            return `vant/es/${name}/style/index.js`
          }
        }
     ]),
     eslintPlugin({ include: '**/*.+(vue|js|jsx|ts|tsx)' }),
     // 如果校验css的话,会有很多奇怪的报错
 ]

export default defineConfig({
  base: VITE_APP_PATH
  plugins,
  server: {
    port: VITE_APP_PORT,
    host: VITE_APP_HOST,
    open: '/index.html',
    cors: true,
    proxy: {
      '^/.*api/.*': {
        target: '', //根据自己业务填写
        changeOrigin: true,
        secure: false
      }
    }
  },
  resolve: {
      // 类型: string[]
      // 默认: ['.mjs', '.js', '.ts', '.jsx', '.tsx', '.json']
      // 导入时想要省略的扩展名列表。如果之前import语句对于vue类型文件没带上.vue 则需要加上'.vue'
      extensions: ['.js', '.vue', '.json'],
      alias: {
        '@': resolve('src'),
        vue$: 'vue/dist/vue.esm.js'
      }
  }
})

后续工作与展望

  • 项目添加引入 @vue/composition-api 推行类Vue3的开发体验
  • 借用vite,尝试使用rollup进行打包处理,从而完全避开Webpack的配置,也使得项目中针对环境的判断统一化