vite 基础一网打尽

发布时间 2023-04-21 23:57:47作者: wanglei1900

vite

Webpack和Vite都是现代化的前端构建工具,它们的主要区别在于构建速度和开发体验。Webpack是一个功能强大的构建工具,它可以处理各种类型的文件,但是在构建大型项目时,它的构建速度可能会变慢

1. vite.config.ts 项目基础配置

/* 
	- defineConfig 是一个函数,它接受一个函数作为参数,该函数返回一个 UserConfig 对象,该对象描述了项目的配置。
	- loadEnv 是一个函数,它接受两个参数:mode 和 cwd。mode 是一个字符串,表示当前的构建模式(例如 development 或 production),cwd 是一个字符串,表示当前工作目录的路径。loadEnv 函数返回一个对象,该对象包含了当前环境的所有变量。
	- ConfigEnv 是一个类型别名,它描述了 Vite 构建工具的配置环境。
	- UserConfig 是一个类型别名,它描述了 Vite 构建工具的用户配置。
	- command参数 是启动vite的命令(dev/serve 或 build),可以用来配置不同场景。
	- mode参数 据当前工作目录中的 `mode` 加载相应的 .env 文件.
	- ssrBuild参数 SSR 构建(ssrBuild)实验属性vite2无,vite3才有
*/
import { defineConfig, loadEnv, ConfigEnv, UserConfig } from "vite";

export default defineConfig(({ command, mode, ssrBuild }: ConfigEnv): UserConfig => {
  // ...
})

2. defineConfig函数的配置项接口UserConfig

可以对暴露的defineConfig函数的配置项有个大概的了解

export declare interface UserConfig {
	/**
	 * 项目根目录。可以是绝对路径,也可以是相对于配置文件本身的路径。
	 * @default process.cwd()
	 */
	root?: string;
	/**
	 * 在开发或生产环境中提供服务时的基本公共路径。
	 * @default '/'
	 */
	base?: string;
	/**
	 * 用作纯静态资源的目录。此目录中的文件将原样提供服务并复制到构建的 dist 目录中,而不进行转换。
	 * 值可以是绝对文件系统路径或相对于 <root> 的路径。
	 *
	 * 将其设置为 `false` 或空字符串以禁用将静态资源复制到构建的 dist 目录中。
	 * @default 'public'
	 */
	publicDir?: string | false;
	/**
	 * 保存缓存文件的目录。此目录中的文件是预打包的依赖项或由 vite 生成的其他缓存文件,可以提高性能。
	 * 您可以使用 `--force` 标志或手动删除目录以重新生成缓存文件。
	 * 值可以是绝对文件系统路径或相对于 <root> 的路径。
	 * 在未检测到 `package.json` 时默认为 `.vite`。
	 * @default 'node_modules/.vite'
	 */
	cacheDir?: string;
	/**
	 * 显式设置要运行的模式。这将覆盖每个命令的默认模式,并可以被命令行 --mode 选项覆盖。
	 */
	mode?: string;
	/**
	 * 定义全局变量替换。
	 * 条目将在开发期间在 `window` 上定义,并在构建期间替换。
	 */
	define?: Record<string, any>;
	/**
	 * 要使用的 vite 插件数组。
	 */
	plugins?: PluginOption[];
	/**
	 * 配置解析器
	 */
	resolve?: ResolveOptions & {
		alias?: AliasOptions;
	};
	/**
	 * 与 CSS 相关的选项(预处理器和 CSS 模块)
	 */
	css?: CSSOptions;
	/**
	 * JSON 加载选项
	 */
	json?: JsonOptions;
	/**
	 * 传递给 esbuild 的转换选项。
	 * 或将其设置为 `false` 以禁用 esbuild。
	 */
	esbuild?: ESBuildOptions | false;
	/**
	 * 指定要视为静态资源的其他 picomatch 模式。
	 */
	assetsInclude?: string | RegExp | (string | RegExp)[];
	/**
	 * 服务器特定选项,例如主机、端口、https...
	 */
	server?: ServerOptions;
	/**
	 * 构建特定选项
	 */
	build?: BuildOptions;
	/**
	 * 预览特定选项,例如主机、端口、https...
	 */
	preview?: PreviewOptions;
	/**
	 * 依赖项优化选项
	 */
	optimizeDeps?: DepOptimizationOptions;
	/* 从此版本中排除:ssr */
	/**
	 * 日志级别。
	 * 默认值:'info'
	 */
	logLevel?: LogLevel;
	/**
	 * 自定义日志记录器。
	 */
	customLogger?: Logger;
	/**
	 * 默认值:true
	 */
	clearScreen?: boolean;
	/**
	 * 环境文件目录。可以是绝对路径,也可以是相对于配置文件本身的路径。
	 * @default root
	 */
	envDir?: string;
	/**
	 * 以 `envPrefix` 开头的环境变量将通过 import.meta.env 在客户端源代码中公开。
	 * @default 'VITE_'
	 */
	envPrefix?: string | string[];
	/**
	 * 导入别名
	 * @deprecated 请改用 `resolve.alias`
	 */
	alias?: AliasOptions;
	/**
	 * 强制 Vite 始终将列出的依赖项解析为相同的副本(从项目根目录)。
	 * @deprecated 请改用 `resolve.dedupe`
	 */
	dedupe?: string[];
	/**
	 * Worker bundle 选项
	 */
	worker?: {
		/**
		 * Worker bundle 的输出格式
		 * @default 'iife'
		 */
		format?: 'es' | 'iife';
		/**
		 * 适用于 worker bundle 的 Vite 插件
		 */
		plugins?: PluginOption[];
		/**
		 * 用于构建 worker bundle 的 Rollup 选项
		 */
		rollupOptions?: Omit<RollupOptions, 'plugins' | 'input' | 'onwarn' | 'preserveEntrySignatures'>;
	};
}

