适用于vue3+pnpm项目自动化类型检查及构建的Python脚本

适用场景

前后端同步开发的时候,需要全流程构建

源码

python 复制代码
#!/usr/bin/env python3
"""
IPAM Frontend - PNPM 构建和验证脚本
实现类型检查、编译验证和代码质量检查
"""

import os
import sys
import json
import time
import subprocess
from pathlib import Path
import argparse
from loguru import logger


def check_pnpm_installed() -> bool:
    """检查 pnpm 是否已安装"""
    logger.info("📋 检查依赖")
    logger.info("   验证 pnpm 是否已安装")

    # 使用os.system进行检测,与build.py保持一致

    pnpm_check_result = os.system("pnpm --version")
    if pnpm_check_result == 0:
        version = subprocess.getoutput("pnpm --version").strip()
        logger.success(f"✅ pnpm已安装 (版本: {version})")
        return True
    else:
        logger.info("ℹ️  安装命令: npm install -g pnpm")
        logger.error("❌ pnpm未安装,请先安装 pnpm")
        sys.exit(1)


def install_dependencies() -> bool:
    """安装依赖"""
    logger.info("📋 安装依赖")
    logger.info("   使用 pnpm install 安装项目依赖")

    try:
        exitCode, output = subprocess.getstatusoutput('pnpm install')

        if exitCode == 0:
            logger.success("✅ 依赖安装成功")
            return True
        else:
            logger.error(f"错误输出: {output}")
            logger.error("❌ 依赖安装失败")
            return False

    except Exception as e:
        logger.error(f"❌ 安装依赖时发生错误: {e}")
        return False


def run_dev_server_test() -> bool:
    """测试开发服务器启动"""
    logger.info("📋 开发服务器测试")
    logger.info("   验证开发服务器可以正常启动")

    # 这里我们只是检查配置,不实际启动服务器
    # 因为启动服务器会阻塞进程

    if os.system('npx vite --version') == 0:
        logger.success("✅ Vite 开发服务器配置正常")
        return True
    else:
        logger.error("❌ Vite 开发服务器配置有问题")
        return False


def run_type_check() -> bool:
    """运行 TypeScript 类型检查和构建验证

    如果任何一个检查步骤发现错误,将立即终止后续检查。
    统一使用os.system执行,避免输出排版混乱。
    """

    # 定义所有检查步骤:title 和 command
    check_steps = [
        {"title": "TypeScript 类型检查", "command": "npx tsc --noEmit"},
        {"title": "TypeScript 类型检查", "command": "pnpm exec tsc --noEmit"},
        {"title": "TypeScript 类型检查", "command": "pnpm run typecheck"},
        {"title": "Vue 严格类型检查", "command": "pnpm run typecheck:strict"},
        {"title": "Vue 文件类型检查", "command": "npx vue-tsc --noEmit"},
        {"title": "Vue SFC 检查", "command": "pnpm run lint:vue"},
        {"title": "Vite 构建类型检查", "command": "npx vite build --mode production"}
    ]

    try:
        # 使用 for 循环执行所有检查步骤
        for step in check_steps:
            title = step["title"]
            command = step["command"]
            desc = f"使用 {command.split()[0]} 进行{title.replace('检查', '')}"

            logger.info(f"📋 {title}")
            logger.info(f"   {desc}")
            if os.system(command) != 0:
                logger.debug(f"执行命令: {command}")
                logger.error(f"❌ {title}失败")
                return False
            logger.success(f"✅ {title}通过")

    except Exception as e:
        logger.error(f"❌ 类型检查过程中发生错误: {e}")
        return False

    # 所有类型检查通过
    logger.info("📋 编译验证")
    logger.info("   类型检查通过,准备编译验证")
    return True


