vite 基础一网打尽
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]"
}
}
}
};
});
洗尽铅华始见金,褪去浮华归本真