3. vite.config.ts中进行场景切换和使用环境变量

export default defineConfig(({ command, mode, ssrBuild }: ConfigEnv): UserConfig => {
	// 如果配置文件需要基于(dev/serve 或 build)命令或者不同的 模式 来决定选项,亦或者是一个 SSR 构建(ssrBuild)
	console.log('mode:', mode); 	// mode: 'development'
	console.log('command:', command); 	// command: 'serve'
	if (command === 'serve') {
    return {
      // dev 独有配置
    }
  } else {
    // command === 'build'
    return {
      // build 独有配置
    }
  }

	/* 
  	根据当前工作目录中的 `mode` 加载 .env 文件
  	第二个参数:process.cwd()表示返回运行当前脚本的工作目录的路径(current work directory)
  	设置第三个参数为 '' 来加载所有环境变量,而不管是否有 `VITE_` 前缀。
	*/
	const env = loadEnv(mode, process.cwd(),'');
	console.log('env:', env);
	/* 
		ViteEnv 是一个接口,它描述了 Vite 构建工具的环境变量配置。具体来说,ViteEnv 包含了以下属性:
		- VITE_API_URL:一个字符串类型的属性,表示 API 的基础 URL。
		- VITE_PORT:一个数字类型的属性,表示 Vite 服务器的端口号。
		- VITE_OPEN:一个布尔类型的属性,表示是否在启动 Vite 服务器时自动打开浏览器。
		- VITE_GLOB_APP_TITLE:一个字符串类型的属性,表示应用程序的标题。
		- VITE_DROP_CONSOLE:一个布尔类型的属性,表示是否在生产模式下删除控制台输出。
		- VITE_PROXY_URL:一个字符串类型的属性,表示代理服务器的 URL。
		- VITE_BUILD_GZIP:一个布尔类型的属性,表示是否在构建时启用 Gzip 压缩。
		- VITE_REPORT:一个布尔类型的属性,表示是否在构建时生成报告。
		env {
			VITE_API_URL: '/api',
			VITE_PORT: '3301',
			VITE_OPEN: 'true',
			VITE_GLOB_APP_TITLE: 'Hooks-Admin',
			VITE_DROP_CONSOLE: 'true'
			VITE_USER_NODE_ENV: 'development',
			VITE_BUILD_GZIP: 'false',
			VITE_REPORT: 'false',
		}
	*/
})

4. 项目中使用环境变量

