普通视图

发现新文章,点击刷新页面。
今天 — 2026年1月28日首页

vue3+vite+ts创建项目-企业级

2026年1月28日 12:23

Vue3+Vite+TS 企业级项目搭建完整指南(含多环境配置)

本文基于 Vue3、Vite4+、TypeScript 构建企业级项目,整合多环境配置、代码规范、自动导入、样式处理等核心功能,配置结构清晰可扩展,适配生产、开发、测试多场景需求。

一、初始化 Vue3 项目

采用 Vite 构建工具(比 Webpack 启动更快、热更新更高效,是 Vue3 官方推荐方案),快速初始化项目并集成 TypeScript。

步骤 1:执行初始化命令

# 使用 npm/cnpm/pnpm 均可,这里以 cnpm 为例
cnpm create vite@latest

# 若需指定版本,可执行:cnpm create vite

步骤 2:交互式配置项目

  1. 输入项目名:如 vite-vue3-ts-enterprise(建议英文,避免特殊字符)
  2. 选择框架:上下键切换至 Vue(默认适配 Vue3)
  3. 选择变体:切换至 TypeScript(集成 TS 类型校验)

步骤 3:安装依赖并启动项目

# 进入项目目录
cd vite-vue3-ts-enterprise

# 安装依赖(优先用项目包管理器,避免版本冲突)
cnpm install

# 启动开发环境
cnpm run dev

启动成功后,访问 http://localhost:5173 即可看到 Vue3 初始页面。Vite 默认端口为 5173,后续可在配置中修改。

二、基础配置(环境、别名、类型)

完善项目基础配置,解决路径别名、Node 类型、环境变量加载等核心问题,适配企业级开发习惯。

步骤 1:安装 Node 类型依赖

为 TS 提供 Node 环境类型定义,避免路径处理等操作时 TS 报错。

cnpm i @types/node --save-dev

步骤 2:配置 tsconfig.json

优化 TS 编译规则,添加路径别名、类型目录等配置,确保 TS 语法兼容 Vue3 单文件组件(SFC)。

{
  "compilerOptions": {
    "typeRoots": [
      "node_modules/@types", // 默认类型目录
      "src/types" // 自定义类型目录(后续可存放全局类型)
    ],
    "target": "ESNext", // 目标 ES 版本
    "useDefineForClassFields": true, // 适配 Vue3 类组件
    "module": "ESNext", // 模块规范
    "moduleResolution": "Node", // 模块解析方式
    "strict": true, // 开启严格模式(强制类型校验)
    "jsx": "preserve", // 保留 JSX 语法(适配 Vue3 JSX/TSX)
    "resolveJsonModule": true, // 允许导入 JSON 文件
    "isolatedModules": true, // 确保每个文件都是独立模块(Vite 要求)
    "esModuleInterop": true, // 兼容 CommonJS 模块
    "lib": ["ESNext", "DOM"], // 引入 ES 特性和 DOM 类型
    "skipLibCheck": true, // 跳过第三方库类型校验(提升编译速度)
    "noEmit": true, // 不生成编译产物(Vite 负责构建)
    "baseUrl": "./", // 基础路径
    "paths": { // 路径别名(简化导入,避免相对路径嵌套)
      "@": ["src"],
      "@/*": ["src/*"]
    }
  },
  "include": [ // 需要 TS 校验的文件
    "src/**/*.ts",
    "src/**/*.d.ts",
    "src/**/*.tsx",
    "src/**/*.vue",
    "build/**/*" // 新增:让 TS 识别 build 文件夹下的配置文件
  ],
  "references": [
    { "path": "./tsconfig.node.json" } // 关联 Node 环境配置
  ]
}

步骤 3:配置多环境变量(env 文件夹)

创建独立 env 文件夹管理不同环境变量,实现开发、测试、生产环境隔离,避免硬编码。

1. 创建 env 文件夹及配置文件

# 根目录创建 env 文件夹
mkdir env

# 新建 3 个环境配置文件(对应开发、测试、生产)
touch env/.env.development
touch env/.env.test
touch env/.env.production

2. 编写各环境变量

