feat: 修改Vite插件配置和新增qrcode和pwa插件

This commit is contained in:
fonghehe 2025-09-29 11:00:31 +08:00
parent 1ab51e68d8
commit 37d0474226
31 changed files with 2041 additions and 994 deletions

View File

@ -2,7 +2,7 @@
VITE_USE_MOCK=true
# 是否开启调试工具
VITE_USE_ERUDA=false
VITE_USE_ERUDA=true
# 是否开启压缩
VITE_USE_COMPRESS=false
@ -11,4 +11,7 @@ VITE_USE_COMPRESS=false
VITE_USE_REPORT=false
# 是否开启https
VITE_USE_HTTPS=false
VITE_USE_HTTPS=false
# 是否开启PWA
VITE_USE_PWA=false

View File

@ -11,4 +11,7 @@ VITE_USE_COMPRESS=true
VITE_USE_REPORT=false
# 是否开启https
VITE_USE_HTTPS=false
VITE_USE_HTTPS=false
# 是否开启PWA
VITE_USE_PWA=false

View File

@ -11,4 +11,7 @@ VITE_USE_COMPRESS=true
VITE_USE_REPORT=false
# 是否开启https
VITE_USE_HTTPS=false
VITE_USE_HTTPS=false
# 是否开启PWA
VITE_USE_PWA=false

1
.gitignore vendored
View File

@ -9,6 +9,7 @@ lerna-debug.log*
node_modules
dist
dev-dist
dist-ssr
*.local
.eslintcache

View File

@ -1,6 +1,6 @@
export const API_BASE_URL = '';
export const API_BASE_URL = '/api';
export const MOCK_API_BASE_URL = '';
export const MOCK_API_BASE_URL = '/mock-api';
export const API_TARGET_URL = '';

View File