4.1 环境变量

Vite 在一个特殊的 import.meta.env 对象上暴露环境变量

以下变量在所有情况下都能直接使用,其余环境变量需考虑对应加载的环境文件。

  • import.meta.env.MODE: {string} 应用运行的模式。
  • import.meta.env.BASE_URL: {string} 部署应用时的基本 URL。他由base 配置项决定。
  • import.meta.env.PROD: {boolean} 应用是否运行在生产环境。
  • import.meta.env.DEV: {boolean} 应用是否运行在开发环境 (永远与 import.meta.env.PROD相反)。
  • import.meta.env.SSR: {boolean} 应用是否运行在 server 上。

4.2 .env文件

vite根据环境模式加载对应的环境变量

指定模式(.env.production)将会比通用模式的优先级更高(.env)

  • .env # 所有情况下都会加载
  • .env.local # 所有情况下都会加载,但会被 git 忽略
  • .env.[mode] # 只在指定模式下加载
  • .env.[mode].local # 只在指定模式下加载,但会被 git 忽略

4.3 环境变量的优先级

  • 指定模式的文件(例如 .env.production)会比通用形式的优先级更高(例如 .env)。
  • Vite 执行时已经存在的环境变量有最高的优先级(系统变量),不会被 .env 类文件覆盖(例如当终端运行 VITE_SOME_KEY=123 npm run dev)。
  • .env 类文件会在 Vite 启动一开始时被加载,而改动会在重启服务器后生效。如果你需要在运行时动态修改环境变量,可以考虑使用 Node.js 的 process.env 对象来实现。
  • 加载的环境变量也会通过 import.meta.env 以字符串形式读取。为了防止意外地将一些环境变量泄漏到客户端,只有以 VITE_ 为前缀的变量才会暴露给经过 vite 处理的代码,所以VITE_的变量不应该包含任何敏感细腻。
  • 敏感变量应该放到.env.*.local中,并在git中设置忽略。

4.4 智能提示

随着在 .env[mode] 文件中自定义了越来越多的环境变量,你可能想要在代码中获取这些以 VITE_ 为前缀的用户自定义环境变量的 TypeScript 智能提示。

//  src 目录下创建一个 env.d.ts 文件,接着按下面这样增加 ImportMetaEnv 的定义
/// <reference types="vite/client" />

// typescrite 智能提示读取import.meta.env里的变量
interface ImportMetaEnv {
	readonly VITE_APP_TITLE: string
  readonly VITE_PORT: string
  readonly VITE_API_URL: string
  readonly VITE_OPEN: string
  // 更多环境变量...
}
interface ImportMeta {
  readonly env: ImportMetaEnv
}

// 解决.ts文件识别不了.vue文件
declare module '*.vue' {
  import type { DefineComponent } from 'vue'
  const component: DefineComponent<{}, {}, any>
  export default **component**
}

4.5 HTML中环境变量的替换

Vite 还支持在 HTML 文件中替换环境变量。import.meta.env 中的任何属性都可以通过特殊的 %ENV_NAME% 语法在 HTML 文件中使用:

<h1>Vite is running in %MODE%</h1>
<p>Using data from %VITE_API_URL%</p>

如果环境变量在 import.meta.env 中不存在,比如不存在的 %NON_EXISTENT%,则会将被忽略而不被替换,这与 JS 中的 import.meta.env.NON_EXISTENT 不同,JS 中会被替换为 undefined。

5. 配置项

5.1 resolve.alias

这将创建一个名为@的别名,指向当前文件所在目录下的src目录。请注意,您需要在webpack配置文件中引入Node.js的path模块,以便使用path.resolve()方法来创建绝对路径。

  resolve: {
  	alias: {
  		"@": resolve(__dirname, "./src")
  	}
  },

5.2 css.preprocessorOptions