class PNPMRunner:
    """PNPM 脚本运行器"""

    def __init__(self, frontend_dir: str = None):
        self.frontend_dir = Path(frontend_dir or os.getcwd())  # pyright: ignore[reportUnannotatedClassAttribute]
        self.project_root = self.frontend_dir.parent  # pyright: ignore[reportUnannotatedClassAttribute]

    def check_typescript_config(self) -> bool:
        """检查 TypeScript 配置"""
        logger.info("📋 TypeScript 配置检查")
        logger.info("   验证 tsconfig.json 配置")

        tsconfig_path = self.frontend_dir / 'tsconfig.json'
        if not tsconfig_path.exists():
            logger.error("❌ tsconfig.json 文件不存在")
            sys.exit(1)

        try:
            with open(tsconfig_path, 'r', encoding='utf-8') as f:
                config = json.load(f)

            # 检查关键配置
            compiler_options = config.get('compilerOptions', {})

            checks = [
                ('strict', compiler_options.get('strict', False)),
                ('noEmit', compiler_options.get('noEmit', False)),
                ('skipLibCheck', compiler_options.get('skipLibCheck', True)),
            ]

            for key, value in checks:
                status = "启用" if value else "禁用"
                symbol = "✅" if value else "⚠️ "
                logger.info(f"   {symbol} {key}: {status}")

            logger.success("✅ TypeScript 配置检查完成")
            return True

        except json.JSONDecodeError as e:
            logger.error(f"❌ tsconfig.json 格式错误: {e}")
            sys.exit(1)

        except Exception as e:
            logger.error(f"❌ 检查 TypeScript 配置时出错: {e}")
            sys.exit(1)

    def check_bundle_size(self) -> bool:
        """检查构建产物大小"""
        logger.info("📋 构建产物检查")
        logger.info("   检查构建产物体积")

        dist_dir = self.frontend_dir / 'dist'
        if not dist_dir.exists():
            logger.warning("⚠️  dist 目录不存在,跳过大小检查")
            return True

        total_size = 0
        for file_path in dist_dir.rglob('*'):
            if file_path.is_file():
                total_size += file_path.stat().st_size

        size_mb = total_size / (1024 * 1024)

        logger.info(f"ℹ️  构建产物总大小: {size_mb:.2f} MB")

        # 建议的阈值
        if size_mb > 10:
            logger.warning("⚠️  构建产物较大,建议优化")
        else:
            logger.success("✅ 构建产物大小正常")

        return True

    def clean_build(self) -> bool:
        """清理构建产物"""
        logger.info("📋 清理构建产物")
        logger.info("   删除 dist 和 node_modules/.vite")

        dist_dir = self.frontend_dir / 'dist'
        vite_cache = self.frontend_dir / 'node_modules' / '.vite'

        try:
            if dist_dir.exists():
                import shutil
                shutil.rmtree(dist_dir)
                logger.success("✅ 清理 dist 目录")

            if vite_cache.exists():
                import shutil
                shutil.rmtree(vite_cache)
                logger.success("✅ 清理 vite 缓存")

            return True

        except Exception as e:
            logger.error(f"❌ 清理失败: {e}")
            return False

    def run_lint_check(self) -> bool:
        """运行代码质量检查"""
        logger.info("📋 代码质量检查")
        logger.info("   检查项目结构和关键文件")

        # 检查关键文件是否存在
        key_files = [
            'src/main.js',
            'src/App.vue',
            'src/router',
            'src/stores',
            'src/views',
            'src/utils',
            'package.json',
            'vite.config.js',
            'tsconfig.json'
        ]

        missing_files = []
        for file_path in key_files:
            full_path = self.frontend_dir / file_path
            if not full_path.exists():
                missing_files.append(file_path)

        if missing_files:
            logger.warning(f"⚠️  缺少关键文件: {', '.join(missing_files)}")
        else:
            logger.success("✅ 关键文件检查通过")

        # 检查 utils 目录中的工具文件
        utils_dir = self.frontend_dir / 'src' / 'utils'
        if utils_dir.exists():
            utils_files = list(utils_dir.glob('*.ts'))
            logger.info(f"ℹ️  找到 {len(utils_files)} 个工具文件")

        return len(missing_files) == 0

    def start(self, need_build: bool = True) -> bool:
        """启动构建流程

        这个方法提供了一个简单的接口来执行前端构建流程,
        根据need_build参数决定是否需要执行构建步骤:
        - need_build=True: 全流程,包括所有检查和构建步骤
        - need_build=False: 仅检查,包括所有检查步骤但不执行构建

        如果任何一个检查步骤发现错误,将立即终止后续流程。

        Args:
            need_build: 是否需要执行构建步骤,默认值为True

        Returns:
            bool: 构建是否成功
        """
        # self.print_banner()

        start_time = time.time()

        try:

            # 1. 检查 pnpm
            if not check_pnpm_installed():
                logger.error("pnpm 检查失败,终止后续流程")
                return False

            # 2. 安装依赖
            if not install_dependencies():
                logger.error("依赖安装失败,终止后续流程")
                return False

            # 3. 检查 TypeScript 配置
            if not self.check_typescript_config():
                logger.error("❌ TypeScript 配置检查失败,终止后续流程")
                return False

            # 4. 清理构建产物
            if not self.clean_build():
                logger.error("❌ 清理构建产物失败,终止后续流程")
                return False

            # 5. 类型检查
            if not run_type_check():
                logger.error("❌ 类型检查失败,终止后续流程")
                return False

            # 6. Vite 构建检查 (仅在need_build=True时执行)
            if need_build:
                logger.info("📋 Vite 构建类型检查")
                logger.info("   使用 npx vite build --mode production 进行构建验证")
                if os.system("npx vite build --mode production") != 0:
                    logger.error("❌ Vite 构建失败")
                    return False
                logger.success("✅ Vite 构建类型检查通过")

            # 7. 检查构建产物
            if not self.check_bundle_size():
                logger.error("❌ 构建产物检查失败,终止后续流程")
                return False

            # 8. 代码质量检查
            if not self.run_lint_check():
                logger.error("❌ 代码质量检查失败,终止后续流程")
                return False

            # 9. 开发服务器测试
            if not run_dev_server_test():
                logger.error("❌ 开发服务器测试失败,终止后续流程")
                return False

            # 完成
            end_time = time.time()
            duration = end_time - start_time

            logger.success("🎉 构建验证完成!")
            logger.info(f"总耗时: {duration:.2f} 秒")

            return True

        except Exception as e:
            logger.error(f"❌ 构建验证过程中发生错误: {e}")
            return False




