Vite 从入门到精通 | 高级应用
Vite 从入门到精通 | 高级应用
本文总结 Vite 中的高级应用, 包括 HMR 热更新功能, glob-import批量导入功能,预编译优化提升 Vite 性能,在非 Node 服务中集成 Vite,Vite 中对 SSR 的使用,静态站点导出,Vite 配置项总结等应用
Vite 中的 HRM 热更新
通过 vanilla 项目创建 HRM
创建项目
$ npm init @vitejs/app ✔ Project name: … vite-project ✔ Select a framework: › vanilla ✔ Select a variant: › vanilla 复制代码
实现单文件HMR 热更新
import './style.css' export function render () { document.querySelector('#app').innerHTML = ` <h1>Hello Vite!</h1> <a href="https://vitejs.dev/guide/features.html" target="_blank">Documentation</a> ` } render() // 集成 HMR // vite build 时 import.meta.hot 是不存在的, 所以加开发环境的判断条件 // 常规范式: 在开发环境中设置 HRM 热更新 if (import.meta.hot) { // 接收热更新 // newModule 对应的当前文件 // Vite 接收到文件更新后, 执行这个方法 重新 render import.meta.hot.accept((newModule) => { newModule.render(); }) } 复制代码
附源码: github.com/xujiantong/…
Vite 中的 glob-import 批量导入功能
glob-import: 可以使用正则表达式, 引入一组的文件
通过 vite-vue3 项目实操 glob-import
创建项目
$ npm init @vitejs/app ✔ Project name: … vite-project ✔ Select a framework: › vue ✔ Select a variant: › vue $ cd vite-project $ yarn $ yarn dev 复制代码
准备文件
在 src 目录下创建 glob 文件夹 并创建 文件
cd src mkdir glob touch a.js a.json b.js b.json test-1.js # 文件内容见源码 # https://github.com/xujiantong/vite-senior-apply/tree/feat/glob 复制代码
在 mian.js 中一键导入 glob 下面的所有文件
导入所有文件
// main.js import { createApp } from 'vue' import App from './App.vue' const globModules = import.meta.glob("./glob/*") console.log(globModules) createApp(App).mount('#app') 复制代码
使用文件里面的数据
import { createApp } from 'vue' import App from './App.vue' const globModules = import.meta.glob("./glob/*") console.log(globModules) // 查看 Key Value Object.entries(globModules).forEach(([k,v]) => { console.log(k+ ":" + v) v().then(m => console.log(k + ":" ,m.default)) }) createApp(App).mount('#app') 复制代码
应用场景
多语言
只引入 JS
const globModules = import.meta.glob("./glob/*.js") 复制代码
只想引入 json 文件
const globModules = import.meta.glob("./glob/*.json") 复制代码
只想引入指定正则的文件
const globModules = import.meta.glob("./glob/*-[0-9].json") 复制代码
Glob-import 是 Vite 提供的功能
源码: github.com/xujiantong/…
Vite 中的 预编译
对于 node_modules 中安装的第三方的库, Vite 在第一次启动之前会去把我们所依赖的这些包进行编译放在 Cache 里面, 之后程序用到回去 Cache 里面去取。
/node_modules/.vite
CommonJS to ESM: 非 ESM 的文件会被编译成 ESM
在开发过程中, Vite 是依赖于浏览器原生的 ESM 加载方式去加载文件的
可配置 vite.config.js 指定哪些是需要预编译的
// vite.config.js export default defineConfig({ plugins: [vue()], optimizeDeps: { exclude: ["react"], include: ["vue"], } }) 复制代码
Bundle files together
非 Nodejs 服务集成 Vite
非 Nodejs 服务:
java
go
python
...
模板引擎使用 Vite
引入路径问题
模板引擎增加标签 Dev
<script type="module" src="http://localhost:3000/@vite/client"> </script> <script type="module" src="http://localhost:3000/src/main.js"></script> 复制代码
解决路径问题 dev
服务端设置静态目录路径映射
打包生产时如何处理?
// vite.config.js build :{ manifest: true } 复制代码
Server 解析 manifest.json
将 index , vendor , css 输出到模板
在模板上接收变量
在 Nodejs 中如何集成 Vite
基础版
yarn add express
// server.js const express = require("express") const app = express() const { createServer: createViteServer} = require("vite") createViteServer({server: { middlewareMode: 'html', // html: vite dev server, ssr: }}).then((vite) => { app.use(vite.middlewares) app.listen(4000) }) 复制代码
服务端渲染 SSR
开发环境 Dev
const express = require("express") const fs = require("fs") const app = express() const { createServer: createViteServer} = require("vite") createViteServer({server: { middlewareMode: 'ssr', // html: vite dev server, ssr: }}).then((vite) => { app.use(vite.middlewares) app.get("*", async (req,res)=> { let template = fs.readFileSync('index.html', 'utf-8') template = await vite.transformIndexHtml(req.url, template) const {render} = await vite.ssrLoadModule('/src/server-entry.jsx') const html = await render(req.url) const responseHtml = template.replace("<!--APP_HTML-->", html) res.set("content-type", "text/html").send(responseHtml) }) app.listen(4000) }) 复制代码
Vite Config
// vim vite.config.js import { defineConfig } from 'vite' import vue from '@vitejs/plugin-vue' // 引入 jsx 依赖 import vueJsx from '@vitejs/plugin-vue-jsx' // https://vitejs.dev/config/ export default defineConfig({ root: "", // index.html 存在的位置 base: "./",// 指定请求资源路径(URL)的前缀, 默认 ./ mode: "development", // 命令行启动时 --mode 同理, 指定 env, 默认 "development"(开发模式) "production" (生产模式) define: "", // ≈ rollup 的 definePlugin, 定义全局常量的替换方式 plugins: [ // 使用插件 vue(), vueJsx(),// 使用 vue-jsx ], publicDir:"", //静态资源存放目录 cacheDir: "", // 开发1时用到的缓存存放目录, 默认"node_modules/.vite" resolve: { alias: {},// 别名,路径映射: "@styles": "/src/styles" dedupe:[], // 如果存在相同依赖的副本, 比如安装了 vue2, vue3, 用该属性来制定最终使用哪一个依赖 conditions: [], // 解决程序包中 情景导出 时的其他允许条件 mainFields: [], // package.json 中,在解析包的入口点时尝试的字段列表。注意:这比从 exports 字段解析的情景导出优先级低:如果一个入口点从 exports 成功解析,resolve.mainFields 将被忽略。 extensions: [], // 导入时想要省略的扩展名列表。不 建议忽略自定义导入类型的扩展名(例如:.vue),因为它会影响 IDE 和类型支持。 }, css: { modules:[], // 配置 CSS modules 的行为 postcss: "", // 内联的 PostCSS 配置(格式同 postcss.config.js) preprocessorOptions:{ //指定传递给 CSS 预处理器的选项 scss: { additionalData: `$injectedColor: orange;` } }, }, json: { namedExports:true, // 是否支持从 .json 文件中进行按名导入。 // json 文件很大的时候建议开启~ stringify: false,// 若设置为 true,导入的 JSON 会被转换为 export default JSON.parse("..."),这样会比转译成对象字面量性能更好,尤其是当 JSON 文件较大的时候。开启此项,则会禁用按名导入。 }, esbuild: {}, // ESbuild 转换选项 assetsInclude: { assetsInclude: ['**/*.txt'] }, // 指定额外的 picomatch 模式 作为静态资源处理, 比如我想 import 一个 txt 文件 logLevel: 'info', // 打印日志级别 clearScreen: true, envDir: "", //.env 文件存放目录 build: { target: 'modules', // 设置最终构建的浏览器兼容目标 polyfillModulePreload: true, //用于决定是否自动注入 module preload 的 polyfill. outDir: "dist",//指定输出路径 assetsDir: "assets",// 静态资源存放的路径 assetsInlineLimit: "4096", // 4kb, 小于此阈值的导入或引用资源将内联为 base64 编码,以避免额外的 http 请求。设置为 0 可以完全禁用此项。 cssCodeSplit: true, // css 文件拆分 sourcemap: 'hidden', // 构建后是否生成 source map 文件。 rollupOptions:{}, commonjsOptions:{}, dynamicImportVarsOptions:{}, lib:{}, manifest: false, // 当设置为 true,构建后将会生成 manifest.json 文件 包含了没有被 hash 的资源文件名和 hash 后版本的映射。可以为一些服务器框架渲染时提供正确的资源引入链接。 ssrManifest: false, minify: 'esbuild', terserOptions: {}, write: true, //设置为 false 来禁用将构建后的文件写入磁盘。这常用于 编程式地调用 build() 在写入磁盘之前,需要对构建后的文件进行进一步处理。 emptyOutDir: true, // 构建时是否先清空 dist brotliSize: true, // 构建后压缩报告 chunkSizeWarningLimit: 500,// 压缩超过 500k 提醒 watch: null, //设置为 {} 则会启用 rollup 的监听器。在涉及只用在构建时的插件时和集成开发流程中很常用。 // 依赖优化项 optimizeDeps: { entries: "", include: [], exclude: [], keepNames: false, // true 重命名符号避免冲突 } } })
作者:墩墩大魔王丶
链接:https://juejin.cn/post/7015408423273496583