@ -1,12 +1,12 @@
/**
* @name AutoImportDeps
* @name ConfigAutoImportPlugin
* @description
*/
import AutoImport from 'unplugin-auto-import/vite';
import { VarletUIResolver, VantResolver } from 'unplugin-vue-components/resolvers';
export const AutoImportDeps = () => {
export const ConfigAutoImportPlugin = () => {
return AutoImport({
dts: 'types/auto-imports.d.ts',
imports: [

View File

@ -1,5 +1,5 @@
/**
* @name AutoRegistryComponents
* @name ConfigAutoComponentsPlugin
* @description
*/
@ -7,7 +7,7 @@ import Components from 'unplugin-vue-components/vite';
import { VueUseComponentsResolver, VantResolver, VarletUIResolver } from 'unplugin-vue-components/resolvers';
import NutUIResolver from '@nutui/auto-import-resolver';
export const AutoRegistryComponents = () => {
export const ConfigAutoComponentsPlugin = () => {
return Components({
// dirs: ['src/components'],
extensions: ['vue', 'md'],

View File

@ -1,10 +1,10 @@
/**
* @name ConfigEruda
* @name ConfigErudaPlugin
* @description 便
*/
import eruda from 'vite-plugin-eruda';
import eruda from '@zhaojjiang/vite-plugin-eruda';
export const ConfigEruda = () => {
export const ConfigErudaPlugin = () => {
return eruda();
};

View File

@ -7,20 +7,22 @@ import type { PluginOption } from 'vite';
import vue from '@vitejs/plugin-vue';
import vueJsx from '@vitejs/plugin-vue-jsx';
import { ConfigSvgIconsPlugin } from './svgIcons';
import { AutoRegistryComponents } from './component';
import { AutoImportDeps } from './autoImport';
import { ConfigAutoComponentsPlugin } from './component';
import { ConfigAutoImportPlugin } from './autoImport';
import { ConfigMockPlugin } from './mock';
import { ConfigCompressPlugin } from './compress';
import { ConfigPagesPlugin } from './pages';
import { ConfigRestartPlugin } from './restart';
import { ConfigProgressPlugin } from './progress';
import { ConfigEruda } from './eruda';
import { ConfigErudaPlugin } from './eruda';
import { ConfigImageminPlugin } from './imagemin';
import { ConfigVisualizerConfig } from './visualizer';
import basicSsl from '@vitejs/plugin-basic-ssl';
import { ConfigVisualizerPlugin } from './visualizer';
import { ConfigSslPlugin } from './ssl';
import { ConfigQrcodePlugin } from './qrcode';
import { ConfigPwaPlugin } from './pwa';
export function createVitePlugins(env: ViteEnv, isBuild: boolean) {
const { VITE_USE_MOCK, VITE_USE_ERUDA, VITE_USE_COMPRESS, VITE_USE_REPORT, VITE_USE_HTTPS } = env;
const { VITE_USE_MOCK, VITE_USE_ERUDA, VITE_USE_COMPRESS, VITE_USE_REPORT, VITE_USE_HTTPS, VITE_USE_PWA } = env;
const vitePlugins: (PluginOption | PluginOption[])[] = [
// vue支持
@ -30,10 +32,10 @@ export function createVitePlugins(env: ViteEnv, isBuild: boolean) {
];
// 自动按需引入组件
vitePlugins.push(AutoRegistryComponents());
vitePlugins.push(ConfigAutoComponentsPlugin());
// 自动按需引入依赖
vitePlugins.push(AutoImportDeps());
vitePlugins.push(ConfigAutoImportPlugin());
// 自动生成路由
vitePlugins.push(ConfigPagesPlugin());
@ -44,37 +46,46 @@ export function createVitePlugins(env: ViteEnv, isBuild: boolean) {
// 构建时显示进度条
vitePlugins.push(ConfigProgressPlugin());
// eruda
// svg 图标
vitePlugins.push(ConfigSvgIconsPlugin(isBuild));
// eruda调试工具
if (VITE_USE_ERUDA) {
vitePlugins.push(ConfigEruda());
vitePlugins.push(ConfigErudaPlugin());
}
// rollup-plugin-visualizer
// 打包分析工具
if (VITE_USE_REPORT) {
vitePlugins.push(ConfigVisualizerConfig());
vitePlugins.push(ConfigVisualizerPlugin());
}
// vite-plugin-mock
// 数据 mock
if (VITE_USE_MOCK) {
vitePlugins.push(ConfigMockPlugin(isBuild));
}
// vite-plugin-svg-icons
vitePlugins.push(ConfigSvgIconsPlugin(isBuild));
if (VITE_USE_HTTPS) {
vitePlugins.push(basicSsl());
// 引入模拟 SSl 证书
vitePlugins.push(ConfigSslPlugin());
}
if (VITE_USE_PWA) {
vitePlugins.push(ConfigPwaPlugin());
}
if (isBuild) {
// vite-plugin-imagemin
vitePlugins.push(ConfigImageminPlugin());
// 开启.gz压缩 rollup-plugin-gzip
// 开启.gz压缩
if (VITE_USE_COMPRESS) {
vitePlugins.push(ConfigCompressPlugin());
// 图片压缩
vitePlugins.push(ConfigImageminPlugin());
}
}
if (!isBuild) {
// 开启二维码插件
vitePlugins.push(ConfigQrcodePlugin());
}
return vitePlugins;
}

View File

@ -8,12 +8,7 @@ export const ConfigMockPlugin = (isBuild: boolean) => {
return viteMockServe({
ignore: /^\_/,
mockPath: 'mock',
localEnabled: !isBuild,
prodEnabled: false, //实际开发请关闭,会影响打包体积
// https://github.com/anncwb/vite-plugin-mock/issues/9
injectCode: `
import { setupProdMockServer } from '../mock/_createProdMockServer';
setupProdMockServer();
`,
enable: !isBuild,
logger: !isBuild,
});
};

View File

@ -4,11 +4,11 @@
*/
import Pages from 'vite-plugin-pages';
export const ConfigPagesPlugin = () => {
return Pages({
pagesDir: [{ dir: 'src/pages', baseRoute: '' }],
extensions: ['vue', 'md'],
exclude: ['**/components/*.vue'],
nuxtStyle: true,
dirs: 'src/pages',
extensions: ['vue', 'ts'],
importMode: 'async',
});
};

View File

@ -3,9 +3,8 @@
* @description
*/
import { Plugin } from 'vite';
import progress from 'vite-plugin-progress';
export const ConfigProgressPlugin = () => {
return progress() as Plugin;
return progress();
};

86
build/vite/plugins/pwa.ts Normal file
View File

@ -0,0 +1,86 @@
/**
* @name ConfigPwaPlugin
* @description
*/
import { VitePWA } from 'vite-plugin-pwa';
export const ConfigPwaPlugin = () => {
return VitePWA({
registerType: 'autoUpdate',
includeAssets: ['favicon.svg', 'robots.txt', 'apple-touch-icon.png'],
devOptions: {
enabled: true,
type: 'module',
},
manifest: {
name: 'Vue-H5-Template',
short_name: 'Vue-H5-Template',
description: '一个使用 Vite 和 Vue3构建的应用',
theme_color: '#ffffff',
background_color: '#ffffff',
display: 'standalone',
orientation: 'portrait',
scope: '/',
start_url: '/',
screenshots: [
{
src: 'logo-320.png',
sizes: '320x320',
type: 'image/png',
},
{
src: 'logo-512.png',
sizes: '512x512',
type: 'image/png',
form_factor: 'wide',
},
],
icons: [
{
src: 'logo-320.png',
sizes: '320x320',
type: 'image/png',
},
{
src: 'logo-512.png',
sizes: '512x512',
type: 'image/png',
},
],
},
workbox: {
// 全局模式匹配
globPatterns: ['**/*.{css,js,html,svg,png,ico,txt,woff2}'], // 运行时缓存配置
runtimeCaching: [
{
// API 请求缓存
urlPattern: ({ url }) => url.pathname.startsWith('/api'),
handler: 'CacheFirst',
options: {
cacheName: 'api-cache',
expiration: {
maxEntries: 10,
maxAgeSeconds: 60 * 60 * 24, // 1天
},
cacheableResponse: {
statuses: [0, 200],
},
},
},
{
// 图片缓存
urlPattern: /\.(?:png|jpg|jpeg|svg|gif|webp)$/,
handler: 'CacheFirst',
options: {
cacheName: 'images-cache',
expiration: {
maxEntries: 60,
maxAgeSeconds: 60 * 60 * 24 * 30, // 30天
},
},
},
],
},
});
};

View File

@ -0,0 +1,10 @@
/**
* @name ConfigQrcodePlugin
* @description qrcode插件
*/
import { qrcode } from 'vite-plugin-qrcode';
export const ConfigQrcodePlugin = () => {
return qrcode();
};

10
build/vite/plugins/ssl.ts Normal file
View File

@ -0,0 +1,10 @@
/**
* @name ConfigSslPlugin
* @description SSl
*/
import basicSsl from '@vitejs/plugin-basic-ssl';
export const ConfigSslPlugin = () => {
return basicSsl();
};

View File

@ -1,5 +1,5 @@
/**
* @name SvgIconsPlugin
* @name ConfigSvgIconsPlugin
* @description SVG文件
*/

View File

@ -1,15 +1,16 @@
/**
* @name ConfigVisualizerConfig
* @name ConfigVisualizerPlugin
* @description
*/
import visualizer from 'rollup-plugin-visualizer';
import { visualizer } from 'rollup-plugin-visualizer';
import type { PluginOption } from 'vite';
export function ConfigVisualizerConfig() {
export const ConfigVisualizerPlugin = () => {
return visualizer({
filename: './node_modules/.cache/visualizer/stats.html',
open: true,
gzipSize: true,
brotliSize: true,
}) as Plugin;
}
}) as PluginOption;
};

View File

@ -1,5 +1,6 @@
import { API_BASE_URL, API_TARGET_URL, MOCK_API_BASE_URL, MOCK_API_TARGET_URL } from '../constant';
import { ProxyOptions } from 'vite';
import type { ProxyOptions } from 'vite';
type ProxyTargetList = Record<string, ProxyOptions>;
const init: ProxyTargetList = {
@ -13,7 +14,7 @@ const init: ProxyTargetList = {
[MOCK_API_BASE_URL]: {
target: MOCK_API_TARGET_URL,
changeOrigin: true,
rewrite: (path) => path.replace(new RegExp(`^${MOCK_API_BASE_URL}`), '/api'),
rewrite: (path) => path.replace(new RegExp(`^${MOCK_API_BASE_URL}`), ''),
},
};

View File

@ -7,7 +7,7 @@ interface Response {
export default [
{
url: '/api/login',
url: '/mock-api/login',
method: 'post',
response: ({ body, query }: Response) => {
console.log('body>>>>>>>>', body);

View File

@ -16,37 +16,38 @@
"dependencies": {
"@nutui/icons-vue": "^0.1.1",
"@nutui/nutui": "^4.3.13",
"@varlet/ui": "^3.11.3",
"@vueuse/core": "13.7.0",
"@vueuse/integrations": "13.7.0",
"axios": "1.11.0",
"dayjs": "^1.11.13",
"@varlet/ui": "^3.11.4",
"@vueuse/core": "13.9.0",
"@vueuse/integrations": "13.9.0",
"axios": "1.12.2",
"dayjs": "^1.11.18",
"mitt": "^3.0.1",
"pinia": "^3.0.2",
"pinia-plugin-persistedstate": "^4.5.0",
"universal-cookie": "^8.0.1",
"vant": "^4.9.19",
"vue": "^3.5.20",
"vue-i18n": "^11.1.3",
"vue": "^3.5.22",
"vue-i18n": "^11.1.12",
"vue-router": "^4.5.1"
},
"devDependencies": {
"@commitlint/cli": "^19.7.1",
"@commitlint/config-conventional": "^19.7.1",
"@commitlint/cli": "^20.0.0",
"@commitlint/config-conventional": "^20.0.0",
"@nutui/auto-import-resolver": "^1.0.0",
"@stylistic/stylelint-plugin": "^4.0.0",
"@tsconfig/node22": "^22.0.2",
"@types/jsdom": "^21.1.7",
"@types/node": "^22.18.0",
"@typescript-eslint/parser": "^8.41.0",
"@typescript-eslint/parser": "^8.44.1",
"@vitejs/plugin-basic-ssl": "^2.0.0",
"@vitejs/plugin-legacy": "^7.2.1",
"@vitejs/plugin-vue": "^6.0.1",
"@vitejs/plugin-vue-jsx": "^5.1.0",
"@vitejs/plugin-vue-jsx": "^5.1.1",
"@vue/eslint-config-prettier": "^10.2.0",
"@vue/eslint-config-typescript": "^14.5.0",
"@vue/test-utils": "^2.4.0",
"@vue/tsconfig": "^0.8.1",
"@zhaojjiang/vite-plugin-eruda": "^0.0.5",
"amfe-flexible": "^2.2.1",
"autoprefixer": "^10.4.21",
"cnjm-postcss-px-to-viewport": "^1.0.1",
@ -55,7 +56,7 @@
"cz-git": "^1.11.1",
"czg": "^1.11.1",
"eruda": "^3.4.1",
"eslint": "^9.34.0",
"eslint": "^9.36.0",
"eslint-define-config": "^2.1.0",
"eslint-plugin-import": "^2.31.0",
"eslint-plugin-prettier": "^5.5.4",
@ -64,7 +65,7 @@
"git-cz": "^4.9.0",
"husky": "9.1.7",
"jsdom": "^26.1.0",
"lint-staged": "16.1.5",
"lint-staged": "16.2.1",
"mockjs": "^1.1.0",
"node": "^22.18.0",
"npm-run-all": "^4.1.5",
@ -84,21 +85,22 @@
"stylelint-scss": "^6.11.0",
"terser": "^5.19.0",
"typescript": "5.8.3",
"unplugin-auto-import": "^20.0.0",
"unplugin-vue-components": "^29.0.0",
"vite": "^7.1.3",
"unplugin-auto-import": "^20.2.0",
"unplugin-vue-components": "^29.1.0",
"vite": "^7.1.7",
"vite-plugin-compression": "^0.5.1",
"vite-plugin-eruda": "^1.0.1",
"vite-plugin-imagemin": "^0.6.1",
"vite-plugin-mock": "^3.0.2",
"vite-plugin-pages": "^0.33.0",
"vite-plugin-progress": "^0.0.7",
"vite-plugin-pwa": "^1.0.3",
"vite-plugin-qrcode": "^0.3.0",
"vite-plugin-restart": "^1.0.0",
"vite-plugin-svg-icons": "^2.0.1",
"vite-plugin-vue-setup-extend-plus": "^0.1.0",
"vitest": "^3.1.3",
"vue-eslint-parser": "^10.1.3",
"vue-tsc": "^3.0.6"
"vue-tsc": "^3.0.8"
},
"engines": {
"node": ">=20.10.0",

1764
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@ -1,3 +1,4 @@
// eslint-disable-next-line @typescript-eslint/no-require-imports
const path = require('path');
const judgeComponent = (file) => {

BIN
public/logo-320.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

BIN
public/logo-512.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

View File

@ -5,7 +5,7 @@ import { http } from '@/utils/request';
* @returns UseAxiosReturn
*/
export function loginPassword() {
return http.post(`/api/login`, {
return http.post(`/mock-api/login`, {
data: { name: '123' },
});
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.7 KiB

View File

@ -30,7 +30,7 @@
const userInfo = await userStore.login();
console.log(userInfo);
if (userInfo) {
router.push({ path: '/home' });
router.push({ path: '/member' });
}
} else {
console.log('error submit!!', errors);

View File

@ -8,7 +8,6 @@ export {};
/* prettier-ignore */
declare module 'vue' {
export interface GlobalComponents {
BasicModal: typeof import('./../src/components/Modal/src/BasicModal.vue')['default']
NutAvatar: typeof import('@nutui/nutui')['Avatar']
NutButton: typeof import('@nutui/nutui')['Button']
NutCard: typeof import('@nutui/nutui')['Card']
@ -19,8 +18,6 @@ declare module 'vue' {
NutGrid: typeof import('@nutui/nutui')['Grid']
NutGridItem: typeof import('@nutui/nutui')['GridItem']
NutInput: typeof import('@nutui/nutui')['Input']
NutSwiper: typeof import('@nutui/nutui')['Swiper']
NutSwiperItem: typeof import('@nutui/nutui')['SwiperItem']
NutTabbar: typeof import('@nutui/nutui')['Tabbar']
NutTabbarItem: typeof import('@nutui/nutui')['TabbarItem']
RouterLink: typeof import('vue-router')['RouterLink']

1
types/env.d.ts vendored
View File

@ -1,2 +1,3 @@
// env.d.ts
/// <reference types="vite/client" />
/// <reference types="vite-plugin-pwa/client" />

1
types/global.d.ts vendored
View File

@ -51,6 +51,7 @@ declare global {
VITE_USE_COMPRESS: boolean;
VITE_USE_REPORT: boolean;
VITE_USE_HTTPS: boolean;
VITE_USE_PWA: boolean;
}
declare function parseInt(s: string | number, radix?: number): number;

988
yarn.lock

File diff suppressed because it is too large Load Diff