指定传递给 CSS 预处理器的选项。文件扩展名用作选项的键。每个预处理器支持的选项可以在它们各自的文档中找到

  css: {
    preprocessorOptions: {
			// additionalData属性设置了一个名为$injectedColor的变量,它的值为orange。这个变量可以在SCSS文件中使用。
      scss: {
        additionalData: `$injectedColor: orange;`,
      },
			// dditionalData属性设置了一个@import语句,它导入了一个名为var.less的文件。这个文件中可能包含一些变量或混合器,可以在LESS文件中使用。
      less: {
				additionalData: `@import "@/styles/var.less";`
      },
			//  仅支持 define,可以作为对象传递
      styl: {
        define: {
          $specialColor: new stylus.nodes.RGBA(51, 197, 255, 1),
        },
      },
    },
  },

5.3 esbuild

  • pure: 安全删除调试
  • target:指定编译后的 JavaScript 代码的目标运行环境。默认为当前 Node.js 版本。
  • jsxFactory 和 jsxFragment:指定 JSX 语法中的 createElement 函数和 Fragment 组件。默认为 React.createElement 和 React.Fragment。
  • jsxInject: 自动为每一个文件注入jsx helper。例如:jsxInject: import React from 'react',
  • define:定义全局常量,可以在代码中使用。例如,define: { 'process.env.NODE_ENV': JSON.stringify(mode) } 可以将 process.env.NODE_ENV 定义为当前的环境变量 mode。
  • minify:是否启用代码压缩。默认为 true。
  • keepNames:是否保留函数和变量的名称。默认为 false。
  • tsconfig:指定 TypeScript 配置文件的路径。默认为 tsconfig.json。
  • loader:自定义文件加载器。例如,loader: { '.svg': 'file' } 可以将 SVG 文件加载为文件路径。
esbuild: {
  pure: ["console.log", "debugger"],
  target: "es2015",
  jsxFactory: "h",
  jsxFragment: "Fragment",
  define: {
    "process.env.NODE_ENV": JSON.stringify(mode),
    "process.env.BASE_URL": JSON.stringify(base),
  },
  minify: false,
  keepNames: true,
  tsconfig: "tsconfig.json",
  loader: {
    ".svg": "file",
  },
},

5.4 server

  • host:指定服务器监听的主机名。默认为 "localhost"。如果将此设置为 0.0.0.0 或者 true,允许外部访问。
  • port:指定服务器监听的端口号。默认为 3000。
  • https:是否启用 HTTPS。默认为 false。
  • open:是否在启动服务器时自动打开浏览器。默认为 false。如果你想在你喜欢的某个浏览器打开该开发服务器,你可以设置环境变量 process.env.BROWSER (例如 firefox)
  • cors:是否启用跨域资源共享。默认为 false。
  • strictPort:是否启用严格的端口检查。默认为 false。
  • proxy:配置代理服务器。例如,proxy: { '/api': 'http://localhost:8080' } 可以将 /api 路径下的请求代理到 http://localhost:8080
  • hmr:配置模块热替换。例如,hmr: { overlay: false } 可以禁用热更新时的错误提示。
  • watch:配置文件监听。例如,watch: { disableGlobbing: true } 可以禁用文件名通配符。
  • middleware:配置自定义中间件。例如,middleware: [myMiddleware] 可以添加一个自定义中间件函数 myMiddleware。
server: {
  host: "localhost",
  port: 8080,
  https: true,
  open: true,
  cors: true,
  strictPort: true,
  proxy: {
    "/api": "http://localhost:3000", // 定代理服务器的地址。
		changeOrigin: true,	// 是否改变请求头中的 Origin 字段。默认为 false。
   	rewrite: path => path.replace(/^\/api/, "")	// 重写请求路径。例如,path => path.replace(/^\/api/, "") 可以将 /api 前缀去掉。
  },
  hmr: {
    overlay: false,	// 模块热替换禁用了错误提示
  },
  watch: {
    usePolling: true,	// 文件监听使用了轮询方式
  },
  middleware: [myMiddleware],	//自定义中间件函数 myMiddleware 被添加到了中间件数组中。
},