def find_frontend_root(start_path: Path = None) -> Path:
    """
    递归查找前端根目录

    遍历所有目录,找到同时存在 package.json、vite.config.ts 文件及 src 目录的目标作为前端根目录

    Args:
        start_path: 开始查找的路径,默认为当前工作目录

    Returns:
        Path: 找到的前端根目录路径

    Raises:
        FileNotFoundError: 未找到符合条件的前端根目录
    """
    if start_path is None:
        start_path = Path.cwd()

    # 需要检查的关键文件和目录
    required_files = ['package.json', 'vite.config.ts']
    required_dir = 'src'

    logger.info(f"开始从 {start_path} 查找前端根目录...")

    # 使用广度优先搜索遍历目录
    from collections import deque
    queue = deque([start_path])

    while queue:
        current_dir = queue.popleft()

        # 检查当前目录是否符合条件
        has_all_files = all((current_dir / file).exists() for file in required_files)
        has_src_dir = (current_dir / required_dir).is_dir()

        if has_all_files and has_src_dir:
            logger.success(f"找到前端根目录: {current_dir}")
            return current_dir

        # 将子目录加入队列继续搜索
        try:
            for item in current_dir.iterdir():
                if item.is_dir() and not item.name.startswith('.') and item.name != 'node_modules':
                    queue.append(item)
        except PermissionError:
            # 跳过无权限访问的目录
            continue

    # 如果遍历完所有目录都没找到,抛出异常
    raise FileNotFoundError(f"未找到包含 {required_files} 和 {required_dir} 目录的前端根目录")


def main():
    """主函数"""
    parser = argparse.ArgumentParser(description='IPAM Frontend PNPM 构建验证工具')
    parser.add_argument(  # pyright: ignore[reportUnusedCallResult]
        'action',
        nargs='?',  # 使参数可选
        default='full',  # 默认执行完整构建
        choices=['full', 'types'],
        type=str,
        help='执行的操作: full(完整构建), types(类型检查)'
    )  # type: ignore
    parser.add_argument(  # pyright: ignore[reportUnusedCallResult]
        '--frontend-dir',
        default=None,
        type=str,
        help='前端项目目录路径'
    )  # type: ignore

    args = parser.parse_args()

    # 智能判断前端目录
    if args.frontend_dir:
        # 如果指定了前端目录,则使用指定的路径
        frontend_path = Path(args.frontend_dir)  # pyright: ignore[reportAny]
        if not frontend_path.exists():
            logger.error(f"❌ 指定的前端目录 {frontend_path} 不存在")
            sys.exit(1)
    else:
        # 如果没有指定前端目录,使用递归查找
        try:
            frontend_path = find_frontend_root()
        except FileNotFoundError as e:
            logger.error(f"❌ {e}")
            sys.exit(1)

    runner = PNPMRunner(str(frontend_path))

    # 保存当前工作目录
    original_cwd = os.getcwd()

    try:
        # 切换到前端目录
        os.chdir(str(frontend_path))
        logger.info(f"切换到前端目录: {frontend_path}")

        # 打印横幅
        logger.info("=" * 60)
        logger.info("🚀 IPAM Frontend - PNPM 构建验证工具")
        logger.info("=" * 60)
        need_build = False
        if str(args.action).lower() == 'full'.lower():
          need_build = True
        success = runner.start(need_build=need_build)
        if success:
            logger.success("✅ 操作执行成功")
            sys.exit(0)
        else:
            logger.error("❌ 操作执行失败")
            sys.exit(1)
    except KeyboardInterrupt:
        logger.warning("操作被用户中断")
        sys.exit(1)
    except Exception as e:
        logger.error(f"执行过程中出现错误: {e}")
    finally:
        # 确保切换回原始目录
        try:
            os.chdir(original_cwd)
            logger.info(f"切换回原始目录: {original_cwd}")
        except Exception as e:
            logger.error(f"切换目录失败: {e}")


