我用deepseek写了一份关于前端模板配置,惊呆了喔

769 阅读4分钟

这个我是用deepseek搜索,堆砌而成,虽然中间遇到了无数次的"服务器繁忙,请稍后再试",但是经过不断问话以及结合豆包写了一份基础模板配置

功能包含

  • Eslint检查
  • Git提交校验
  • 代码自动修复
  • 图片压缩
  • 别名配置
  • 代码分割
  • 开发可视化调试
  • UI组件自动导入
  • 打包分析
  • html模板注入变量
  • 移除无效日志
  • 原子化css-tailwindcss
  • Node版本控制
  • 包选择器控制
  • 像素转换

文件目录结构

【具体代码-👉】【vue-web-template

vue-web-template/
├── .husky
│   ├── commit-msg               
├── nginx/
│   ├── nginx.conf                
├── public
├── src/
│   ├── app
│   │   ├── admin
│   │   │   ├── router
│   │   │   ├── view
│   │   │   ├── main.js
│   │   ├── web
│   │   │   ├── router
│   │   │   ├── view
│   │   │   ├── http
│   │   │   ├── main.js
│   └── packages
│   │   ├── assets
│   │   ├── components
│   │   ├── config
│   │   ├── helpers
│   │   ├── hooks
│   │   ├── http
│   │   ├── pinia
│   │   ├── style
│   │   ├── utils
│   │   ├── App.vue
│   │   ├── install.js
├── .env.development
├── .env.production
├── .env.staging
├── .gitignore
├── .npmrc
├── index.html
├── admin.html
├── eslint.config.js
├── package.json
├── postcss.config.js
├── preinstall.js
├── tailwind.config.js
├── vite.config.js

如果项目需要格式化执行

npm run eslint

Git结合Eslint拦截

如果没有.husky目录,执行npx husky init

确保文件有可执行权限:chmod +x .husky/pre-commit

提交自动修复

添加一下属性,自动修复--fix --quiet

{
    "lint-staged": {
        "*.{js,jsx,ts,tsx,vue}": [
            "eslint --fix --quiet"
        ]
    }
}

规则校验

  • feat: 新功能(feature)
  • fix: 修补bug
  • docs: 文档(documentation)
  • style: 格式(不影响代码运行的变动)
  • refactor: 重构(即不是新增功能,也不是修改bug的代码变动)
  • chore: 构建过程或辅助工具的变动
  • revert: 撤销,版本回退
  • perf: 性能优化
  • test:测试
  • improvement: 改进
  • build: 打包
  • ci: 持续集成

启用Git校验规则

在当前项目根目录下执行此命令

npx husky add .husky/commit-msg 'npx --no -- commitlint --edit "$1"'

安装包说明

@vueuse/gesture

演示文档

手势组件,图片预览时的捏合缩放 ,导航栏的左右滑动切换 ,列表项的上拉加载更多 ,界面元素的触摸反馈 ,更复杂的滑动手势控制,如卡片翻转等

vconsole

移动端调试库

环境变量

/ 项目根目录
├── .env.development # 开发环境
├── .env.staging # 测试环境
├── .env.production # 生产环境
└── ...

区分PC端和移动端

在mobile模式下,会自定转UI尺寸为rem,以及会加入移动端调试,规则请看配置

VITE_DEVICE_TYPE = pc
VITE_DEVICE_TYPE = mobile
// 通过环境变量判断设备类型
const deviceType = import.meta.env.VITE_DEVICE_TYPE;

if (deviceType === 'pc') {
    // PC 端逻辑
} else {
    // 移动端逻辑
}

dotenvParseVariables

自定将环境的变量转换为适当的 JavaScript 数据类型,VITE_DEBUG=true,转换为布尔值 如果不做此过程得到是true的字符串

const env = loadEnv(mode, process.cwd(), "VITE_");
const parsedEnv = dotenvParseVariables(env);
createHtmlPlugin({
    inject: {
        data: {
            ...parsedEnv,
        },
    },
})

VueDevTools

