背景
最近在做公司项目的技术栈迁移, 基于老项目的技术栈是vue2,因此新的技术栈采用vue3+vant的模式。 并且新增ts+eslint的配置提高项目的可维护性, 项目打包工具在正式环境打包依旧采用webpack,而开发环境存在两种打包模式vite和webpack 。vite基于浏览器ES Moudle,有打包快,体积小等优势,利于项目进行快速开发。但是由于vite本身暂时不推荐用于生产环境且生产环境需要更高的维稳性,因此开发和生产都共建一套webpack打包方式,方便日常问题的排查。本文只记录大概的开发框架以及打包配置,仅供参考。
项目结构
基础配置
在明确好技术栈之后,先搭建vu3+webpack+ts+babel的环境配置。介于老项目有用到Node修改静态页面的值,因此不考虑vue-cli的脚手架。yarn init
初始化页面,再安装vue3+babel7+typescript等依赖项。此处不做详细赘述,主要注意以下几点:
- babel.config.js文件需要对vant框架需做额外插件处理
plugins: [
[
'import',
{
libraryName: 'vant',
libraryDirectory: 'es',
style: true
},
'vant'
]
]
- ts配置时需要去除掉node_modules, 避免对依赖项进行校验,额外增加项目编译时间
"exclude": ["node_modules"]
- 项目引用路径的简写除了在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