if __name__ == '__main__':
    main()

效果

powershell 复制代码
PS D:\Code\gitee\go\系统\dns-go\pure-admin-thin-v6.0.0> python .\pnpm.py
2025-12-17 23:22:53.957 | INFO     | __main__:find_frontend_root:359 - 开始从 D:\Code\gitee\go\系统\dns-go\pure-admin-thin-v6.0.0 查找前端根目录...
2025-12-17 23:22:53.958 | SUCCESS  | __main__:find_frontend_root:373 - 找到前端根目录: D:\Code\gitee\go\系统\dns-go\pure-admin-thin-v6.0.0
2025-12-17 23:22:53.958 | INFO     | __main__:main:432 - 切换到前端目录: D:\Code\gitee\go\系统\dns-go\pure-admin-thin-v6.0.0
2025-12-17 23:22:53.958 | INFO     | __main__:main:435 - ============================================================
2025-12-17 23:22:53.959 | INFO     | __main__:main:436 - 🚀 IPAM Frontend - PNPM 构建验证工具
2025-12-17 23:22:53.959 | INFO     | __main__:main:437 - ============================================================
2025-12-17 23:22:53.959 | INFO     | __main__:check_pnpm_installed:19 - 📋 检查依赖
2025-12-17 23:22:53.959 | INFO     | __main__:check_pnpm_installed:20 -    验证 pnpm 是否已安装
2025-12-17 23:22:54.337 | SUCCESS  | __main__:check_pnpm_installed:27 - ✅ pnpm已安装 (版本: )
2025-12-17 23:22:54.338 | INFO     | __main__:install_dependencies:37 - 📋 安装依赖
2025-12-17 23:22:54.338 | INFO     | __main__:install_dependencies:38 -    使用 pnpm install 安装项目依赖
2025-12-17 23:22:54.545 | SUCCESS  | __main__:install_dependencies:44 - ✅ 依赖安装成功
2025-12-17 23:22:54.545 | INFO     | __main__:check_typescript_config:124 - 📋 TypeScript 配置检查
2025-12-17 23:22:54.545 | INFO     | __main__:check_typescript_config:125 -    验证 tsconfig.json 配置
2025-12-17 23:22:54.546 | INFO     | __main__:check_typescript_config:148 -    ⚠️  strict: 禁用
2025-12-17 23:22:54.546 | INFO     | __main__:check_typescript_config:148 -    ✅ noEmit: 启用
2025-12-17 23:22:54.546 | INFO     | __main__:check_typescript_config:148 -    ✅ skipLibCheck: 启用
2025-12-17 23:22:54.546 | SUCCESS  | __main__:check_typescript_config:150 - ✅ TypeScript 配置检查完成
2025-12-17 23:22:54.547 | INFO     | __main__:clean_build:190 - 📋 清理构建产物
2025-12-17 23:22:54.547 | INFO     | __main__:clean_build:191 -    删除 dist 和 node_modules/.vite
2025-12-17 23:22:54.568 | SUCCESS  | __main__:clean_build:200 - ✅ 清理 dist 目录
2025-12-17 23:22:54.568 | INFO     | __main__:run_type_check:97 - 📋 TypeScript 类型检查
2025-12-17 23:22:54.568 | INFO     | __main__:run_type_check:98 -    使用 npx 进行TypeScript 类型
2025-12-17 23:23:06.914 | SUCCESS  | __main__:run_type_check:103 - ✅ TypeScript 类型检查通过
2025-12-17 23:23:06.914 | INFO     | __main__:run_type_check:97 - 📋 TypeScript 类型检查
2025-12-17 23:23:06.915 | INFO     | __main__:run_type_check:98 -    使用 pnpm 进行TypeScript 类型
2025-12-17 23:23:07.124 | SUCCESS  | __main__:run_type_check:103 - ✅ TypeScript 类型检查通过
2025-12-17 23:23:07.124 | INFO     | __main__:run_type_check:97 - 📋 TypeScript 类型检查
2025-12-17 23:23:07.124 | INFO     | __main__:run_type_check:98 -    使用 pnpm 进行TypeScript 类型
2025-12-17 23:23:07.345 | SUCCESS  | __main__:run_type_check:103 - ✅ TypeScript 类型检查通过
2025-12-17 23:23:07.345 | INFO     | __main__:run_type_check:97 - 📋 Vue 严格类型检查
2025-12-17 23:23:07.345 | INFO     | __main__:run_type_check:98 -    使用 pnpm 进行Vue 严格类型
2025-12-17 23:23:07.581 | SUCCESS  | __main__:run_type_check:103 - ✅ Vue 严格类型检查通过
2025-12-17 23:23:07.582 | INFO     | __main__:run_type_check:97 - 📋 Vue 文件类型检查
2025-12-17 23:23:07.582 | INFO     | __main__:run_type_check:98 -    使用 npx 进行Vue 文件类型
2025-12-17 23:23:20.486 | SUCCESS  | __main__:run_type_check:103 - ✅ Vue 文件类型检查通过
2025-12-17 23:23:20.486 | INFO     | __main__:run_type_check:97 - 📋 Vue SFC 检查
2025-12-17 23:23:20.486 | INFO     | __main__:run_type_check:98 -    使用 pnpm 进行Vue SFC 
2025-12-17 23:23:20.683 | SUCCESS  | __main__:run_type_check:103 - ✅ Vue SFC 检查通过
2025-12-17 23:23:20.683 | INFO     | __main__:run_type_check:97 - 📋 Vite 构建类型检查
2025-12-17 23:23:20.683 | INFO     | __main__:run_type_check:98 -    使用 npx 进行Vite 构建类型
vite v6.3.5 building for production...
Browserslist: browsers data (caniuse-lite) is 6 months old. Please run:
  npx update-browserslist-db@latest
  Why you should do it regularly: https://github.com/browserslist/update-db#readme