Vite 环境变量需以 VITE_ 为前缀,否则无法在业务代码中访问。

  • env/.env.development(开发环境) # 开发环境 API 基础地址 `` VITE_API_BASE_URL=http://localhost:3000/api `` # 环境标识 `` VITE_ENV=development `` # 调试模式(开发环境开启) ``VITE_DEBUG=true
  • env/.env.test(测试环境) VITE_API_BASE_URL=https://test.api.example.com `` VITE_ENV=test ``VITE_DEBUG=false
  • env/.env.production(生产环境) VITE_API_BASE_URL=https://api.example.com `` VITE_ENV=production ``VITE_DEBUG=false

步骤 4:拆分多环境 Vite 配置(build 文件夹)

将 Vite 配置拆分为「基础配置+环境专属配置」,统一放入 build 文件夹,提升可维护性,后续新增环境可快速扩展。

1. 创建 build 文件夹及配置文件

# 根目录创建 build 文件夹(集中管理所有配置)
mkdir build

# 新建 3 个配置文件
touch build/vite.base.ts # 基础通用配置
touch build/vite.dev.ts  # 开发环境配置
touch build/vite.prod.ts # 生产环境配置

调整后根目录核心结构:

vite-vue3-ts-enterprise/
├── build/               # 配置文件目录
│   ├── vite.base.ts     # 基础配置(通用逻辑)
│   ├── vite.dev.ts      # 开发环境专属配置
│   └── vite.prod.ts     # 生产环境专属配置
├── env/                 # 环境变量目录
├── src/                 # 业务代码目录
├── public/              # 静态资源目录
├── package.json
├── tsconfig.json
└── tsconfig.node.json

2. 编写 build 文件夹下的配置文件

(1)build/vite.base.ts(基础通用配置)

抽取所有环境共用逻辑,如插件、别名、环境变量目录、静态资源处理等。

import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue'; // Vue 单文件组件插件
import vueJsx from '@vitejs/plugin-vue-jsx'; // 支持 Vue3 JSX/TSX
import path from 'path';

export default defineConfig({
  // 环境变量目录(指定 env 文件夹,而非默认根目录)
  envDir: path.resolve(__dirname, '../env'),
  // 插件配置(所有环境共用插件)
  plugins: [
    vue(), // 解析 .vue 文件
    vueJsx() // 解析 .jsx/.tsx 文件
  ],
  // 路径解析配置
  resolve: {
    alias: {
      // 别名 @ 指向 src 目录(与 tsconfig.json 保持一致)
      '@': path.resolve(__dirname, '../src')
    }
  },
  // 基础构建配置
  build: {
    outDir: path.resolve(__dirname, '../dist'), // 打包输出目录
    assetsDir: 'assets', // 静态资源存放目录
    rollupOptions: {
      // 静态资源分类打包(按后缀名分组)
      output: {
        assetFileNames: (assetInfo) => {
          if (assetInfo.name?.endsWith('.css')) {
            return 'css/[name].[hash:8].[ext]';
          }
          if (assetInfo.name?.match(/.(png|jpg|jpeg|gif|svg)$/i)) {
            return 'images/[name].[hash:8].[ext]';
          }
          return 'assets/[name].[hash:8].[ext]';
        },
        // JS 文件分类打包
        chunkFileNames: 'js/chunks/[name].[hash:8].js',
        entryFileNames: 'js/[name].[hash:8].js'
      }
    }
  }
});
(2)build/vite.dev.ts(开发环境配置)

补充开发环境独有逻辑,如热更新、代理、端口配置等,优化开发体验。

import { defineConfig ,mergeConfig} from 'vite';
import path from 'path';
import baseConfig from './vite.base';

export default mergeConfig(
  baseConfig,
  defineConfig({
    mode: 'development', // 开发模式
    server: {
      port: 8080, // 自定义开发端口(替换默认 5173)
      open: true, // 启动后自动打开浏览器
      hmr: { // 热模块替换(提升热更新速度)
        host: 'localhost',
        port: 8080
      },
      proxy: { // 接口代理(解决跨域问题)
        '/api': {
          target: process.env.VITE_API_BASE_URL, // 读取环境变量中的 API 地址
          changeOrigin: true, // 开启跨域代理
          rewrite: (path) => path.replace(/^/api/, '') // 重写路径(移除前缀 /api)
        }
      }
    },
    css: {
      devSourcemap: true // 开发环境生成 CSS SourceMap(便于调试样式)
    }
  })
);
(3)build/vite.prod.ts(生产环境配置)

