feat(admin): 模板精简+请求层适配 Django JWT
- 克隆 art-design-pro v3.0.2(GitHub depth1),rm .git,pnpm clean:dev 精简演示页(92 文件) - .env.development/.env.production 均设 VITE_API_URL=/api,代理目标 127.0.0.1:8000(移除 Apifox Mock) - http 封装信封适配:code===200 解包 data;msg/message 字段兼容(拦截器/error/类型) - /api/admin/auth/token 登录适配(access->Bearer token, refresh->refreshToken);/api/admin/auth/me 映射 UserInfo(userName/roles/is_admin) - 登录页演示账号替换为真实 admin;logOut 按路由名判登录页修复 redirect 嵌套 - 根 .gitignore 补 !admin/.env(模板公共 env 非密钥,需入库) - 验证:Playwright 全链路(错误密码 401 留登页/正确登录进工作台/登出/受保护路由重定向/redirect 回跳)+ pnpm build(vue-tsc 通过,产物无 mock 域名) Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,156 @@
|
||||
import { defineConfig, loadEnv } from 'vite'
|
||||
import vue from '@vitejs/plugin-vue'
|
||||
import path from 'path'
|
||||
import { fileURLToPath } from 'url'
|
||||
import vueDevTools from 'vite-plugin-vue-devtools'
|
||||
import viteCompression from 'vite-plugin-compression'
|
||||
import Components from 'unplugin-vue-components/vite'
|
||||
import AutoImport from 'unplugin-auto-import/vite'
|
||||
import ElementPlus from 'unplugin-element-plus/vite'
|
||||
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
|
||||
import tailwindcss from '@tailwindcss/vite'
|
||||
// import { visualizer } from 'rollup-plugin-visualizer'
|
||||
|
||||
export default ({ mode }: { mode: string }) => {
|
||||
const root = process.cwd()
|
||||
const env = loadEnv(mode, root)
|
||||
const { VITE_VERSION, VITE_PORT, VITE_BASE_URL, VITE_API_URL, VITE_API_PROXY_URL } = env
|
||||
|
||||
console.log(`🚀 API_URL = ${VITE_API_URL}`)
|
||||
console.log(`🚀 VERSION = ${VITE_VERSION}`)
|
||||
|
||||
return defineConfig({
|
||||
define: {
|
||||
__APP_VERSION__: JSON.stringify(VITE_VERSION)
|
||||
},
|
||||
base: VITE_BASE_URL,
|
||||
server: {
|
||||
port: Number(VITE_PORT),
|
||||
proxy: {
|
||||
'/api': {
|
||||
target: VITE_API_PROXY_URL,
|
||||
changeOrigin: true
|
||||
}
|
||||
},
|
||||
host: true
|
||||
},
|
||||
// 路径别名
|
||||
resolve: {
|
||||
alias: {
|
||||
'@': fileURLToPath(new URL('./src', import.meta.url)),
|
||||
'@views': resolvePath('src/views'),
|
||||
'@imgs': resolvePath('src/assets/images'),
|
||||
'@icons': resolvePath('src/assets/icons'),
|
||||
'@utils': resolvePath('src/utils'),
|
||||
'@stores': resolvePath('src/store'),
|
||||
'@styles': resolvePath('src/assets/styles')
|
||||
}
|
||||
},
|
||||
build: {
|
||||
target: 'es2015',
|
||||
outDir: 'dist',
|
||||
chunkSizeWarningLimit: 2000,
|
||||
minify: 'terser',
|
||||
terserOptions: {
|
||||
compress: {
|
||||
// 生产环境去除 console
|
||||
drop_console: true,
|
||||
// 生产环境去除 debugger
|
||||
drop_debugger: true
|
||||
}
|
||||
},
|
||||
dynamicImportVarsOptions: {
|
||||
warnOnError: true,
|
||||
exclude: [],
|
||||
include: ['src/views/**/*.vue']
|
||||
}
|
||||
},
|
||||
plugins: [
|
||||
vue(),
|
||||
tailwindcss(),
|
||||
// 自动按需导入 API
|
||||
AutoImport({
|
||||
imports: ['vue', 'vue-router', 'pinia', '@vueuse/core'],
|
||||
dts: 'src/types/import/auto-imports.d.ts',
|
||||
resolvers: [ElementPlusResolver()],
|
||||
eslintrc: {
|
||||
enabled: true,
|
||||
filepath: './.auto-import.json',
|
||||
globalsPropValue: true
|
||||
}
|
||||
}),
|
||||
// 自动按需导入组件
|
||||
Components({
|
||||
dts: 'src/types/import/components.d.ts',
|
||||
resolvers: [ElementPlusResolver()]
|
||||
}),
|
||||
// 按需定制主题配置
|
||||
ElementPlus({
|
||||
useSource: true
|
||||
}),
|
||||
// 压缩
|
||||
viteCompression({
|
||||
verbose: false, // 是否在控制台输出压缩结果
|
||||
disable: false, // 是否禁用
|
||||
algorithm: 'gzip', // 压缩算法
|
||||
ext: '.gz', // 压缩后的文件名后缀
|
||||
threshold: 10240, // 只有大小大于该值的资源会被处理 10240B = 10KB
|
||||
deleteOriginFile: false // 压缩后是否删除原文件
|
||||
}),
|
||||
vueDevTools()
|
||||
// 打包分析
|
||||
// visualizer({
|
||||
// open: true,
|
||||
// gzipSize: true,
|
||||
// brotliSize: true,
|
||||
// filename: 'dist/stats.html' // 分析图生成的文件名及路径
|
||||
// }),
|
||||
],
|
||||
// 依赖预构建:避免运行时重复请求与转换,提升首次加载速度
|
||||
optimizeDeps: {
|
||||
include: [
|
||||
'echarts/core',
|
||||
'echarts/charts',
|
||||
'echarts/components',
|
||||
'echarts/renderers',
|
||||
'xlsx',
|
||||
'xgplayer',
|
||||
'crypto-js',
|
||||
'file-saver',
|
||||
'vue-img-cutter',
|
||||
'element-plus/es',
|
||||
'element-plus/es/components/*/style/css',
|
||||
'element-plus/es/components/*/style/index'
|
||||
]
|
||||
},
|
||||
css: {
|
||||
preprocessorOptions: {
|
||||
// sass variable and mixin
|
||||
scss: {
|
||||
additionalData: `
|
||||
@use "@styles/core/el-light.scss" as *;
|
||||
@use "@styles/core/mixin.scss" as *;
|
||||
`
|
||||
}
|
||||
},
|
||||
postcss: {
|
||||
plugins: [
|
||||
{
|
||||
postcssPlugin: 'internal:charset-removal',
|
||||
AtRule: {
|
||||
charset: (atRule) => {
|
||||
if (atRule.name === 'charset') {
|
||||
atRule.remove()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function resolvePath(paths: string) {
|
||||
return path.resolve(__dirname, paths)
|
||||
}
|
||||
Reference in New Issue
Block a user