╭─────────────────────────────────────────────╮
│ 您好! 欢迎使用 pure-admin 开源项目          │
│ 我们为您精心准备了下面两个贴心的保姆级文档  │
│ https://pure-admin.cn                       │
│ https://pure-admin-utils.netlify.app        │
╰─────────────────────────────────────────────╯
vite v6.3.5 building for production... (x2)
✓ 4 modules transformed.
✓ built in 86ms
✓ 2124 modules transformed.
dist/index.html                                    1.38 kB │ gzip:   0.79 kB
dist/static/png/bg-oEDCYcDF.png                   17.47 kB
dist/static/css/index-CuXHOUNG.css                 0.71 kB │ gzip:   0.29 kB
dist/static/css/index-BwpJ2zvG.css                 0.76 kB │ gzip:   0.32 kB
dist/static/css/ServerStatusCard-BXWi_eVN.css      1.00 kB │ gzip:   0.41 kB
dist/static/css/index-CwweYm2b.css                 1.05 kB │ gzip:   0.44 kB
dist/static/css/index-Dq2LWDcB.css                 1.13 kB │ gzip:   0.50 kB
dist/static/css/index-CoW4IlgW.css                 1.19 kB │ gzip:   0.48 kB
dist/static/css/index-lBbMo2Rz.css                 1.45 kB │ gzip:   0.50 kB
dist/static/css/index-BU2_xh3l.css                 1.51 kB │ gzip:   0.56 kB
dist/static/css/index-BZXwHqyH.css                 1.64 kB │ gzip:   0.52 kB
dist/static/css/index-DELtkfT7.css                 2.06 kB │ gzip:   0.69 kB
dist/static/css/index-DK-BFDeJ.css                 2.09 kB │ gzip:   0.56 kB
dist/static/css/index-DLPS3bnu.css                 2.35 kB │ gzip:   0.73 kB
dist/static/css/index-CsV-WVqV.css                 6.71 kB │ gzip:   1.25 kB
dist/static/css/index-BoJncB2v.css                10.66 kB │ gzip:   2.66 kB
dist/static/css/index-vK_cPLDp.css                12.59 kB │ gzip:   1.84 kB
dist/static/css/index-BwuqdUXz.css                89.23 kB │ gzip:   8.91 kB
dist/static/css/index-DZHeCOjN.css               407.16 kB │ gzip:  62.13 kB
dist/static/js/sse-Dhjr6cTk.js                     0.12 kB │ gzip:   0.13 kB
dist/static/js/fixed-menu-B7zLbfz-.js              0.23 kB │ gzip:   0.20 kB
dist/static/js/database-6w86ZeGl.js                0.23 kB │ gzip:   0.17 kB
dist/static/js/redirect-B--L8EPc.js                0.30 kB │ gzip:   0.24 kB
dist/static/js/time-DyQSDnlA.js                    0.62 kB │ gzip:   0.35 kB
dist/static/js/domain-api-CAqJoWNM.js              0.84 kB │ gzip:   0.36 kB
dist/static/js/user-BXk2TImu.js                    0.87 kB │ gzip:   0.46 kB
dist/static/js/data-formatter-1125vuTK.js          1.65 kB │ gzip:   0.70 kB
dist/static/js/sse-BuRURl0b.js                     2.30 kB │ gzip:   0.80 kB
dist/static/js/index-Br2TOtv0.js                   5.81 kB │ gzip:   2.04 kB
dist/static/js/index-uaiQm_YY.js                   6.53 kB │ gzip:   2.29 kB
dist/static/js/index-DkmO5dFZ.js                   7.50 kB │ gzip:   2.53 kB
dist/static/js/index-B66HAFaa.js                   7.86 kB │ gzip:   3.01 kB
dist/static/js/index-BEE6bx05.js                   9.97 kB │ gzip:   3.81 kB
dist/static/js/index-CKr8-tTK.js                  10.32 kB │ gzip:   2.72 kB
dist/static/js/index-DVjMqkCd.js                  10.85 kB │ gzip:   4.13 kB
dist/static/js/index-CWon3ikp.js                  11.21 kB │ gzip:   3.70 kB
dist/static/js/403-DsJhAKRy.js                    11.67 kB │ gzip:   5.12 kB
dist/static/js/404-1Ck2fgZx.js                    12.77 kB │ gzip:   5.53 kB
dist/static/js/index-BJow6DFB.js                  13.78 kB │ gzip:   4.38 kB
dist/static/js/500-Dmln0DMO.js                    14.75 kB │ gzip:   5.91 kB
dist/static/js/dark-DmnHUM4t.js                   15.58 kB │ gzip:   8.58 kB
dist/static/js/index-CTZitnQn.js                  15.66 kB │ gzip:   5.04 kB
dist/static/js/index-DVbii3Zm.js                  16.56 kB │ gzip:   5.70 kB
dist/static/js/index-DNWph3c8.js                  19.16 kB │ gzip:   6.31 kB
dist/static/js/index-BPNaIIJB.js                  25.95 kB │ gzip:   8.33 kB
dist/static/js/index-BDZNKtfQ.js                  35.89 kB │ gzip:  10.44 kB
dist/static/js/index-BgIdC-wq.js                 424.26 kB │ gzip: 182.96 kB
dist/static/js/index-BlmFNnW-.js               1,284.70 kB │ gzip: 430.59 kB
✓ built in 13.10s
╭───────────────────────────────────────────────────────────╮
│ 🎉 恭喜打包完成(总用时00分13秒,打包后的大小为2.42 MB)  │
╰───────────────────────────────────────────────────────────╯
2025-12-17 23:23:39.111 | SUCCESS  | __main__:run_type_check:103 - ✅ Vite 构建类型检查通过
2025-12-17 23:23:39.111 | INFO     | __main__:run_type_check:110 - 📋 编译验证
2025-12-17 23:23:39.111 | INFO     | __main__:run_type_check:111 -    类型检查通过,准备编译验证
2025-12-17 23:23:39.111 | INFO     | __main__:start:299 - 📋 Vite 构建类型检查
2025-12-17 23:23:39.111 | INFO     | __main__:start:300 -    使用 npx vite build --mode production 进行构建验证
vite v6.3.5 building for production...
Browserslist: browsers data (caniuse-lite) is 6 months old. Please run:
  npx update-browserslist-db@latest
  Why you should do it regularly: https://github.com/browserslist/update-db#readme