补充生产环境优化逻辑,如压缩、清除控制台、SourceMap 控制等,提升打包产物性能。

import { defineConfig ,mergeConfig} from 'vite';
import { visualizer } from 'rollup-plugin-visualizer'; // 打包分析插件
import baseConfig from './vite.base';

export default mergeConfig(
  baseConfig,
  defineConfig({
    mode: 'production', // 生产模式
    build: {
      minify: 'terser', // 使用 terser 压缩代码(比默认 esbuild 压缩更彻底)
      sourcemap: false, // 生产环境关闭 SourceMap(保护源码,减小包体积)
      terserOptions: {
        compress: {
          drop_console: true, // 清除控制台打印(生产环境可选)
          drop_debugger: true // 清除 debugger 语句
        }
      }
    },
    plugins: [
      // 打包分析插件(可选,生成可视化报告,优化包体积)
      visualizer({
        open: false, // 不自动打开报告
        filename: path.resolve(__dirname, '../dist/analysis.html')
      })
    ]
  })
);

4. 更新 package.json 脚本

修改启动、打包脚本,指向 build 文件夹下的对应配置文件,实现按环境加载配置。

"scripts": {
  "dev": "vite --config build/vite.dev.ts", // 启动开发环境
  "build:dev": "vue-tsc -b && vite build --config build/vite.dev.ts", // 开发环境打包(测试用)
  "build:test": "vue-tsc -b && vite build --config build/vite.prod.ts --mode test", // 测试环境打包
  "build:prod": "vue-tsc -b && vite build --config build/vite.prod.ts", // 生产环境打包
  "type-check": "vue-tsc --noEmit", // TS 类型校验(不生成产物)
  "preview": "vite preview" // 预览打包产物
}

vue-tsc -b 用于在打包前执行 TS 类型校验,若存在类型错误则终止打包,避免带错上线;--mode 参数用于指定环境,匹配 env 文件夹下的配置文件。

三、集成代码规范工具(ESLint + Prettier)

统一代码风格,减少团队协作冲突,自动修复格式问题,确保代码质量。需先在 VS Code 安装 ESLintPrettier 插件。

步骤 1:安装依赖

# ESLint 核心及 Vue/TS 适配依赖
cnpm i eslint @eslint/js typescript-eslint @typescript-eslint/parser @typescript-eslint/plugin eslint-plugin-vue vue-eslint-parser -D

# Prettier 及 ESLint 兼容依赖(解决两者规则冲突)
cnpm i prettier eslint-config-prettier eslint-plugin-prettier -D

# Vite ESLint 插件(开发时实时校验)
cnpm i vite-plugin-eslint -D

步骤 2:配置 ESLint(eslint.config.js)

ESLint 8.21.0+ 支持扁平配置文件,适配 Vue3+TS 语法,集成 Prettier 规则。

import globals from "globals";
import pluginJs from "@eslint/js";
import tseslint from "typescript-eslint";
import pluginVue from "eslint-plugin-vue";
import prettier from "eslint-plugin-prettier";
import prettierConfig from "eslint-config-prettier";
import eslintParser from "vue-eslint-parser";

export default [
  // 配置忽略文件(替代传统 .eslintignore)
  {
    ignores: [
      "node_modules/**",
      "dist/**",
      "public/**",
      "build/**",
      "src/assets/**",
      "*.config.js",
      "*.config.ts"
    ]
  },
  // 基础配置(适配 Vue/TS 文件)
  {
    files: ["**/*.{js,mjs,cjs,vue,ts,tsx}"],
    languageOptions: {
      parser: eslintParser, // 解析 Vue 单文件组件
      parserOptions: {
        parser: "@typescript-eslint/parser", // 解析 TS 语法
        ecmaVersion: 2020,
        sourceType: "module"
      },
      globals: { ...globals.browser, ...globals.node } // 全局变量
    },
    plugins: {
      vue: pluginVue,
      "@typescript-eslint": tseslint.plugin,
      prettier: prettier // 集成 Prettier
    },
    rules: {
      // 基础规则
      "no-var": "error", // 禁止使用 var
      "no-console": process.env.NODE_ENV === "production" ? "error" : "off", // 生产环境禁止 console
      "no-multiple-empty-lines": ["warn", { max: 1 }], // 最多允许 1 行空行
      
      // Vue 规则
      "vue/multi-word-component-names": "off", // 关闭组件名多单词校验(灵活命名)
      "vue/valid-template-root": "off", // 允许模板根节点多元素
      
      // TS 规则
      "@typescript-eslint/no-explicit-any": "off", // 允许使用 any(可选,根据团队规范调整)
      "no-unused-vars": ["error", { "varsIgnorePattern": "Vue" }], // 忽略 Vue 未使用警告
      
      // Prettier 规则(将 Prettier 错误作为 ESLint 错误提示)
      "prettier/prettier": "error"
    }
  },
  // 集成推荐规则
  pluginJs.configs.recommended,
  ...tseslint.configs.recommended,
  ...pluginVue.configs["flat/essential"],
  ...pluginVue.configs["flat/recommended"],
  prettierConfig // 覆盖 ESLint 与 Prettier 冲突的规则
];