无需浏览器安装在线调试面板工具,点击定位浏览器的元素,可定位到vscode的指定代码位置

import {defineConfig} from 'vite'
import VueDevTools from 'vite-plugin-vue-devtools'

export default defineConfig({
    plugins: [
        VueDevTools(),
        vue(),
    ],
})

辅助函数

$navigateTo

禁止直接使用 router.push 或 window.location.href,必须通过 navigateTo 跳转

// 内部跳转(单页应用)
navigateTo('/user/123');
// 外部跳转(直接跳转)
navigateTo('https://github.com');
// 新标签页打开
navigateTo('https://github.com', true);

版本控制

控制Node版本和pnpm安装版本,确保开发者使用相同的工具链,避免因环境差异导致的各类问题

使用scripts 中的 preinstall 脚本会在执行 pnpm install 之前运行 preinstall.js 脚本来检查 Node 版本

{
    "engines": {
        "node": ">=18.0.0",
        "pnpm": "^8.0.0"
    },
    "scripts": {
        "preinstall": "node preinstall.js"
    }
}
// 强制使用 pnpm 检查
if (!/pnpm/.test(process.env.npm_execpath)) {
    console.error('\x1b[31m✖ 请使用 pnpm 安装依赖\x1b[0m');
    console.log('\x1b[36m→ 解决方案:\x1b[0m');
    console.log('  1. 安装 pnpm: \x1b[33mnpm i -g pnpm\x1b[0m');
    console.log('  2. 安装依赖: \x1b[33mpnpm install\x1b[0m');
    process.exit(1);
}

// Node.js 版本检查
const MIN_NODE_VERSION = 20;
const [currentMajor] = process.version
    .slice(1)
    .split('.')
    .map(Number);

if (currentMajor < MIN_NODE_VERSION) {
    console.error(
        `\x1b[31m✖ 需要 Node.js v${MIN_NODE_VERSION}+,当前版本为 ${process.version}\x1b[0m`
    );
    console.log('\x1b[36m→ 解决方案:\x1b[0m');
    console.log('  1. 使用 nvm 切换版本:');
    console.log(`     \x1b[33mnvm install ${MIN_NODE_VERSION}\x1b[0m`);
    console.log(`     \x1b[33mnvm use ${MIN_NODE_VERSION}\x1b[0m`);
    process.exit(1);
}

前端监控

使用的是Page Spy,服务端安装好以后,添加以下脚本即可,管理面板安装完成即可有一个对应的ip地址和端口

<!-- PageSpy SDK -->
<script crossorigin="anonymous" src="http://172.16.26.150:6752/page-spy/index.min.js"></script>

<!-- 插件(非必须,但建议使用) -->
<script crossorigin="anonymous" src="http://172.16.26.150:6752/plugin/data-harbor/index.min.js"></script>
<script crossorigin="anonymous" src="http://172.16.26.150:6752/plugin/rrweb/index.min.js"></script>
<script>
    window.$harbor = new DataHarborPlugin();
    window.$rrweb = new RRWebPlugin();
    [window.$harbor, window.$rrweb].forEach(p => {
        PageSpy.registerPlugin(p)
    })
    window.$pageSpy = new PageSpy();
</script>

完整配置

import {defineConfig, loadEnv} from "vite";
import vue from "@vitejs/plugin-vue";
import path from "path";
import AutoImport from "unplugin-auto-import/vite";
import Components from "unplugin-vue-components/vite";
import {NaiveUiResolver} from "unplugin-vue-components/resolvers";
import tailwindcss from "tailwindcss";
import autoprefixer from "autoprefixer";
import eslintPlugin from "vite-plugin-eslint";
import {VantResolver} from "@vant/auto-import-resolver";
import viteImagemin from "vite-plugin-imagemin";
import postcssPxToRem from "postcss-pxtorem";
import {visualizer} from "rollup-plugin-visualizer"
import {fileURLToPath, URL} from "node:url";
import {resolve, dirname} from "node:path";
import history from "connect-history-api-fallback"
import {createHtmlPlugin} from "vite-plugin-html";
import dotenvParseVariables from "dotenv-parse-variables"
import VueDevTools from 'vite-plugin-vue-devtools'

