import {defineConfig} from 'vite' import vue from '@vitejs/plugin-vue' import vitePluginImp from 'vite-plugin-imp' import path from 'path' const isProduction = process.env.NODE_ENV === 'production' // https://vitejs.dev/config/ export default defineConfig{ // 项目根目录 root: process.cwd), // 在生产中服务时的基本公共路径 base: isProduction ? './' : '', // 配置中指明将会把 serve 和 build 时的模式都覆盖掉,serve 时默认 'development',build 时默认 'production' mode: 'development', // 在开发时会被定义为全局变量,而在构建时则是静态替换 define: '', // 静态资源服务的文件夹 publicDir: 'assets', resolve: { // 目录别名 alias: { '@': path.resolve__dirname, '/src'), }, }, // CSS 预处理器 css: { preprocessorOptions: { scss: { // additionalData: `$injectedColor: orange;` additionalData: "@import './src/assets/style/mixin.scss';" } , less: { javascriptEnabled: true } }, postcss: { plugins: [ require'autoprefixer') ] } }, // server: { // 是否自动打开浏览器 open: true, // 服务器主机名,如果允许外部访问,可设置为"0.0.0.0" host: '0.0.0.0', // 服务器端口号 port: 56438, // 设为 true ,若端口已被占用则会直接退出,而不是尝试下一个可用端口 strictPort: false, // 为开发服务器配置 CORS cors: true, // 设置为 true 强制使依赖预构建 force: true, // 代理 proxy: { '/api': { target: 'http://xxx.xxx.xx', changeOrigin: true, rewrite: path) => path.replace/^/api/, '') } } , } , // build build: { // 压缩 minify: "esbuild", assetsDir: "", outDir: `./dist/${process.env.VITE_ENV}`, // 进行压缩计算 brotliSize: false }, ssr: false, // 将要用到的插件数组 plugins: [ vue), vitePluginImp{ libList: [ { libName: 'vant', stylename) { if /CompWithoutStyleFile/i.testname)) { // This will not import any style file return false } return `vant/es/${name}/style/index.js` } }, { libName: 'element-plus', style: name) => { return `element-plus/lib/theme-chalk/${name}.css` } } ] }), require'autoprefixer') ] })
Vite插件是什么
使用Vite插件可以扩展Vite能力,比如解析用户自定义的文件输入,在打包代码前转译代码,或者查找第三方模块。
Vite插件的形式
Vite
插件扩展自Rollup
插件接口,只是额外多了一些Vite
特有选项。
Vite
插件是一个拥有名称、创建钩子build hook)或生成钩子output generate hook)的对象。
如果需要配置插件,它的形式应该是一个接收插件选项,返回插件对象的函数。
范例:加载一个不存在的虚拟模块
创建vite-plugin-my-example.js
export default function myExample ) { return { name: 'my-example', // 名称用于警告和错误展示 resolveId source ) { if source === 'virtual-module') { return source; // 返回source表明命中,vite不再询问其他插件处理该id请求 } return null; // 返回null表明是其他id要继续处理 }, load id ) { if id === 'virtual-module') { return 'export default "This is virtual!"'; // 返回"virtual-module"模块源码 } return null; // 其他id继续处理 } }; }
插件钩子
通用钩子
开发时,Vite dev server
创建一个插件容器按照Rollup
调用创建钩子的规则请求各个钩子函数。
下面钩子会在服务器启动时调用一次:
options
替换或操纵rollup
选项
buildStart
开始创建
下面钩子每次有模块请求时都会被调用:
resolveId
创建自定义确认函数,常用语定位第三方依赖
load
创建自定义加载函数,可用于返回自定义的内容
transform
可用于转换已加载的模块内容
下面钩子会在服务器关闭时调用一次:
Vite特有钩子
config: 修改Vite配置
configResolved:Vite配置确认
configureServer:用于配置dev server
transformIndexHtml:用于转换宿主页
handleHotUpdate:自定义HMR更新时调用
范例:钩子调用顺序测试
export default function myExample ) { // 返回的是插件对象 return { name: 'hooks-order', // 初始化hooks,只走一次 optionsopts) { console.log'options', opts); }, buildStart) { console.log'buildStart'); }, // vite特有钩子 configconfig) { console.log'config', config); return {} }, configResolvedresolvedCofnig) { console.log'configResolved'); }, configureServerserver) { console.log'configureServer'); // server.app.usereq, res, next) => { // // custom handle request... // }) }, transformIndexHtmlhtml) { console.log'transformIndexHtml'); return html // return html.replace // /<title>.*?)</title>/, // `<title>Title replaced!</title>` // ) }, // 通用钩子 resolveId source ) { if source === 'virtual-module') { console.log'resolvedId', source); return source; } return null; }, load id ) { if id === 'virtual-module') { console.log'load'); return 'export default "This is virtual!"'; } return null; }, transformcode, id) { if id === 'virtual-module') { console.log'transform'); } return code }, }; }
钩子调用顺序
插件顺序
别名处理Alias
用户插件设置enforce: 'pre'
Vite核心插件
用户插件未设置enforce
Vite构建插件
用户插件设置enforce: 'post'
Vite构建后置插件minify, manifest, reporting)
插件编写实操
实现一个mock服务器vite-plugin-mock
实现思路是给开发服务器实例connect)配一个中间件,该中间件可以存储用户配置接口映射信息,并提前处理输入请求,如果请求的url和路由表匹配则接管,按用户配置的handler返回结果。
创建plugins/vite-plugin-mock.js
import path from 'path' let mockRouteMap = {}; function matchRoutereq) { let url = req.url; let method = req.method.toLowerCase); let routeList = mockRouteMap[method]; return routeList && routeList.finditem) => item.path === url); } function createRoutemockConfList) { mockConfList.forEachmockConf) => { let method = mockConf.type || 'get'; let path = mockConf.url; let handler = mockConf.response; let route = { path, method: method.toLowerCase), handler }; if !mockRouteMap[method]) { mockRouteMap[method] = []; } console.log'create mock api: ', route.method, route.path); mockRouteMap[method].pushroute); }); } function sendbody) { let chunk = JSON.stringifybody); // Content-Length if chunk) { chunk = Buffer.fromchunk, 'utf-8'); this.setHeader'Content-Length', chunk.length); } // content-type this.setHeader'Content-Type', 'application/json'); // status this.statusCode = 200; // respond this.endchunk, 'utf8'); } export default function options = {}) { options.entry = options.entry || './mock/index.js'; if !path.isAbsoluteoptions.entry)) { options.entry = path.resolveprocess.cwd), options.entry); } return { configureServer: function { app }) { const mockObj = requireoptions.entry); createRoutemockObj); const middleware = req, res, next) => { let route = matchRoutereq); if route) { console.log'mock request', route.method, route.path); res.send = send; route.handlerreq, res); } else { next); } }; app.usemiddleware); }, }; }
export default function vitePlugin ) { // 定义vite插件唯一id const virtualFileId = '@my-virtual-plugin' // 返回插件对象 return { // 必须的,将会显示在 warning 和 error 中 name: 'vite-plugin', // *以下钩子函数按照实际执行顺序排列* /** * config 可以在被解析之前修改 Vite 配置 * Vite独有钩子 * https://cn.vitejs.dev/guide/api-plugin.html#config * @param config vite配置信息 * @param env 描述配置环境的变量 */ config: config, env) => {}), /** * configResolved 解析 Vite 配置后调用,使用这个钩子读取和存储最终解析的配置 * Vite独有钩子 * https://cn.vitejs.dev/guide/api-plugin.html#configresolved * @param config vite配置信息 */ configResolved: config => {}), /** * options 替换或操作传递给rollup.rollup)的选项 * 通用钩子 * https://rollupjs.org/guide/en/ * @param options rollup配置信息 */ options: options => {}), /** * configureServer 用于配置开发服务器 * Vite独有钩子 * https://cn.vitejs.dev/guide/api-plugin.html#configureserver * @param server ViteDevServer配置信息 * https://cn.vitejs.dev/guide/api-javascript.html#vitedevserver */ configureServer: server => {}), /** * buildStart 在每个rollup.rollup)构建时被调用 * 通用钩子 * https://rollupjs.org/guide/en/ * @param options rollup配置信息 */ buildStart: options => {}), /** * 此时 Vite dev server is running */ /** * transformIndexHtml 转换 index.html 的专用钩子 * Vite独有钩子 * https://cn.vitejs.dev/guide/api-plugin.html#transformindexhtml * @param html html字符串 * @param ctx 转换上下文; 在开发期间会额外暴露ViteDevServer实例; 在构建期间会额外暴露Rollup输出的包 */ transformIndexHtml: html, ctx) => {}), /** * resolveId 用户自定义解析器 * 通用钩子 会在每个传入模块请求时被调用 * https://rollupjs.org/guide/en/ * @param source 源导入者 例子: import { foo } from '../bar.js', '../bar.js' 为source * @param importer 导入者所在文件绝对路径 */ resolveId: source, importer) => {}), /** * load 用户自定义加载器 * 通用钩子 会在每个传入模块请求时被调用 * https://rollupjs.org/guide/en/ * @param id 同resolveId source */ load: id => {}), /** * transform 可以用来转换单个模块 * 通用钩子 会在每个传入模块请求时被调用 * https://rollupjs.org/guide/en/ * @param code 模块代码 * @param id 同resolveId source */ transform: code, id) => {}) } }