步骤 3:配置 Prettier(.prettierrc.js)

定义代码格式化规则,与 ESLint 规则兼容,统一团队代码风格。

module.exports = {
  printWidth: 80, // 一行最多 80 字符
  tabWidth: 2, // 2 个空格缩进(与 Vue 官方一致)
  useTabs: false, // 不使用 Tab 缩进
  semi: true, // 行尾添加分号
  singleQuote: true, // 使用单引号
  quoteProps: "as-needed", // 对象 key 仅必要时加引号
  jsxSingleQuote: false, // JSX 中使用双引号
  trailingComma: "all", // 对象/数组末尾添加逗号(便于 diff)
  bracketSpacing: true, // 大括号内保留空格 { foo: bar }
  jsxBracketSameLine: false, // JSX 闭合标签换行
  arrowParens: "always", // 箭头函数单参数也加括号 (x) => x
  endOfLine: "auto" // 自动适配系统换行符
};

步骤 4:配置 VS Code 自动格式化(.vscode/settings.json)

实现保存时自动修复 ESLint 错误并执行 Prettier 格式化,提升开发效率。

{
  "eslint.enable": true,
  "eslint.format.enable": true,
  "editor.quickSuggestions": true,
  "eslint.validate": ["javascript", "javascriptreact", "vue-html", "typescript", "html", "vue"],
  "eslint.options": {
    "extensions": [".js", ".jsx", ".ts", ".tsx", ".vue"]
  },
  "editor.formatOnSave": true, // 保存时格式化
  "editor.codeActionsOnSave": {
    "source.fixAll.eslint": "explicit" // 保存时自动修复 ESLint 错误
  },
  // 不同文件指定默认格式化工具
  "editor.defaultFormatter": "esbenp.prettier-vscode",
  "[vue]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode"
  },
  "[typescript]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode"
  }
}

步骤 5:添加脚本命令

"scripts": {
  // 新增 ESLint/Prettier 命令
  "lint": "eslint "src/**/*.{js,ts,vue,tsx}" --fix", // 自动修复 ESLint 错误
  "prettier": "prettier --write "src/**/*.{js,ts,vue,tsx,json,css}"" // 自动格式化
}

四、集成 Git 提交规范(Husky + Lint-Staged + CommitLint)

约束 Git 提交信息,在提交前校验代码规范,避免不合格代码入库,保障代码仓库整洁。

步骤 1:初始化 Git 仓库(若未初始化)

git init

步骤 2:安装依赖

# Husky(Git Hook 工具)、Lint-Staged(暂存区代码校验)
cnpm i husky@9.1.2 lint-staged@^15.2.7 -D

# CommitLint(提交信息校验)
cnpm i @commitlint/cli@^19.3.0 @commitlint/config-conventional@^19.2.2 -D

步骤 3:配置 Husky

# 生成 .husky 文件夹(存储 Git Hook 脚本)
npx husky init

# 手动创建 pre-commit(提交前校验)和 commit-msg(提交信息校验)脚本
touch .husky/pre-commit
touch .husky/commit-msg

