理解企业级前端脚手架:原理、实现与实战

在企业级前端开发中,脚手架是提升研发效率、规范项目架构的核心工具。从早期的 VueCLI 到现代化的 Vite,再到多端适配的 TaroCLI,脚手架的设计理念与实现方案不断迭代,但核心价值始终围绕"降低工程化门槛、标准化开发流程"展开。本文将从底层原理拆解、从 0 到 1 开发流程、主流工具差异对比三个维度,为中高级前端开发者深入剖析企业级脚手架的核心知识,兼具理论深度与实践指导性。
一、企业级脚手架底层原理深度拆解
企业级脚手架的核心本质是"命令行工具(CLI)+ 工程化配置方案 + 插件化扩展体系"的集合,其底层运作依赖 Node.js 的文件系统、进程管理能力,以及一系列成熟的工程化工具链。以下将从 5 个核心模块,结合主流脚手架案例进行原理拆解。
1.1 初始化流程:从命令输入到项目生成
脚手架的初始化流程是用户接触的第一个环节,核心目标是"接收用户输入 → 解析需求 → 生成标准化项目结构"。其完整链路可拆解为 4 个步骤,不同脚手架在细节上存在优化差异,但核心逻辑一致。
1.1.1 核心流程拆解
-
命令解析 :接收用户在终端输入的命令(如
vue create project、vite init project),通过命令行解析工具识别命令、参数与选项(如--template、--force)。 -
用户交互:根据预设规则向用户询问关键配置(如项目框架、TypeScript 支持、CSS 预处理器、代码规范等),收集用户需求。
-
模板拉取:根据用户选择的配置,从远程仓库(如 GitHub、GitLab)拉取对应的项目模板(基础模板、业务模板等)。
-
项目生成:将拉取的模板渲染(替换模板中的变量,如项目名称、作者信息)后,写入本地文件系统,完成项目初始化。
1.1.2 主流脚手架实现差异
-
VueCLI :采用
commander.js解析命令,inquirer.js处理用户交互,模板存储在官方 GitHub 仓库(vuejs/vue-cli-templates),支持自定义模板仓库地址。初始化时会先检查本地缓存,避免重复拉取模板,提升速度。 -
Vite :同样基于
commander.js,但简化了交互流程(默认提供基础模板,复杂配置通过--template参数指定)。核心优化点是"模板拉取轻量化",仅拉取必要的模板文件(而非完整项目),结合原生 ES 模块特性,避免了 VueCLI 初始化时的依赖预安装步骤,初始化速度提升 50% 以上。 -
TaroCLI :针对多端适配场景,在交互环节增加了"目标平台选择"(微信小程序、支付宝小程序、H5 等),模板按平台分类存储,拉取后会自动注入对应平台的配置文件(如
app.json小程序配置)。
1.1.3 核心代码片段(命令解析与交互)
javascript
// 基于 commander.js + inquirer.js 实现基础命令解析与交互
const { program } = require('commander');
const inquirer = require('inquirer');
const download = require('download-git-repo'); // 模板拉取工具
// 定义 create 命令
program
.command('create <projectName>')
.description('创建一个新的企业级项目')
.option('--template <templateName>', '指定项目模板(vue/react/taro)')
.action(async (projectName, options) => {
// 1. 补全用户交互(若未指定模板)
const answers = options.template
? { template: options.template }
: await inquirer.prompt([
{
type: 'list',
name: 'template',
message: '请选择项目模板',
choices: ['vue', 'react', 'taro'],
},
{
type: 'confirm',
name: 'typescript',
message: '是否启用 TypeScript?',
default: true,
},
]);
// 2. 拉取对应模板(以 vue 模板为例)
const repo = `xxx/enterprise-template-${answers.template}`; // 远程模板仓库
download(repo, projectName, (err) => {
if (err) {
console.error('模板拉取失败:', err);
return;
}
console.log('模板拉取成功,开始生成项目...');
// 3. 后续:模板渲染、配置写入等逻辑
});
});
program.parse(process.argv);
1.2 配置解析机制:标准化与个性化的平衡
企业级项目的配置需求复杂,既要保证团队开发的标准化,又要支持项目的个性化配置。脚手架的配置解析机制核心解决"配置来源整合 → 配置优先级排序 → 配置生效"的问题。
1.2.1 配置来源与优先级
脚手架的配置来源通常分为 4 类,按优先级从高到低排序为:
-
命令行参数(如
vite --port 3000):优先级最高,直接覆盖其他配置; -
项目本地配置文件(如
vue.config.js、vite.config.js、taro.config.js):项目级个性化配置,优先级次之; -
脚手架默认配置:团队标准化基础配置,优先级较低;
-
环境变量配置(如
.env.development、.env.production):针对不同环境的动态配置,会嵌入到上述配置中生效。
1.2.2 主流脚手架实现方案
-
VueCLI :采用"默认配置 + vue.config.js 覆盖 + 环境变量注入"的方案。核心是
@vue/cli-service模块,内部通过webpack-merge工具合并默认 Webpack 配置与用户自定义配置。支持通过chainWebpack方法精细修改 Webpack 配置(基于webpack-chain实现配置的链式操作)。 -
Vite :配置解析更轻量化,支持
vite.config.js(支持 ESM 语法),内部通过defineConfig函数整合配置,无需手动合并。对于环境变量,支持.env文件,通过import.meta.env注入,比 VueCLI 的process.env更贴近原生 ES 模块。 -
TaroCLI :配置文件为
taro.config.js,核心特点是"多端配置分离",支持通过h5、mini等字段配置不同平台的专属选项。解析时会根据当前编译目标(如taro build --type weapp)自动筛选对应平台的配置,合并到基础配置中。
1.3 依赖管理逻辑:高效处理项目依赖
依赖管理是脚手架的核心能力之一,负责项目初始化时的依赖安装、开发过程中的依赖更新、构建时的依赖优化。核心目标是"快速安装、版本兼容、体积优化"。
1.3.1 核心实现逻辑
-
依赖分类 :区分
dependencies(生产依赖,如 Vue、React 核心库)和devDependencies(开发依赖,如 Webpack、Vite、ESLint),根据模板预设自动生成package.json。 -
安装策略:
-
自动选择包管理器:检测本地环境已安装的包管理器(npm/yarn/pnpm),优先使用用户习惯的工具;
-
缓存优化:VueCLI 会缓存已下载的依赖包到本地(
~/.vue/cli-cache),避免重复下载;Vite 则依赖包管理器自身的缓存机制(如 pnpm 的 node_modules 缓存); -
版本锁定:生成
package-lock.json或yarn.lock,确保团队成员使用相同版本的依赖,避免"版本地狱"。
-
-
依赖优化:构建时通过 Tree-Shaking 移除未使用的依赖代码,通过依赖预构建(如 Vite 的依赖预构建)提升运行速度。
1.3.2 案例对比:Vite vs VueCLI 依赖安装差异
VueCLI 在初始化时会自动安装所有依赖(包括开发依赖),导致初始化时间较长;而 Vite 初始化时仅生成 package.json,不自动安装依赖,让用户自主选择包管理器(推荐 pnpm),同时在首次启动开发服务器时进行"依赖预构建"------将 CommonJS 格式的依赖(如 Vue)转换为 ESM 格式,并存入 node_modules/.vite 缓存,既提升了启动速度,又保证了原生 ES 模块的兼容性。
1.4 构建/打包核心链路:从源码到产物
构建/打包是脚手架的核心功能之一,负责将开发者编写的源码(Vue/React 组件、TypeScript、SCSS 等)转换为浏览器可识别的静态资源。不同脚手架的构建链路差异较大,核心取决于底层构建工具的选择。
1.4.1 主流脚手架构建工具选型
-
VueCLI :基于 Webpack 构建,支持从源码到产物的全链路处理(转译、打包、压缩、优化等)。核心是
@vue/cli-service封装了 Webpack 配置,支持多环境构建(开发、测试、生产),通过vue-cli-plugin-xxx扩展构建能力(如vue-cli-plugin-babel处理 ES6+ 转译)。 -
Vite:开发环境基于原生 ES 模块(无需打包),生产环境基于 Rollup 构建。开发时通过服务器拦截模块请求,实时转译源码(如 TypeScript 转 JS、SFC 解析),避免了 Webpack 的全量打包,启动速度极快;生产环境利用 Rollup 的 tree-shaking 能力和更小的打包体积优势,优化产物性能。
-
TaroCLI:多端适配场景下,构建工具根据目标平台动态选择:H5 端基于 Webpack,小程序端基于自研的打包工具(处理小程序的目录结构和配置约束),React Native 端基于 Metro 构建。核心是通过"源码转换 + 平台适配层"实现一套代码多端运行。
1.4.2 核心构建流程(以 Vite 生产构建为例)
javascript
// Vite 生产构建核心流程简化逻辑(源码位于 vite/src/node/build/index.ts)
async function build(options) {
// 1. 解析配置(合并默认配置、用户配置、环境变量)
const config = await resolveConfig(options, 'build', 'production');
// 2. 初始化 Rollup 配置
const rollupOptions = await createRollupOptions(config);
// 3. 执行 Rollup 构建
const bundle = await rollup.rollup(rollupOptions);
await Promise.all(rollupOptions.output.map(bundle.write));
// 4. 产物优化(压缩、Tree-Shaking、资源处理等)
await optimizeBundle(config, bundle);
// 5. 生成构建报告
generateBuildReport(config, bundle);
}
1.5 插件化架构设计:脚手架的扩展性核心
企业级脚手架需要支持团队个性化需求(如接入内部代码规范、集成业务组件库、对接内部部署系统),插件化架构是实现"核心功能稳定 + 扩展功能灵活"的关键。其核心设计理念是"钩子机制 + 插件注册/执行流程"。
1.5.1 插件化核心原理
-
钩子定义:脚手架在核心流程中预设一系列钩子(如初始化前、模板拉取后、构建前、构建后),插件通过监听这些钩子注入自定义逻辑。
-
插件注册 :支持通过配置文件(如
vue.config.js中的plugins数组)、命令行参数或自动发现(如vue-cli-plugin-xxx插件)的方式注册插件。 -
插件执行:脚手架在运行到对应钩子时,按注册顺序执行插件的钩子函数,实现功能扩展。
1.5.2 主流脚手架插件化实现
-
VueCLI :插件化体系最成熟,插件格式为
vue-cli-plugin-xxx,支持:示例:`vue-cli-plugin-eslint` 插件在构建前执行 ESLint 校验,确保代码规范。-
命令扩展:通过插件添加自定义命令(如
vue invoke xxx); -
配置修改:通过插件修改 Webpack 配置、项目配置;
-
模板注入:通过插件向项目中注入业务模板、配置文件。
-
-
Vite :插件格式更灵活,支持 ESM 模块,核心是基于 Rollup 插件 API 扩展,同时新增了 Vite 专属钩子(如
configResolved、configureServer)。支持:-
开发服务器扩展:如
vite-plugin-mock实现接口模拟; -
源码转译:如
vite-plugin-vue2支持 Vue2 项目; -
构建优化:如
vite-plugin-imagemin优化图片资源。
-
-
TaroCLI :插件化围绕多端适配展开,支持通过插件扩展平台能力(如新增钉钉小程序适配)、注入业务逻辑(如接入内部埋点系统)。插件需遵循 Taro 定义的钩子规范(如
onBuildStart、onBuildFinish)。
二、企业级脚手架从 0 到 1 开发流程
理解底层原理后,我们可以动手开发一个极简的企业级脚手架(基于 Node.js)。以下将按"需求拆解 → 技术选型 → 核心模块开发 → 调试优化 → 发布维护"的流程,详细说明开发步骤,并提供核心代码实现。
2.1 需求拆解:明确脚手架核心功能
企业级脚手架的需求需结合团队实际场景,此处以"通用前端项目脚手架"为例,拆解核心需求:
-
支持
create <projectName>命令创建项目; -
支持用户交互选择项目模板(Vue/React)、是否启用 TypeScript、是否集成 ESLint;
-
自动拉取远程模板,渲染并生成项目;
-
自动安装依赖(支持 npm/yarn/pnpm);
-
支持
dev(开发启动)、build(打包构建)命令; -
支持插件扩展(预留钩子)。
2.2 技术选型:核心工具与依赖
基于 Node.js 开发,选择成熟的工具库提升开发效率,核心依赖如下:
| 功能模块 | 选择工具 | 作用说明 |
|---|---|---|
| 命令解析 | commander.js | 解析终端命令、参数、选项 |
| 用户交互 | inquirer.js | 向用户询问配置信息,收集需求 |
| 模板拉取 | download-git-repo | 从 Git 仓库拉取项目模板 |
| 模板渲染 | ejs | 渲染模板中的变量(如项目名称、作者) |
| 进程管理 | child_process | 执行依赖安装、开发服务器启动等命令 |
| 日志输出 | chalk + ora | 美化日志输出,显示加载状态 |
| 构建工具 | webpack/rollup | 封装开发、构建命令 |
2.3 核心模块开发:分步实现核心功能
以下按"项目初始化 → 命令解析 → 用户交互 → 模板拉取与渲染 → 依赖安装 → 开发/构建命令封装 → 插件化预留"的顺序,实现核心模块。
2.3.1 项目初始化:创建脚手架工程
bash
# 1. 创建项目目录
mkdir enterprise-cli && cd enterprise-cli
# 2. 初始化 package.json
npm init -y
# 3. 安装核心依赖
npm install commander inquirer download-git-repo ejs chalk ora --save
# 4. 创建入口文件
mkdir bin && touch bin/index.js
# 5. 配置 package.json,指定入口(支持全局命令)
{
"name": "enterprise-cli",
"version": "1.0.0",
"bin": {
"ent-cli": "./bin/index.js"
},
"type": "commonjs"
}
2.3.2 命令解析模块(bin/index.js)
javascript
#!/usr/bin/env node
const { program } = require('commander');
const chalk = require('chalk');
const ora = require('ora');
const createProject = require('../lib/create');
const dev = require('../lib/dev');
const build = require('../lib/build');
// 定义版本和描述
program
.version(require('../package.json').version, '-v, --version')
.description('企业级前端脚手架,支持 Vue/React 项目快速初始化与构建');
// 定义 create 命令
program
.command('create <projectName>')
.description('创建一个新的企业级项目')
.action((projectName) => {
console.log(chalk.blue(`开始创建项目:${projectName}`));
createProject(projectName);
});
// 定义 dev 命令
program
.command('dev')
.description('启动开发服务器')
.action(() => {
dev();
});
// 定义 build 命令
program
.command('build')
.description('构建生产环境产物')
.action(() => {
build();
});
// 解析命令行参数
program.parse(process.argv);
// 若无命令输入,显示帮助信息
if (!process.argv.slice(2).length) {
program.outputHelp(chalk.green);
}
2.3.3 项目创建模块(lib/create.js)
javascript
const fs = require('fs');
const path = require('path');
const inquirer = require('inquirer');
const download = require('download-git-repo');
const ejs = require('ejs');
const chalk = require('chalk');
const ora = require('ora');
const { execSync } = require('child_process');
// 远程模板仓库地址(示例:GitHub 仓库)
const TEMPLATE_REPOS = {
vue: 'xxx/enterprise-vue-template',
react: 'xxx/enterprise-react-template',
};
async function createProject(projectName) {
const cwd = process.cwd();
const projectPath = path.join(cwd, projectName);
// 1. 检查项目是否已存在
if (fs.existsSync(projectPath)) {
console.log(chalk.red(`错误:项目 ${projectName} 已存在`));
return;
}
// 2. 用户交互,收集配置
const answers = await inquirer.prompt([
{
type: 'list',
name: 'template',
message: '请选择项目模板',
choices: [
{ name: 'Vue 3 + Vite', value: 'vue' },
{ name: 'React 18 + Vite', value: 'react' },
],
},
{
type: 'confirm',
name: 'typescript',
message: '是否启用 TypeScript?',
default: true,
},
{
type: 'confirm',
name: 'eslint',
message: '是否集成 ESLint + Prettier?',
default: true,
},
{
type: 'list',
name: 'packageManager',
message: '请选择包管理器',
choices: ['npm', 'yarn', 'pnpm'],
default: 'pnpm',
},
]);
// 3. 拉取模板
const spinner = ora(chalk.blue('正在拉取项目模板...')).start();
try {
await new Promise((resolve, reject) => {
const repo = TEMPLATE_REPOS[answers.template];
download(repo, projectPath, (err) => {
if (err) {
reject(err);
return;
}
resolve();
});
});
spinner.succeed(chalk.green('模板拉取成功'));
} catch (err) {
spinner.fail(chalk.red('模板拉取失败'));
console.error(err);
return;
}
// 4. 渲染模板变量(如 package.json 中的项目名称、TypeScript 配置等)
const packageJsonPath = path.join(projectPath, 'package.json');
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
// 替换项目名称
packageJson.name = projectName;
// 根据用户选择,添加/移除依赖、配置
if (answers.typescript) {
packageJson.devDependencies = {
...packageJson.devDependencies,
typescript: '^5.0.0',
'@types/node': '^20.0.0',
};
}
if (answers.eslint) {
packageJson.devDependencies = {
...packageJson.devDependencies,
eslint: '^8.0.0',
prettier: '^3.0.0',
};
}
// 写入渲染后的 package.json
fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2), 'utf8');
// 5. 自动安装依赖
spinner.text = chalk.blue('正在安装依赖...');
spinner.start();
try {
// 执行包管理器安装命令
execSync(`${answers.packageManager} install`, { cwd: projectPath, stdio: 'ignore' });
spinner.succeed(chalk.green('依赖安装成功'));
} catch (err) {
spinner.fail(chalk.red('依赖安装失败,请手动安装'));
console.error(err);
return;
}
// 6. 输出成功信息
console.log(chalk.green(`\n项目创建成功!路径:${projectPath}`));
console.log(chalk.blue('\n后续命令:'));
console.log(chalk.grey(` cd ${projectName}`));
console.log(chalk.grey(` ${answers.packageManager} dev`));
}
module.exports = createProject;
2.3.4 开发/构建命令封装(lib/dev.js、lib/build.js)
开发和构建命令的核心是调用底层构建工具(如 Vite、Webpack),此处以 Vite 为例进行封装:
javascript
// lib/dev.js
const { execSync } = require('child_process');
const chalk = require('chalk');
const ora = require('ora');
function dev() {
const spinner = ora(chalk.blue('启动开发服务器...')).start();
try {
// 调用 vite dev 命令(假设项目模板中已集成 Vite)
execSync('vite', { stdio: 'inherit' });
spinner.succeed(chalk.green('开发服务器启动成功'));
} catch (err) {
spinner.fail(chalk.red('开发服务器启动失败'));
console.error(err);
}
}
module.exports = dev;
// lib/build.js
const { execSync } = require('child_process');
const chalk = require('chalk');
const ora = require('ora');
function build() {
const spinner = ora(chalk.blue('正在构建生产环境产物...')).start();
try {
// 调用 vite build 命令
execSync('vite build', { stdio: 'inherit' });
spinner.succeed(chalk.green('构建成功,产物位于 dist 目录'));
} catch (err) {
spinner.fail(chalk.red('构建失败'));
console.error(err);
}
}
module.exports = build;
2.3.5 插件化预留:钩子机制实现
为支持后续扩展,在核心流程中添加钩子机制。以创建项目流程为例,新增钩子:
javascript
// lib/hooks.js
class Hook {
constructor() {
this.hooks = {};
}
// 注册钩子
tap(hookName, callback) {
if (!this.hooks[hookName]) {
this.hooks[hookName] = [];
}
this.hooks[hookName].push(callback);
}
// 执行钩子
async call(hookName, ...args) {
const callbacks = this.hooks[hookName] || [];
for (const callback of callbacks) {
await callback(...args);
}
}
}
// 导出全局钩子实例
module.exports = new Hook();
// 在 create.js 中引入并使用钩子
const hook = require('./hooks');
async function createProject(projectName) {
// ... 前面逻辑不变
// 模板拉取前执行钩子
await hook.call('beforeTemplateDownload', projectName, projectPath);
// 3. 拉取模板(原有逻辑)
// ...
// 模板拉取后执行钩子
await hook.call('afterTemplateDownload', projectName, projectPath);
// ... 后面逻辑不变
}
后续开发插件时,可通过注册钩子注入逻辑,例如:
javascript
// 插件:向项目中注入内部业务组件库
const hook = require('../lib/hooks');
const fs = require('fs');
const path = require('path');
hook.tap('afterTemplateDownload', async (projectName, projectPath) => {
// 写入业务组件库配置文件
const configPath = path.join(projectPath, 'components.config.js');
fs.writeFileSync(configPath, `module.exports = { import: ['@company/components'] }`, 'utf8');
console.log('注入业务组件库配置成功');
});
2.4 调试优化:提升开发与使用体验
2.4.1 本地调试
通过 npm link 将脚手架链接到全局,实现本地调试:
bash
# 在脚手架项目根目录执行
npm link
# 此时可在任意目录执行脚手架命令
ent-cli create my-project
2.4.2 优化点
-
错误处理增强:对文件操作、模板拉取、依赖安装等环节添加更细致的错误捕获,给出明确的解决方案提示;
-
缓存机制:添加模板缓存,避免重复拉取远程模板;
-
日志美化 :使用
chalk区分不同类型日志(成功、错误、信息),使用ora显示加载状态; -
命令补全 :通过
commander.js的completion方法支持命令自动补全。
2.5 发布维护:推向团队使用
-
发布到 npm :将脚手架发布到 npm 仓库(私有仓库用于团队内部使用),方便团队安装:
npm install -g enterprise-cli; -
版本管理:遵循 SemVer 语义化版本规范(主版本号.次版本号.修订号),迭代功能时更新版本;
-
文档编写:编写详细的使用文档,说明命令、配置、插件开发规范;
-
迭代维护:收集团队使用反馈,优化核心功能,更新模板,修复 bug。
三、主流脚手架设计差异与适配场景
VueCLI、Vite、TaroCLI 是不同场景下的优秀脚手架,其设计理念、底层架构、性能表现存在显著差异,选择时需结合项目类型、团队技术栈、性能需求综合判断。以下从 5 个维度进行对比,并给出适配场景建议。
3.1 核心维度对比
| 对比维度 | VueCLI | Vite | TaroCLI |
|---|---|---|---|
| 核心定位 | Vue 生态专用脚手架,全链路工程化解决方案 | 通用前端构建工具,主打极速开发体验 | 多端适配脚手架,一套代码运行于多平台 |
| 底层构建工具 | Webpack | 开发环境:原生 ES 模块;生产环境:Rollup | H5:Webpack;小程序:自研工具;RN:Metro |
| 开发体验 | 启动速度中等,热更新速度一般 | 启动速度极快(毫秒级),热更新即时 | 启动速度取决于平台,小程序端需编译,速度中等 |
| 插件化体系 | 成熟的 Vue 插件生态,支持命令、配置扩展 | 基于 Rollup 插件 API,扩展灵活,生态快速发展 | 多端适配专属插件体系,支持平台能力扩展 |
| 适用场景 | Vue 项目(PC 端、移动端 H5),需要完整工程化配置 | 现代前端项目(Vue/React/Svelte 等),追求极致开发体验 | 需要多端适配的项目(小程序、H5、App) |
3.2 适配场景建议
-
单一 Vue 项目(PC/H5):
-
若团队熟悉 Webpack,需要丰富的插件生态和完整的工程化配置,选择VueCLI;
-
若追求极速开发体验,项目基于 Vue 3,选择 Vite(Vue 官方已推荐 Vite 替代 VueCLI 用于新项目)。
-
-
多框架项目(Vue/React 并存) :选择 Vite,支持多框架模板,统一构建工具,降低维护成本。
-
多端适配项目(小程序 + H5 + App) :选择 TaroCLI,成熟的多端适配方案,避免重复开发,提升效率。
-
轻量级项目/原型开发 :选择 Vite,快速初始化、启动,专注业务开发,无需关注复杂配置。
四、总结与展望
企业级前端脚手架的核心价值是"标准化 + 效率提升",其底层原理围绕"命令解析、配置管理、依赖处理、构建打包、插件扩展"展开,不同脚手架的差异本质是"底层工具选型"与"场景适配优化"。通过从 0 到 1 开发脚手架,我们可以深入理解其核心逻辑,更好地应对团队个性化需求。
未来,脚手架的发展趋势将集中在三个方向:
- 更轻量化:减少冗余配置,基于原生能力提升性能;
- 更智能化:结合 AI 自动生成配置、排查问题、优化代码;
- 更一体化:整合 CI/CD、监控、部署等全链路能力,实现研发全流程标准化。
对于中高级前端开发者而言,深入理解脚手架原理,不仅能提升日常开发效率,更能结合团队场景设计合适的工程化方案,成为连接业务与工程化的核心桥梁。
(注:文档部分内容可能由 AI 生成)