export default defineConfig(({command, mode}) => {
    const env = loadEnv(mode, process.cwd(), "VITE_");
    const parsedEnv = dotenvParseVariables(env);
    const cssPostcssPlugins = [tailwindcss, autoprefixer];
    const isProduction = mode === "production";
    if (env.VITE_DEVICE_TYPE === "mobile") {
        cssPostcssPlugins.push(postcssPxToRem({
            rootValue: 75,
            unitPrecision: 3,
            propList: ["*"],
            selectorBlackList: [".ignore"],
            replace: true,
            mediaQuery: false,
            minPixelValue: 0,
            exclude: /node_modules/
        }));
    }

    const autoImportOptions = {
        imports: [
            "vue",
            {
                "naive-ui": [
                    "useDialog",
                    "useMessage",
                    "useNotification",
                    "useLoadingBar"
                ]
            }
        ],
        resolvers: [VantResolver()],
    };

    const componentsOptions = {
        resolvers: [
            NaiveUiResolver(),
            VantResolver()
        ]
    };

    const eslintOptions = {
        include: ["src/**/*.js", "src/**/*.vue", "src/*.js", "src/*.vue"]
    };

    const imageminOptions = {
        optipng: {
            optimizationLevel: 7
        },
        pngquant: {
            quality: [0.8, 0.9],
        },
        svgo: {
            plugins: [
                {name: "removeViewBox"},
                {name: "removeEmptyAttrs", active: false}
            ]
        }
    };

    const aliasConfig = {
        "@": path.resolve(__dirname, "src"),
        "__ROOT__": path.resolve(__dirname, ""),
    };

    const manualChunksFunction = (id) => {
        if (id.includes("node_modules")) {
            return id.toString().split("node_modules/")[1].split("/")[0];
        }
    };

    const historyPlugin = () => {
        return {
            name: "vite-plugin-history",
            configureServer(server) {
                server.middlewares.use(history({
                    rewrites: [
                        {from: /\/admin/, to: "/admin.html"} // 解决页面 在history 刷新下会 404 的问题
                    ],
                    htmlAcceptHeaders: ["text/html", "application/xhtml+xml"],
                }))
            }
        }
    }

    return {
        base: "./", // 公共基础路径(部署目录)
        plugins: [
            VueDevTools(),
            vue(),
            AutoImport(autoImportOptions),
            Components(componentsOptions),
            eslintPlugin(eslintOptions),
            viteImagemin(imageminOptions),
            // 打包分析插件
            visualizer({
                open: true,
                gzipSize: true,
                brotliSize: true
            }),
            historyPlugin(),
            createHtmlPlugin({
                inject: {
                    data: {
                        ...parsedEnv,
                    },
                },
            })
        ],
        define: {
            __APP_ENV__: JSON.stringify(env.APP_ENV),
        },
        resolve: {
            alias: aliasConfig,
            extensions: [".mjs", ".js", ".ts", ".jsx", ".tsx", ".json", ".vue"]
        },
        build: {
            outDir: "dist",
            sourcemap: false,
            minify: "terser",  // 生产环境移除 console 和 debugger
            terserOptions: {
                compress: {
                    drop_console: isProduction,
                    drop_debugger: isProduction,
                },
            },
            rollupOptions: {
                output: {
                    manualChunks: manualChunksFunction,
                    input: {
                        index: resolve(__dirname, "index.html"),
                        admin: resolve(__dirname, "admin.html")
                    }
                }
            }
        },
        css: {
            postcss: {
                plugins: cssPostcssPlugins
            }
        },
        server: {
            host: "0.0.0.0",
            port: 5173,
            open: false,  // 自动打开浏览器
            proxy: {
                "/api": {
                    target: "http://127.0.0.1:1338",
                    changeOrigin: true,
                },
            },
        }
    };
});