5.5 build

  • outDir:指定输出目录,默认为dist。
  • assetsDir:指定静态资源目录,默认为assets。
  • assetsInlineLimit:指定资源内联的最大大小,单位为字节,默认为4096。
  • cssCodeSplit:指定是否将CSS代码拆分为单独的文件,默认为true。
  • minify:指定是否压缩代码,默认:'esbuild'。boolean | 'terser' | 'esbuild'
  • sourcemap:指定是否生成sourcemap,默认为false。
  • chunkSizeWarningLimit:规定触发警告的 chunk 大小。(以 kbs 为单位)。
  • rollupOptions:指定传递给Rollup的选项,例如input、output、plugins等。
  • terserOptions:指定传递给Terser的选项,例如compress、mangle等。
  build: {
    outDir: 'dist',
    assetsDir: 'assets',
    cssCodeSplit: true,
    minify: 'esbuild',
    sourcemap: false,
		chunkSizeWarningLimit: 1500,
    rollupOptions: {
      input: {
        main: './src/main.js',
        secondary: './src/secondary.js'
      },
      output: {
        entryFileNames: '[name]-[hash].js',
        chunkFileNames: '[name]-[hash].js',
        assetFileNames: '[name]-[hash].[ext]'
      },
      plugins: [
        // 添加rollup插件
					// Static resource classification and packaging
					chunkFileNames: "assets/js/[name]-[hash].js",
					entryFileNames: "assets/js/[name]-[hash].js",
					assetFileNames: "assets/[ext]/[name]-[hash].[ext]"
      ]
    },
    // terserOptions: {
    //   compress: {
    //     drop_console: true,
    //     drop_debugger: true
    //   },
    //   mangle: true
    // }
  }

5.6 plugins

需要用到的插件数组

  • react():用于在Vite中使用React。
  • createHtmlPlugin():用于生成HTML文件并注入数据。
  • createSvgIconsPlugin():用于导入SVG图标。
  • eslintPlugin():用于在开发过程中进行ESLint检查。
  • visualizer():用于生成包预览。
  • viteCompression():用于压缩生成的文件。
  • @vitejs/plugin-vue:用于在Vue应用程序中使用单文件组件。
  • @vitejs/plugin-react-refresh:用于在React应用程序中启用热重载。
  • @vitejs/plugin-legacy:用于在旧版浏览器中使用ES5代码。
  • @vitejs/plugin-json:用于导入JSON文件。
  • @vitejs/plugin-commonjs:用于将CommonJS模块转换为ES模块。
  • @vitejs/plugin-node-resolve:用于解析Node.js模块。
  • @vitejs/plugin-eslint:用于在开发过程中进行ESLint检查。
  • @vitejs/plugin-svg:用于导入SVG文件。
  • @vitejs/plugin-image:用于导入图像文件。

6.示例

/* 
	- defineConfig 是一个函数,它接受一个函数作为参数,该函数返回一个 UserConfig 对象,该对象描述了项目的配置。
	- loadEnv 是一个函数,它接受两个参数:mode 和 cwd。mode 是一个字符串,表示当前的构建模式(例如 development 或 production),cwd 是一个字符串,表示当前工作目录的路径。loadEnv 函数返回一个对象,该对象包含了当前环境的所有变量。
	- ConfigEnv 是一个类型别名,它描述了 Vite 构建工具的配置环境。
	- UserConfig 是一个类型别名,它描述了 Vite 构建工具的用户配置。
*/
import { defineConfig, loadEnv, ConfigEnv, UserConfig } from "vite";
import react from "@vitejs/plugin-react";
import { resolve } from "path";
import { wrapperEnv } from "./src/utils/getEnv";
import { visualizer } from "rollup-plugin-visualizer";
import { createHtmlPlugin } from "vite-plugin-html";
import viteCompression from "vite-plugin-compression";
import eslintPlugin from "vite-plugin-eslint";
import { createSvgIconsPlugin } from "vite-plugin-svg-icons";