步骤 4:编写 Hook 脚本

  • .husky/pre-commit(提交前校验暂存区代码) #!/bin/sh `` . "$(dirname -- "$0")/_/husky.sh" ```` echo -e "\033[33m ------------- 正在校验暂存区代码规范 ---------------- \033[0m" ``npx --no-install lint-staged
  • .husky/commit-msg(校验提交信息格式) #!/bin/sh `` . "$(dirname -- "$0")/_/husky.sh" ```` echo -e "\033[33m ------------- 正在校验提交信息格式 ---------------- \033[0m" ``npx --no-install commitlint --edit "$1"

步骤 5:配置 Lint-Staged(package.json)

仅对暂存区代码执行校验和格式化,提升效率(避免全量校验)。

"lint-staged": {
  "src/**/*.{vue,js,jsx,ts,tsx}": [
    "eslint --fix", // 自动修复 ESLint 错误
    "prettier --write" // 格式化代码
  ],
  "src/**/*.{cjs,json,css}": [
    "prettier --write" // 格式化配置文件和样式文件
  ]
}

步骤 6:配置 CommitLint(commitlint.config.cjs)

由于 package.json 默认为 ES 模块,需用 .cjs 后缀声明 CommonJS 格式。

module.exports = {
  ignores: [commit => commit.includes('init')], // 忽略 init 初始化提交
  extends: ['@commitlint/config-conventional'], // 基础规范
  rules: {
    'body-leading-blank': [2, 'always'], // 提交描述主体前空行
    'footer-leading-blank': [1, 'always'], // 底部说明前空行
    'header-max-length': [2, 'always', 108], // 标题最大长度 108
    'subject-empty': [2, 'never'], // 标题不可为空
    'type-empty': [2, 'never'], // 类型不可为空
    'type-enum': [ // 允许的提交类型(规范提交场景)
      2,
      'always',
      [
        'wip', // 开发中
        'feat', // 新增功能
        'fix', // 修复 Bug
        'test', // 测试相关
        'refactor', // 代码重构
        'build', // 构建配置(如依赖、打包)
        'docs', // 文档更新
        'perf', // 性能优化
        'style', // 代码风格(不影响逻辑)
        'ci', // 持续集成配置
        'chore', // 琐事(如配置文件修改)
        'revert', // 回滚代码
        'types', // 类型声明更新
        'release' // 版本发布
      ]
    ]
  }
};

提交格式规范

git commit -m "<type>[optional scope]: <description>"

# 示例
git commit -m "feat[user]: 新增用户登录功能"
git commit -m "fix[api]: 修复用户列表接口跨域问题"

说明:type 为提交类型(必填),optional scope 为涉及模块(可选),description 为提交描述(必填,简洁明了)。

五、Vue3 专属插件集成(提升开发效率)

步骤 1:自动导入(API/组件)

无需手动导入 Vue 内置 API(如 ref、reactive)和全局组件,减少模板代码。

# 安装自动导入插件
cnpm i unplugin-auto-import unplugin-vue-components -D

# 若使用 UI 库(如 Ant Design Vue),需安装对应解析器
cnpm i unplugin-vue-components/resolvers -D

更新 build/vite.base.ts,添加插件配置:

import AutoImport from 'unplugin-auto-import/vite';
import Components from 'unplugin-vue-components/vite';
import { AntDesignVueResolver } from 'unplugin-vue-components/resolvers'; // AntD Vue 解析器

export default defineConfig({
  plugins: [
    // ... 原有插件
    // 自动导入 Vue API
    AutoImport({
      imports: ['vue', 'vue-router', 'pinia'], // 自动导入的库
      dts: path.resolve(__dirname, '../src/auto-imports.d.ts'), // 生成类型声明文件
      eslintrc: {
        enabled: true // 生成 ESLint 配置,避免未导入警告
      }
    }),
    // 自动导入组件
    Components({
      dirs: [path.resolve(__dirname, '../src/components')], // 自定义组件目录
      extensions: ['vue', 'tsx'], // 组件后缀
      dts: path.resolve(__dirname, '../src/components.d.ts'), // 生成组件类型声明
      resolvers: [AntDesignVueResolver({ importStyle: false })], // UI 库组件自动导入
    })
  ]
});

步骤 2:PX 转 REM(适配多端)

实现移动端自适应,将 PX 自动转为 REM,替代手动计算。

cnpm i postcss @minko-fe/postcss-pxtorem autoprefixer -D

根目录创建 postcss.config.js

