vite+vue3+ts+vant搭建项目

3,942 阅读4分钟

背景

最近在做公司项目的技术栈迁移, 基于老项目的技术栈是vue2,因此新的技术栈采用vue3+vant的模式。 并且新增ts+eslint的配置提高项目的可维护性, 项目打包工具在正式环境打包依旧采用webpack,而开发环境存在两种打包模式vite和webpack 。vite基于浏览器ES Moudle,有打包快,体积小等优势,利于项目进行快速开发。但是由于vite本身暂时不推荐用于生产环境且生产环境需要更高的维稳性,因此开发和生产都共建一套webpack打包方式,方便日常问题的排查。本文只记录大概的开发框架以及打包配置,仅供参考。

项目结构

image.png

基础配置

在明确好技术栈之后,先搭建vu3+webpack+ts+babel的环境配置。介于老项目有用到Node修改静态页面的值,因此不考虑vue-cli的脚手架。yarn init初始化页面,再安装vue3+babel7+typescript等依赖项。此处不做详细赘述,主要注意以下几点:

  1. babel.config.js文件需要对vant框架需做额外插件处理
plugins: [ 
    [ 
        'import', 
        { 
            libraryName: 'vant', 
            libraryDirectory: 'es', 
            style: true 
        }, 
        'vant' 
    ]
]
  1. ts配置时需要去除掉node_modules, 避免对依赖项进行校验,额外增加项目编译时间
"exclude": ["node_modules"]
  1. 项目引用路径的简写除了在webpack文件中需要配置,tsconfig.json也需要额外配置
// webpack.base.js 
"alias": { 
    // 用@直接指引到src目录下 
    '@': path.resolve(__dirname, '../src'), 
    '@libs': path.resolve(__dirname, '../src/libs'), 
    '@cp': path.resolve(__dirname, '../src/components'), 
    "@store": path.resolve(__dirname, '../src/store'), 
} 
//tsconfig.json 
    "paths": { 
        "@/*": ["src/*"], 
        "@libs/*": ["src/libs/*"], 
        "@cp/*": ["src/components/*"], 
        "@store/*": ["src/store/*"], 
        "@store": ["src/store"] 
    },

vite配置

1.安装vite等项目依赖
yarn add vite @vitejs/plugin-vue vite-plugin-style-import

2.安装less处理样式,配置vite编译方式

// vite.config.js
import { defineConfig } from 'vite' 
import vue from '@vitejs/plugin-vue' 
import styleImport from 'vite-plugin-style-import' 
import path from 'path' 
export default defineConfig({ 
    plugins: [ 
        vue(), 
        styleImport({ 
            // 处理vant框架的引入 
            libs: [ { 
                libraryName: 'vant', 
                esModule: true, 
                resolveStyle: name => { return `vant/es/${name}/style` } 
            } ] 
        }) 
    ], 
    // 路径别名 
    resolve: { 
        alias: { 
            '@': path.resolve(__dirname, './src'), 
            '@libs': path.resolve(__dirname, './src/libs'), 
            '@cp': path.resolve(__dirname, './src/components'), 
            '@store': path.resolve(__dirname, './src/store') 
        } 
    }, 
    css: { 
        preprocessorOptions: { 
            less: {
                modifyVars: { 
                    hack: `true; @import (reference) "${path.resolve( __dirname, './src/styles/global.less' )}";` 
                }, 
                javascriptEnabled: true // 支持less嵌入js文件 
            } 
        } 
    }, 
    server: { 
        port: 9999, // 端口号 
        open: true, // 是否自动在浏览器打开 
        https: false, // 是否开启 https 
    } 
})

以下几点同样也需要注意:
1. 和webpack类似,路径别名需要额外在vite.config.js配置
2. vite没有内置Less或者Sass的编译依赖,需要额外安装和配置
3. @vitejs/plugin-vue只针对vue3 如果需要对Vue2支持则需要安装vite-plugin-vue2,具体请参考vite-plugin-vue2

vite-ssr服务配置

由于老项目基于node向静态页面注入参数,因此额外配置ssr服务。在build文件中新建viteServer.js 配置vite服务端内容以及根据已有的index.html文件配置新的入口文件
启动命令node build/viteServer.js

入口配置
// vite.html
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <meta name="apple-mobile-web-app-capable" content="yes" />
    <!--需要额外注入的内容-->
    <!--preload-links-->
  </head>

  <body>
    <div id="app"></div>
    <script type="module" src="/src/vite/entry-client.js"></script>
  </body>
</html>
vue渲染方式更改
import { createSSRApp } from 'vue' 
import App from '../App.vue' 
import store from '@store/index' 

export function createApp() { 
    const app = createSSRApp(App) 
    return { app, store } 
}
vite-ssr配置
const fs = require('fs')
const express = require('express')
const path = require('path') 
const { createServer: createViteServer } = require('vite')
async function createServer() { 
    const app = express() 
    // 以中间件模式创建 vite 应用,这将禁用 Vite 自身的 HTML 服务逻辑 
    // 并让上级服务器接管控制 
    const vite = await createViteServer({ 
        logLevel: 'error', 
        server: { 
            middlewareMode: 'ssr', 
            watch: { 
                // During tests we edit the files too fast and sometimes chokidar 
                // misses change events, so enforce polling for consistency 
                usePolling: true,
                interval: 100 
            } 
        } 
    }) 
    // 使用 vite 的 Connect 实例作为中间件
    app.use(vite.middlewares) 
    app.use('/render', async (req, res) => { 
        // 服务 index.html 
        res.setHeader('X-Frame-Options', 'allow-from *') 
        const url = req.originalUrl 
        const isSupportWebp = req.headers['accept'].toLowerCase().includes('image/webp') 
        try { 
            // 1. 读取 index.html 
            let template = fs.readFileSync( path.resolve(__dirname, '../src/vite/vite.html'), 'utf-8' ) 
            // 2. 应用 vite HTML 转换。这将会注入 vite HMR 客户端, 
            // 同时也会从 Vite 插件应用 HTML 转换。 
            // 例如:@vitejs/plugin-react-refresh 中的 global preambles
            template = await vite.transformIndexHtml(url, template) 
            // 4. 渲染应用的 HTML。这假设 entry-server.js 导出的 `render` 
            // 函数调用了适当的 SSR 框架 API。 
            // 例如 ReactDOMServer.renderToString() 
            const appScript = `<script>window.TA = window.TA || {};</script>` 
            // 5. 注入渲染后的应用程序 HTML 到模板中。 
            const html = template.replace(``, appScript)
            // 6. 返回渲染后的 HTML。
            res.status(200).set({ 'Content-Type': 'text/html' }).end(html) 
        } catch (e) { 
            // 如果捕获到了一个错误,让 vite 来修复该堆栈,这样它就可以映射回你的实际源码中。 
            vite.ssrFixStacktrace(e) 
            console.error(e) 
            res.status(500).end(e.message) 
        } 
    }) 
    app.use(
        express.static('./', {
          extensions: ['html']
        })
    )
    return { app, vite } 
} 
createServer().then(({ app }) => { 
    app.listen(7777, () => { console.log('localhost:7777') }) 
})

结语

此文章主要是用来总结vite+vue的搭建过程,由于笔者也是处于vite的初学阶段, 有什么写的不严谨的地方希望大家可以提出宝贵的意见。
相关参考链接
vite中文网
vue3
vant-v3