/**
* import.meta.env.VITE_x 在.env[mode]中定义的变量不能访问到要用 loadEnv函数代替
*
*
* https://github.com/vitejs/awesome-vite#plugins
*/
import { defineConfig, loadEnv } from 'vite'
/**
* postCssPxToRem 插件
* npm i postcss-pxtorem -D
* npm i postcss -D
* npm i postcss-loader -D
* npm i autoprefixer -D (待测试)
* npm i postcss-import -D (待测试)
* npm i postcss-url -D (待测试)
* npm i postcss-aspect-ratio-mini -D (待测试)
*/
import postCssPxToRem from "postcss-pxtorem"
/**
* vue 整合插件
* npm i @vitejs/plugin-vue -D
* npm i vue -D
* npm i vue-router -D
* npm i vuex -D
* npm i axios -D
*/
import vue from '@vitejs/plugin-vue'
const url = require('url')
let parseURL = url.parse('http://user:[email protected]:8080/p/a/t/h?name=zhangsan&age=12#hash', true, true)
// 解析路径
const path = require('path')
/**
* 设置server.open默认打开的浏览器
* npm i open -D
*/
const open = require('open');
process.env.BROWSER = open.apps.chrome
/**
* gzip 压缩配置
* @type {boolean}
* @default false
* @description 是否开启 gzip 压缩
* npm i vite-plugin-compression -D
*/
import viteCompression from 'vite-plugin-compression'
/**
* mockjs 配置
* npm (配置)
* npm i mockjs -D
* npm i vite-plugin-mock -D
* npm i cross-env -D
* npm i vite-plugin-mock-server -D
* yarn (配置)
* yarn add -D cross-env vite-plugin-mock
* yarn add mockjsD
*/
import { viteMockServe } from 'vite-plugin-mock';
/**
* yarn add vite-plugin-mock-server
*/
// import mockServer from 'vite-plugin-mock-server'
// vite-plugin-mock-server
// options.plugins.push(mockServer({
// logLevel: 'info',
// urlPrefixes: ['/api/'],
// mockRootDir: './mock',
// mockJsSuffix: '.mock.js',
// mockTsSuffix: '.mock.ts',
// noHandlerResponse404: true,
// mockModules: []
// }))
// export default ({ command, mode }) => {
// console.log(command, mode);
export default defineConfig(({ command, mode }) => {
let options = {
// q:root配置项有什么用?
// a:root配置项是为了解决打包后的资源路径问题,比如打包后的index.html中的资源路径是相对于index.html的,而不是相对于域名的,这样会导致资源加载失败,所以需要设置root,将资源路径设置为相对于域名的
root: process.cwd(), //项目根目录(index.html 文件所在的位置
base: '/', //开发或生产环境服务的公共基础路径
// mode:'development' 'production'
define: { // 这是node环境读不了process,直接在代码中使用 例如:web中直接能调用,process.env.NODE_ENV
"process.env.NODE_ENV": process.env.NODE_ENV !== 'production' ? 'development' : 'production',
__PBR_APP_VERSION__: '1.0'
},
plugins: [vue(),
// q:mock插件有什么用?
// a:mock插件是为了解决开发环境下的接口调试问题,可以在开发环境下模拟接口返回数据,而不用等待后端接口开发完成
// q:viteCompression插件有什么用?
// a:viteCompression插件是为了解决生产环境下的资源压缩问题,可以在生产环境下对资源进行压缩,减少资源体积,提高加载速度
// import { viteMockServe } from 'vite-plugin-mock';
// viteCompression方法的参数是一个对象,对象中的属性是vite-plugin-compression插件的配置项
viteCompression({
filter: /\.(js|css|json|txt|html|ico|svg)(\?.*)?$/i, // 需要压缩的文件
threshold: 1024, // 文件容量大于这个值进行压缩
algorithm: 'gzip', // 压缩方式
ext: 'gz', // 后缀名
deleteOriginFile: true, // 压缩后是否删除压缩源文件
})
], // 需要用到的插件数组
publicDir: 'public', // 静态资源文件夹,默认访问路径‘/’, 构建是会放在outDir根目录
cacheDir: 'node_modules/.vite', // vite缓存文件目录,--force可以强制重新缓存
resolve: {
alias: { // 别名
'@': path.resolve(__dirname, './src'),
'comps': path.resolve(__dirname, './src/components'),
'utils': path.resolve(__dirname, './src/utils'),
'views': path.resolve(__dirname, './src/views'),
'apis': path.resolve(__dirname, './src/apis')
},
dedupe: [], // 强制将相同依赖解析为同一副本, ======待研究怎么用======
//package.json 相关 开
// q:conditions 有什么用?举个例子
// a:conditions 用于指定导入的模块的条件,比如指定导入的模块的环境
conditions: [
'import', // 导入时
'require', // require时
'node', // node环境
'default', // 默认
'import.meta', // 导入元数据
'url', // url
'script', // 脚本
'worker', // worker
'worker-src', // worker源
'typeof', // 类型
'browser', // 浏览器
'esm', // esm
'production', // 生产环境
'development', // 开发环境
'test', // 测试环境
'electron', // electron
'electron-renderer', // electron渲染器
'electron-main', // electron主进程
'nw', // nw
'nwjs', // nwjs
'web', // web
'webworker', // webworker
'global', // 全局
'pure', // 纯
], // 场景条件,
mainFields: ['module', 'jsnext:main', 'jsnext'], // 入口点字段列表
//package.json 相关 关
extensions: ['.mjs', '.js', '.ts', '.jsx', '.tsx', '.json'], //导入时想要省略的扩展名列表
},
// q:CSS配置项有什么用?
// a:CSS配置项是用来配置css相关的配置项
CSS: {
postcss: {
plugins: [
//import postCssPxToRem from "postcss-pxtorem"
//npm i postcss-pxtorem 适配移动端配置
// q:postCssPxToRem 为什么不用px2rem-loader
// a:px2rem-loader 会把所有的px都转换成rem,但是有些px不需要转换,比如border-width:1px;这种就不需要转换
postCssPxToRem({ // px转rem
rootValue({ file }) { // 根元素字体大小 rootValue
return file.indexOf('vant') !== -1 ? 37.5 : 75 // vant组件库字体大小为37.5,其他为75
}, // 根元素字体大
propList: ['*'], // 需要转换的属性,这里选择全部都进行转换
selectorBlackList: ['van-'] // 不需要转换的选择器
})
]
}
// modules:'',
// preprocessorOptions: {},
},
// q:JSON配置项有什么用
// a:JSON配置项是用来配置导入json文件的
JSON: {
namedExports: true, // 是否支持从 .json 文件中进行按名导入
stringify: false, // 若设置为 true,性能好,单不支持按名导入
},
// q:esbuild配置项有什么用?
// a:esbuild是一个JavaScript和TypeScript的构建工具,它可以在浏览器中运行,也可以在Node.js中运行,它可以将JavaScript和TypeScript代码转换为更快的JavaScript代码
esbuild: { // esbuild配置项,false为关闭esbuild
include: /\.[jt]sx?$/, // 匹配文件
exclude: /node_modules/, // 排除文件
// jsxInject: `import vue from 'vue'`, // 自动注入到每个jsx文件的顶部
// jsxFactory: 'React.createElement', // 自定义jsx工厂函数
// jsxFragment: 'React.Fragment', // 自定义jsx片段函数
// tsconfigRaw: {}, // 自定义tsconfig.json
// target: 'es2015', // 编译目标
}, // esbuild配置项,false为关闭esbuild
// q:assetsInclude配置项有什么用?
// a:assetsInclude配置项是用来配置静态资源文件夹的,比如你的静态资源文件夹是static,那么你就可以配置assetsInclude: 'static',这样vite就会把static文件夹下的文件都当做静态资源文件处理
assetsInclude: '', // 静态资源文件夹,默认访问路径‘/’, 构建是会放在outDir根目录
logLevel: 'info', // 控制台输出级别,默认info,'info' | 'warn' | 'error' | 'silent'
clearScreen: true, // 清屏, --clearScreen false
envDir: './', //默认 root
server: {
host: '0.0.0.0',
port: 9999, // 端口,若端口被占用时,自动尝试下一个端口
// q:strictPort配置项有什么用?
// a:strictPort配置项是用来配置端口被占用时直接退出的,比如你的端口是9999,但是9999被占用了,那么你就可以配置strictPort: true,这样vite就会直接退出
strictPort: true, // 若端口被占用时直接退出
cssPreprocessOptions: {
less: {
javascriptEnabled: true,
},
},
// q:https配置项有什么用?
// a:https配置项是用来配置https的,比如你的后端接口是https://localhost:3000,那么你就可以配置https: true,这样vite就会把https://localhost:3000作为后端接口
// https: {
// host: 'localhost',
// port: 443,
// key: fs.readFileSync('path/to/key'),
// cert: fs.readFileSync('path/to/cert'),
// },
https: false, // 启用 TLS + HTTP/2 配置,注意:当 server.proxy 选项 也被使用时,将会仅使用 TLS。false则关闭
// open: {
// app: {
// name: 'chrome',
// args: ['--incognito'],
// },
// path: '/foo',
// options: {
// wait: true,
// },
// },
open: '/', // 项目启动时自动打开浏览器,可以设置默认打开的路径
// q:proxy配置项有什么用?
// a:proxy配置项是用来配置代理的,比如你的后端接口是http://localhost:3000,那么你就可以配置proxy: { '/api': 'http://localhost:3000' },这样vite就会把/api开头的请求都代理到http://localhost:3000
proxy: { // 服务器代理 https://github.com/http-party/node-http-proxy#options
'/foo': 'http://localhost:4567/foo',
'/apidd': {
target: loadEnv(mode, process.cwd()).VITE_APP_SERVER_URL,
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, ''),
configure: (proxy, options) => {
// proxy 是 'http-proxy' 的实例
},
},
'^/fallback/.*': { // 正则
target: loadEnv(mode, process.cwd()).VITE_APP_SERVER_FALLBACK_URL,
changeOrigin: true,
rewrite: (path) => path.replace(/^\/fallback/, '')
},
},
cors: true, // 跨域,默认允许任何源 或 {origin: 'http://example.com',optionsSuccessStatus: 200}
//q:force配置项有什么用?
//a:force配置项是用来配置强制依赖预构建的,比如你的项目依赖了vue,那么你就可以配置force: true,这样vite就会把vue预构建
force: false, // 强制依赖预构建
// q:fsServe配置项有什么用?
// a:fsServe配置项是用来配置是否启用文件系统访问的,比如你的项目依赖了vue,那么你就可以配置fsServe: true,这样vite就会把vue预构建
fsServe: { // 配置文件系统访问
root: process.cwd(),
strict: true,
},
// q:hmr配置项有什么用?
// a:hmr配置项是用来配置是否启用热模块替换的,比如你的项目依赖了vue,那么你就可以配置hmr: true,这样vite就会把vue预构建 https://www.cnblogs.com/zhongweiv/p/14488838.html
hmr: true, //禁用或配置 HMR 连接
/**
* {
* protocol?: string,
* host?: string,
* port?: number,
* path?: string,
* timeout?: number,
* overlay?: boolean, // 屏蔽开发服务器错误提示
* clientPort?: number,
* server?: Server
* }
*/
watch: {
usePolling: false, // 是否使用轮询
interval: 100, // 多久检查一次变动
binaryInterval: 300, // 监听二进制文件时的轮询间隔
disableGlobbing: false, // 是否禁用 globbing,如果你的文件夹中有大量文件,可以尝试禁用它
}, //传递给 chokidar 的文件系统监听器选项 ,
middlewareMode: 'html', //
// https://cn.vitejs.dev/guide/ssr.html#setting-up-the-dev-server ======待研究怎么用======
/**
* 以中间件模式创建 Vite 服务器。(不含 HTTP 服务器)
* 'ssr' 将禁用 Vite 自身的 HTML 服务逻辑,因此你应该手动为 index.html 提供服务。
* 'html' 将启用 Vite 自身的 HTML 服务逻辑。
*/
},
// q:build配置项有什么用?
// a:build配置项是用来配置构建的
build: { // 构建
target: 'modules', // 构建目标格式,默认是modules,也可以是esbuild配置项,https://esbuild.github.io/api/#target
outDir: 'dist', // 构建输出路径
assetsDir: 'assets', //静态资源文件夹,和outDir同级
assetsInlineLimit: 4096, // 小于此大小的资源将被内联为 base64 编码,以减少请求数 4096 kb
cssCodeSplit: true, // 运行css文件按chunk拆分,chunk加载时插入,如果false则所有的样式导出为一个css文件
cssPreprocessOptions: { // css预处理器配置项
scss: { // scss预处理器配置项
additionalData: `$injectedColor: orange;` // 注入到每个scss文件的顶部
}, // scss预处理器配置项
less: { // less预处理器配置项
javascriptEnabled: true // 允许在less文件中使用js
},
stylus: { // stylus预处理器配置项
additionalData: `$injectedColor = orange` // 注入到每个stylus文件的顶部
},
}, // css预处理器配置项
// cssModulesOptions: {}, // css模块配置项
// q:sourcemap有什么用?
// a:sourcemap是用来调试的,当你的代码出错时,你可以通过sourcemap找到出错的代码位置
sourcemap: false, // 构建后是否生成sourcemap文件
/*
* true,将会创建一个独立的 source map 文件
* 'inline',source map 将作为一个 data URI 附加在输出文件中
* 'hidden' 的工作原理与 'true' 相似,只是 bundle 文件中相应的注释将不被保留。
*/
rollupOptions: { // rollup配置项 https://rollupjs.org/guide/en/#big-list-of-options
external: ['vue', 'vue-router', 'vuex', 'axios', 'vant'], // 不打包的模块 https://rollupjs.org/guide/en/#external
output: { // 输出配置 https://rollupjs.org/guide/en/#outputoptions
manualChunks: { // 手动拆分代码块 https://rollupjs.org/guide/en/#outputmanualchunks
vue: ['vue', 'vue-router', 'vuex'], // 拆分vue相关的包
vant: ['vant'], // 拆分vant相关的包
axios: ['axios'], // 拆分axios相关的包
},
},
},
// q:commonjsOptions这个配置有什么用?
// a:commonjsOptions是@rollup/plugin-commonjs插件的配置,用于将CommonJS模块转换为ES模块,以便可以在Rollup中使用它们
// q:为什么要转换CommonJS模块?
// a:因为rollup只能打包ES模块,如果要打包CommonJS模块,就需要使用@rollup/plugin-commonjs插件
commonjsOptions: { // @rollup/plugin-commonjs 插件的选项
include: /node_modules/, // 需要转换的模块
exclude: /node_modules\/(?!vite)/, // 不需要转换的模块
sourceMap: false, // 是否生成sourcemap
extensions: ['.js', '.cjs'], // 需要转换的文件后缀
ignoreGlobal: false, // 忽略全局模块
ignore: [], // 忽略的模块
namedExports: {}, // 模块的命名导出
transformMixedEsModules: false, // 是否转换混合的ES模块
esmExternals: false, // 是否将外部模块视为ES模块
requireReturnsDefault: 'auto', // 是否将require()视为返回default属性的函数
}, // @rollup/plugin-commonjs 插件的选项
dynamicImportVarsOptions: {}, // @rollup/plugin-dynamic-import-vars 的选项
// q:lib这个配置有什么用?
// a:lib是用来配置构建为库的
// q:为什么要构建为库?
// a:因为有时候我们需要将一些公共的方法或者组件抽离出来,作为一个独立的库,供其他项目使用
// q:构建为库的配置项有哪些?
// a:https://cn.vitejs.dev/guide/build.html#library-mode
lib: {
entry: path.resolve(__dirname, 'src/index.ts'), // 入口文件
name: 'ViteLib', // 暴露的全局变量
formats: ['es', 'umd'], // 构建的格式
fileName: (format) => `vite-lib.${format}.js`, // 输出的文件名
}, // 构建为库,https://cn.vitejs.dev/guide/build.html#library-mode
/**
* entry 是必须的因为库不能使用 HTML 作为入口。
* name 则是暴露的全局变量,在 formats 包含 'umd' 或 'iife' 时是必须的。
* 默认 formats 是 ['es', 'umd'] 。
* fileName 是输出的包文件名,默认 fileName 是 package.json 的 name 选项,同时,它还可以被定义为参数为 format 的函数。
*/
entry: "./main.ts", // 入口文件
// q:manifest这个配置有什么用?
// a:manifest是一个json文件,记录了构建后的文件名和文件内容的hash值,用于缓存控制
// q:manifest文件是怎么生成的?
// a:manifest文件是在构建时生成的,构建时会根据构建后的文件名和文件内容的hash值生成一个manifest.json文件
// q:manifest文件有什么用?
// a:manifest文件有两个作用,第一是用于缓存控制,第二是用于服务端渲染
// q:manifest文件用于缓存控制是怎么做的?
// a:manifest文件用于缓存控制是通过在html中引入manifest.json文件,然后在html中引入的js文件中通过读取manifest.json文件中的hash值来判断是否需要更新缓存
// q:manifest文件用于服务端渲染是怎么做的?
// a:manifest文件用于服务端渲染是通过在服务端渲染的时候,通过读取manifest.json文件中的hash值来判断是否需要更新缓存
manifest: false,
// q:minify这个配置有什么用?
// a:minify用于压缩构建后的代码
// q:minify这个配置是怎么做的?
// a:minify是在构建时通过rollup-plugin-terser插件来实现的
// q:rollup-plugin-terser这个插件是怎么做的?
// a:rollup-plugin-terser这个插件是通过terser这个库来实现的
// q:terser这个库是怎么做的?
// a:terser这个库是通过esbuild来实现的
// q:esbuild是怎么做的?
// a:esbuild是通过esbuild-wasm来实现的
minify: 'terser', // 构建后是否压缩代码,terser是默认的压缩器,也可以是esbuild配置项,https://esbuild.github.io/api/#minify
TerserOptions: { // esbuild的压缩配置项 https://esbuild.github.io/api/#minify
compress: { // 压缩配置项 https://esbuild.github.io/api/#minify
drop_console: true, // 去掉console
drop_debugger: true, // 去掉debugger
pure_funcs: ['console.log'], // 去掉console.log
},
}, // terser混淆配置项
cleanCssOptions: {}, // clean css 配置项, ======待研究怎么用======
write: true, // 是否允许构建写入磁盘,false一般用在对构建做进一步处理
emptyOutDir: true, // 构建前清库outDir目录
brotliSize: true, //启用/禁用 brotli 压缩大小报告, 大型项目禁用可能提高构建速度
chunkSizeWarningLimit: 500, //chunk 大小警告的限制(以 kbs 为单位
// q:watch这个配置有什么用?
// a:watch是用来监听文件变化的
// q:watch这个配置是怎么做的?
// a:watch是通过rollup的watch选项来实现的
// q:rollup的watch选项是怎么做的?
// a:rollup的watch选项是通过chokidar来实现的
// q:chokidar是怎么做的?
// a:chokidar是通过fs.watch来实现的
// q:fs.watch是怎么做的?
// a:fs.watch是通过fs.watchFile来实现的
// q:fs.watchFile是怎么做的?
// a:fs.watchFile是通过fs.stat来实现的
// q:fs.stat是怎么做的?
// a:fs.stat是通过fs.fstat来实现的
// q:fs.fstat是怎么做的?
// a:fs.fstat是通过fs.open来实现的
// q:fs.open是怎么做的?
// ...
watch: {
clearScreen: true, // 清除屏幕
chokidar: {}, // chokidar的配置项
exclude: [], // 不需要监听的文件
include: [], // 需要监听的文件
usePolling: false, // 是否监听文件变化
interval: 100, // 多久检查一次文件变化
binaryInterval: 300, // 多久检查一次二进制文件变化 https://rollupjs.org/guide/en/#watchoptions
// chokidar: { // chokidar的配置项
// usePolling: true, // 是否监听文件变化
// interval: 100, // 多久检查一次文件变化
// binaryInterval: 300, // 多久检查一次二进制文件变化
// ignoreInitial: true, // 忽略初始添加的文件
// ignored: /node_modules/, // 忽略监听的文件
// awaitWriteFinish: { // 等待文件写入完成后再重新构建
// stabilityThreshold: 2000, // 等待多久
// pollInterval: 100, // 多久检查一次文件变化
// },
// },
}, // watchoptions,https://rollupjs.org/guide/en/#watch-options, 设置为 {} 则会启用 rollup 的监听器,代码改变时自动打包
},
// q:optimizeDeps这个配置有什么用?
// a:optimizeDeps用于优化依赖 https://vitejs.dev/config/#dep-optimization-options
// q:optimizeDeps这个配置是怎么做的?
// a:optimizeDeps是通过rollup-plugin-node-resolve插件来实现的
// q:rollup-plugin-node-resolve这个插件是怎么做的?
// a:rollup-plugin-node-resolve这个插件是通过resolve这个库来实现的
optimizeDeps: { // 依赖优化
// entries, '' | [], // 预构建入口
// exclude: [], // 预构建排查的依赖
// include: [], // 不在 node_modules 中的依赖包预构建
// keepNames:false, //打包器有时需要重命名符号以避免冲突
},
// q:ssr配置项有什么用?
// a:ssr配置项用于服务端渲染
ssr: { // 试验型,没做研究
// external: [], //强制外部化的依赖
// noExternal: '', // 防止外部化的依赖
// target:'node', // SSR 服务器的构建目标
}
}
if (command === 'serve') {
// dev & serve
//vite-plugin-mock
//mock配置
let prodMock = true;
const viteMockServeOptions = {
mockPath: 'mock',
supportTs: false,
ignore: undefined,
watchFiles: true,
localEnabled: command === 'serve',
prodEnabled: command !== 'serve' && prodMock,
injectCode: ``, // prodEnabled=true生效 main.{ts,js}
injectFile: '', // default: path.resolve(process.cwd(),'src/main.{ts,js}')
configPath: '', //default: vite.mock.config.ts
logger: true, //请求是输入日志
}
options.plugins.push(viteMockServe(viteMockServeOptions))
console.log('mock')
} else {
// build
options.plugins.push(viteCompression(viteCompressionOptions))
}
return options
})