import pxtorem from '@minko-fe/postcss-pxtorem';
import autoprefixer from 'autoprefixer';

export default {
  plugins: [
    pxtorem({
      rootValue: 16, // 基准值(1rem = 16px,可根据设计稿调整)
      unitPrecision: 5, // 转换精度(保留 5 位小数)
      propList: ['*'], // 所有属性都转换
      selectorBlackList: ['no-rem'], // 类名含 no-rem 的不转换
      atRules: ['media'], // 媒体查询中的 PX 也转换
      exclude: /node_modules/ // 排除第三方库
    }),
    autoprefixer() // 自动添加 CSS 前缀(适配低版本浏览器)
  ]
};

步骤 3:SVG 组件化

将 SVG 图片转为 Vue 组件,支持按需引入和样式修改。

cnpm i vite-svg-loader -D

更新 build/vite.base.ts

import svgLoader from 'vite-svg-loader';

export default defineConfig({
  plugins: [
    // ... 原有插件
    svgLoader() // 解析 SVG 为 Vue 组件
  ]
});

使用方式:import Logo from '@/assets/logo.svg';,直接作为组件使用 <Logo />

六、项目测试与验证

  1. 开发环境启动cnpm run dev,验证热更新、接口代理、自动导入是否正常。
  2. 类型校验cnpm run type-check,确保无 TS 类型错误。
  3. 代码规范校验cnpm run lint,自动修复格式错误。
  4. 生产环境打包cnpm run build:prod,验证打包产物是否正常,体积是否合理。
  5. 提交测试:修改代码后执行 git add .git commit -m "test: 测试提交规范",验证 Husky 校验是否生效。

七、总结

本指南构建了一套企业级 Vue3+Vite+TS 项目架构,核心亮点:

  • 多环境配置拆分,环境隔离清晰,可快速扩展测试环境。
  • 完整代码规范体系,从开发到提交全流程约束,保障代码质量。
  • Vue3 专属插件集成,自动导入、自适应等功能提升开发效率。
  • 配置结构清晰,build 文件夹集中管理配置,便于后期维护。

可根据项目需求扩展 Pinia(状态管理)、Vue Router(路由)、单元测试等功能,适配更复杂的业务场景。

昨天以前首页

后台管理系统 Vite + elementPlus

2026年1月24日 11:50

弄这个项目缘由

本想学习下vue3 的后台管理项目, 借鉴了vbtn-admin github地址 线上地址, 颜值在线, 但是封装太骚了改代码太累。就自己额外处理了下。

做到简单易懂 开箱即用

这是一个前后端分离的 monorepo 示例项目,使用 pnpm workspace 管理前端(Vite + Tailwind + shadcn-ui)和后端(Node/Express 或自定义后端)。

github源码地址

当前项目公网地址

项目结构

.
├── 📁 backend/                    # 后端项目
├── 📁 frontend/                   # 前端项目
├── 📄 deploy.sh                   # 部署脚本
├── 📄 pnpm-lock.yaml              # pnpm 锁文件
└── 📄 pnpm-workspace.yaml         # pnpm 工作区配置

🚀 快速开始

1. 克隆仓库

git clone https://github.com/hangfengnice/vite-admin-ele.git
cd vite-admin-ele

2. 安装依赖

npm install -g pnpm
pnpm install

3. 启动项目

#同时启动前后端
pnpm run all

#启动前端
pnpm run dev
# 或者
pnpm --filter frontend dev

#启动后端
pnpm run back
# 或者
pnpm --filter backend dev

4. 一键部署阿里云

# 使用 chmod 添加执行权限(第一次)
chmod +x deploy.sh

# 部署
./deploy.sh

5. 开发配置

阿里云地址 获取服务器 付费

阿里云需要装

# 镜像 Ubuntu Server 24.04 LTS

# 安装 Node.js 24 LTS
curl -fsSL https://deb.nodesource.com/setup_24.x | bash -
sudo apt install -y nodejs

# 安装 PM2
sudo npm install -g pm2

# 安装 Nginx
sudo apt install -y nginx

# 安装 myswl
sudo apt install -y mysql-server

6.本地配置

# 电脑 mac

# node -v
# v24.12.0

# pnpm -v
# 10.28.1

# 本地额外装了mysql
❌
❌