╭─────────────────────────────────────────────╮
│ 您好! 欢迎使用 pure-admin 开源项目          │
│ 我们为您精心准备了下面两个贴心的保姆级文档  │
│ https://pure-admin.cn                       │
│ https://pure-admin-utils.netlify.app        │
╰─────────────────────────────────────────────╯
vite v6.3.5 building for production... (x2)
✓ 4 modules transformed.
✓ built in 88ms
✓ 2124 modules transformed.
dist/index.html                                    1.38 kB │ gzip:   0.79 kB
dist/static/png/bg-oEDCYcDF.png                   17.47 kB
dist/static/css/index-CuXHOUNG.css                 0.71 kB │ gzip:   0.29 kB
dist/static/css/index-BwpJ2zvG.css                 0.76 kB │ gzip:   0.32 kB
dist/static/css/ServerStatusCard-BXWi_eVN.css      1.00 kB │ gzip:   0.41 kB
dist/static/css/index-CwweYm2b.css                 1.05 kB │ gzip:   0.44 kB
dist/static/css/index-Dq2LWDcB.css                 1.13 kB │ gzip:   0.50 kB
dist/static/css/index-CoW4IlgW.css                 1.19 kB │ gzip:   0.48 kB
dist/static/css/index-lBbMo2Rz.css                 1.45 kB │ gzip:   0.50 kB
dist/static/css/index-BU2_xh3l.css                 1.51 kB │ gzip:   0.56 kB
dist/static/css/index-BZXwHqyH.css                 1.64 kB │ gzip:   0.52 kB
dist/static/css/index-DELtkfT7.css                 2.06 kB │ gzip:   0.69 kB
dist/static/css/index-DK-BFDeJ.css                 2.09 kB │ gzip:   0.56 kB
dist/static/css/index-DLPS3bnu.css                 2.35 kB │ gzip:   0.73 kB
dist/static/css/index-CsV-WVqV.css                 6.71 kB │ gzip:   1.25 kB
dist/static/css/index-BoJncB2v.css                10.66 kB │ gzip:   2.66 kB
dist/static/css/index-vK_cPLDp.css                12.59 kB │ gzip:   1.84 kB
dist/static/css/index-BwuqdUXz.css                89.23 kB │ gzip:   8.91 kB
dist/static/css/index-DZHeCOjN.css               407.16 kB │ gzip:  62.13 kB
dist/static/js/sse-Dhjr6cTk.js                     0.12 kB │ gzip:   0.13 kB
dist/static/js/fixed-menu-B7zLbfz-.js              0.23 kB │ gzip:   0.20 kB
dist/static/js/database-6w86ZeGl.js                0.23 kB │ gzip:   0.17 kB
dist/static/js/redirect-B--L8EPc.js                0.30 kB │ gzip:   0.24 kB
dist/static/js/time-DyQSDnlA.js                    0.62 kB │ gzip:   0.35 kB
dist/static/js/domain-api-CAqJoWNM.js              0.84 kB │ gzip:   0.36 kB
dist/static/js/user-BXk2TImu.js                    0.87 kB │ gzip:   0.46 kB
dist/static/js/data-formatter-1125vuTK.js          1.65 kB │ gzip:   0.70 kB
dist/static/js/sse-BuRURl0b.js                     2.30 kB │ gzip:   0.80 kB
dist/static/js/index-Br2TOtv0.js                   5.81 kB │ gzip:   2.04 kB
dist/static/js/index-uaiQm_YY.js                   6.53 kB │ gzip:   2.29 kB
dist/static/js/index-DkmO5dFZ.js                   7.50 kB │ gzip:   2.53 kB
dist/static/js/index-B66HAFaa.js                   7.86 kB │ gzip:   3.01 kB
dist/static/js/index-BEE6bx05.js                   9.97 kB │ gzip:   3.81 kB
dist/static/js/index-CKr8-tTK.js                  10.32 kB │ gzip:   2.72 kB
dist/static/js/index-DVjMqkCd.js                  10.85 kB │ gzip:   4.13 kB
dist/static/js/index-CWon3ikp.js                  11.21 kB │ gzip:   3.70 kB
dist/static/js/403-DsJhAKRy.js                    11.67 kB │ gzip:   5.12 kB
dist/static/js/404-1Ck2fgZx.js                    12.77 kB │ gzip:   5.53 kB
dist/static/js/index-BJow6DFB.js                  13.78 kB │ gzip:   4.38 kB
dist/static/js/500-Dmln0DMO.js                    14.75 kB │ gzip:   5.91 kB
dist/static/js/dark-DmnHUM4t.js                   15.58 kB │ gzip:   8.58 kB
dist/static/js/index-CTZitnQn.js                  15.66 kB │ gzip:   5.04 kB
dist/static/js/index-DVbii3Zm.js                  16.56 kB │ gzip:   5.70 kB
dist/static/js/index-DNWph3c8.js                  19.16 kB │ gzip:   6.31 kB
dist/static/js/index-BPNaIIJB.js                  25.95 kB │ gzip:   8.33 kB
dist/static/js/index-BDZNKtfQ.js                  35.89 kB │ gzip:  10.44 kB
dist/static/js/index-BgIdC-wq.js                 424.26 kB │ gzip: 182.96 kB
dist/static/js/index-BlmFNnW-.js               1,284.70 kB │ gzip: 430.59 kB
✓ built in 12.30s
╭───────────────────────────────────────────────────────────╮
│ 🎉 恭喜打包完成(总用时00分12秒,打包后的大小为2.42 MB)  │
╰───────────────────────────────────────────────────────────╯
2025-12-17 23:23:55.804 | SUCCESS  | __main__:start:304 - ✅ Vite 构建类型检查通过
2025-12-17 23:23:55.804 | INFO     | __main__:check_bundle_size:163 - 📋 构建产物检查
2025-12-17 23:23:55.804 | INFO     | __main__:check_bundle_size:164 -    检查构建产物体积
2025-12-17 23:23:55.822 | INFO     | __main__:check_bundle_size:178 - ℹ️  构建产物总大小: 2.42 MB
2025-12-17 23:23:55.822 | SUCCESS  | __main__:check_bundle_size:184 - ✅ 构建产物大小正常
2025-12-17 23:23:55.822 | INFO     | __main__:run_lint_check:215 - 📋 代码质量检查
2025-12-17 23:23:55.822 | INFO     | __main__:run_lint_check:216 -    检查项目结构和关键文件
2025-12-17 23:23:55.823 | SUCCESS  | __main__:run_lint_check:240 - ✅ 关键文件检查通过
2025-12-17 23:23:55.824 | INFO     | __main__:run_lint_check:246 - ℹ️  找到 17 个工具文件
2025-12-17 23:23:55.824 | INFO     | __main__:run_dev_server_test:58 - 📋 开发服务器测试
2025-12-17 23:23:55.824 | INFO     | __main__:run_dev_server_test:59 -    验证开发服务器可以正常启动
vite/6.3.5 win32-x64 node-v22.15.0
2025-12-17 23:23:57.285 | SUCCESS  | __main__:run_dev_server_test:65 - ✅ Vite 开发服务器配置正常
2025-12-17 23:23:57.285 | SUCCESS  | __main__:start:325 - 🎉 构建验证完成!
2025-12-17 23:23:57.285 | INFO     | __main__:start:326 - 总耗时: 63.33 秒
2025-12-17 23:23:57.285 | SUCCESS  | __main__:main:443 - ✅ 操作执行成功
2025-12-17 23:23:57.285 | INFO     | __main__:main:457 - 切换回原始目录: D:\Code\gitee\go\系统\dns-go\pure-admin-thin-v6.0.0
PS D:\Code\gitee\go\系统\dns-go\pure-admin-thin-v6.0.0> 
相关推荐
应用市场8 小时前
汽车CAN总线隔离设计与故障诊断:从原理到代码实战
开发语言·汽车·无人机
我爱烤冷面8 小时前
kotlin项目实现Java doc的方案:使用Dokka
java·开发语言·kotlin·dokka
历程里程碑8 小时前
C++ 4:内存管理
java·c语言·开发语言·数据结构·c++·笔记·算法
EAIReport8 小时前
基于AI的全国蔬菜供应与价格预测PPT自动化生成方案
人工智能·自动化·powerpoint
LXS_3578 小时前
Day17 C++提高 之 类模板案例
开发语言·c++·笔记·算法·学习方法
leo__5208 小时前
基于MATLAB实现的鲁棒性音频数字水印系统
开发语言·matlab·音视频
2301_789015628 小时前
C++:多态(面向对象的主要手段之一)
c语言·开发语言·c++·多态
小年糕是糕手8 小时前
【C++】string类(一)
linux·开发语言·数据结构·c++·算法·leetcode·改行学it
小小鸟0088 小时前
Vue响应式原理
前端·javascript·vue.js