// @see: https://vitejs.dev/config/
export default defineConfig((mode: ConfigEnv): UserConfig => {
	console.log('mode', mode);
	/* 
		mode {                                                                                 23:15:28
			mode: 'development',
			command: 'serve'
		}
	*/
	/* 
	根据当前工作目录中的 `mode` 加载 .env 文件
	第二个参数:process.cwd()表示返回运行当前脚本的工作目录的路径(current work directory)
	设置第三个参数为 '' 来加载所有环境变量,而不管是否有 `VITE_` 前缀。
	*/
	const env = loadEnv(mode.mode, process.cwd());
	const viteEnv = wrapperEnv(env);
	console.log('env', env);
	/* 
		ViteEnv 是一个接口,它描述了 Vite 构建工具的环境变量配置。具体来说,ViteEnv 包含了以下属性:
		- VITE_API_URL:一个字符串类型的属性,表示 API 的基础 URL。
		- VITE_PORT:一个数字类型的属性,表示 Vite 服务器的端口号。
		- VITE_OPEN:一个布尔类型的属性,表示是否在启动 Vite 服务器时自动打开浏览器。
		- VITE_GLOB_APP_TITLE:一个字符串类型的属性,表示应用程序的标题。
		- VITE_DROP_CONSOLE:一个布尔类型的属性,表示是否在生产模式下删除控制台输出。
		- VITE_PROXY_URL:一个字符串类型的属性,表示代理服务器的 URL。
		- VITE_BUILD_GZIP:一个布尔类型的属性,表示是否在构建时启用 Gzip 压缩。
		- VITE_REPORT:一个布尔类型的属性,表示是否在构建时生成报告。
		env {                                                                                  23:22:04
			VITE_API_URL: '/api',
			VITE_PORT: '3301',
			VITE_OPEN: 'true',
			VITE_GLOB_APP_TITLE: 'Hooks-Admin',
			VITE_DROP_CONSOLE: 'true'
			VITE_USER_NODE_ENV: 'development',
			VITE_BUILD_GZIP: 'false',
			VITE_REPORT: 'false',
		}
	*/

	return {
		// base: "/",
		// alias config
		resolve: {
			alias: {
				"@": resolve(__dirname, "./src")
			}
		},
		// global css
		css: {
			preprocessorOptions: {
				less: {
					// modifyVars: {
					// 	"primary-color": "#1DA57A",
					// },
					javascriptEnabled: true,
					additionalData: `@import "@/styles/var.less";`
				}
			}
		},
		// server config
		server: {
			host: "0.0.0.0", // 服务器主机名,如果允许外部访问,可设置为"0.0.0.0"
			port: viteEnv.VITE_PORT,
			open: viteEnv.VITE_OPEN,
			cors: true,
			// https: false,
			// 代理跨域(mock 不需要配置,这里只是个事列)
			proxy: {
				"/api": {
					target: "https://mock.mengxuegu.com/mock/62abda3212c1416424630a45", // easymock
					changeOrigin: true,
					rewrite: path => path.replace(/^\/api/, "")
				}
			}
		},
		// plugins
		plugins: [
			react(),
			createHtmlPlugin({
				inject: {
					data: {
						title: viteEnv.VITE_GLOB_APP_TITLE
					}
				}
			}),
			// * 使用 svg 图标
			createSvgIconsPlugin({
				iconDirs: [resolve(process.cwd(), "src/assets/icons")],
				symbolId: "icon-[dir]-[name]"
			}),
			// * EsLint 报错信息显示在浏览器界面上
			eslintPlugin(),
			// * 是否生成包预览
			viteEnv.VITE_REPORT && visualizer(),
			// * gzip compress
			viteEnv.VITE_BUILD_GZIP &&
			viteCompression({
				verbose: true,
				disable: false,
				threshold: 10240,
				algorithm: "gzip",
				ext: ".gz"
			})
		],
		esbuild: {
			pure: viteEnv.VITE_DROP_CONSOLE ? ["console.log", "debugger"] : []
		},
		// build configure
		build: {
			outDir: "dist",
			// esbuild 打包更快,但是不能去除 console.log,去除 console 使用 terser 模式
			minify: "esbuild",
			// minify: "terser",
			// terserOptions: {
			// 	compress: {
			// 		drop_console: viteEnv.VITE_DROP_CONSOLE,
			// 		drop_debugger: true
			// 	}
			// },
			rollupOptions: {
				output: {
					// Static resource classification and packaging
					chunkFileNames: "assets/js/[name]-[hash].js",
					entryFileNames: "assets/js/[name]-[hash].js",
					assetFileNames: "assets/[ext]/[name]-[hash].[ext]"
				}
			}
		}
	};
});