> For the complete documentation index, see [llms.txt](https://docs.ipcheck.ing/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.ipcheck.ing/developer/zh/development/dev-environment.md).

# 开发环境

MyIP 是一个仓库，分为两部分：一个 **Vue 3** 位于……下的单页应用 `frontend/` 以及一个 **Express 5** 位于……下的 API `api/` + `backend-server.js`。一个命令即可同时运行两者。

## 先决条件

<table><thead><tr><th width="180">工具</th><th width="220">版本</th><th>说明</th></tr></thead><tbody><tr><td><strong>Node.js</strong></td><td>24</td><td>Docker 镜像（<code>node:24-alpine</code>）和 CI 都使用的版本。</td></tr><tr><td><strong>pnpm</strong></td><td>固定在 <code>package.json</code></td><td>不要手动安装其他版本——见下文。</td></tr><tr><td><strong>Git</strong></td><td>任何较新的版本</td><td>贡献分支从……分出 <code>dev</code>.</td></tr></tbody></table>

获取正确 pnpm 的最简单方式是 Corepack，它随 Node 一起提供：

```bash
corepack enable
```

Corepack 会读取 `packageManager` ……中的字段 `package.json` 并准确准备那个 pnpm 版本。Dockerfile 和 CI 工作流也这样做，因此你的本地工具链会与它们保持一致。

## 仅支持 pnpm

{% hint style="danger" %}
**切勿运行 `npm install` 或 `yarn` 在这个仓库中。**
{% endhint %}

有三件事特别依赖 pnpm：

* **`packageManager` 在 `package.json` 会固定精确的 pnpm 版本。** Corepack、Dockerfile 和 GitHub Actions 工作流都会读取它，因此每个人解析出的依赖树都相同。
* **`pnpm-lock.yaml` 已提交。** npm 会写入 `package-lock.json` 而 yarn 会写入 `yarn.lock` ——这是另一个相互竞争的锁定文件，项目中没有任何东西会读取它。CI 安装时使用 `--frozen-lockfile`，因此一旦 pnpm 锁定文件发生漂移，构建就会直接失败。
* **`pnpm-workspace.yaml` 保存安装脚本批准** (`allowBuilds`）给少数被允许运行 postinstall 脚本的包。npm 和 yarn 完全忽略该文件。

## 安装并运行

{% stepper %}
{% step %}

#### 克隆并安装

```bash
git clone https://github.com/jason5ng32/MyIP.git
cd MyIP
pnpm install
```

{% endstep %}

{% step %}

#### 创建你的 `.env`

```bash
cp .env.example .env
```

……中的一切 `.env.example` 对于……是可选的 *启动* 应用，但如果没有 MaxMind 凭据，IP 地理定位仍然无法使用。参见 [MaxMind 设置](/developer/zh/getting-started/maxmind-setup.md) 和 [环境变量](/developer/zh/reference/environment-variables.md).
{% endstep %}

{% step %}

#### 启动两部分

```bash
pnpm dev
```

这会同时运行 Vite 开发服务器和后端（位于 `nodemon`）并排运行，借助 `concurrently`。编辑一个 `.vue` 文件，Vite 会热重载；编辑后端导入的任何内容，nodemon 就会重启 API。
{% endstep %}

{% step %}

#### 打开应用

访问 `http://localhost:18966`。Vite 开发服务器会代理 `/api` 到后端。
{% endstep %}
{% endstepper %}

## 端口

这两个端口都来自 `.env` ，默认如下：

| 变量              | 默认      | 使用者                                        |
| --------------- | ------- | ------------------------------------------ |
| `FRONTEND_PORT` | `18966` | Vite 开发服务器（`pnpm dev`）和静态服务器（`pnpm start`) |
| `BACKEND_PORT`  | `11966` | Express API（`backend-server.js`)           |

Vite 开发服务器绑定到 `0.0.0.0`，因此你可以从局域网中的另一台设备访问它，并代理 `/api` → `http://localhost:<BACKEND_PORT>`。你很少需要直接访问后端端口。

{% hint style="warning" %}
**对……的请求 `/api/*` 需要一个 `Referer`.** 全局中间件（`requireReferer` 在 `common/guards.js`）会拒绝 referer 不在允许列表中的请求。 `localhost` 是允许的，所以浏览器没问题——但单独的 `curl http://localhost:11966/api/...` 会得到一个 `403`。添加 `-H 'Referer: http://localhost/'` 用于手动测试时。
{% endhint %}

## 本地 `.env` 说明

* `.env` 由……加载 **两个** 两部分： `backend-server.js` 在运行时，且 `vite.config.js` 在构建时。
* 以前缀开头的变量 `VITE_` 是 **在构建时被打包进前端 bundle**。修改它需要 `pnpm dev` 重启，而不只是刷新页面——并且绝不要把密钥放在 `VITE_` 名称之后。
* 可选集成在其变量为空时会完全关闭。没有 Sentry DSN 就不会加载任何 Sentry 代码；没有 Firebase 配置就不会获取 SDK。你可以用一个几乎空白的 `.env`.
* 日志开关是 `LOG_LEVEL`, `LOG_FORMAT`，以及 `LOG_HTTP` ——参见 [日志](/developer/zh/configuration/logging.md)。没有 `NODE_ENV` 可以在本项目中任何地方切换。

## 每个脚本

| 命令                    | 作用                             |
| --------------------- | ------------------------------ |
| `pnpm dev`            | Vite 开发服务器 + nodemon 下的后端，一起运行 |
| `pnpm build`          | 将生产环境前端构建到 `dist/`             |
| `pnpm preview`        | 用于构建产物的 Vite 预览服务器             |
| `pnpm test`           | `node --test tests/*.test.js`  |
| `pnpm check`          | `测试` + `构建` ——提交前自检            |
| `pnpm start`          | 静态前端服务器 + 后端（生产主机运行的内容）        |
| `pnpm start-backend`  | 仅后端                            |
| `pnpm start-frontend` | 仅静态前端服务器                       |

## 自检

在你交接一个改动——PR、提交、审查请求——之前，运行：

```bash
pnpm check
```

也就是 `pnpm test` 之后接着 `pnpm build`。这也是 CI 在每次 push 和针对……的 pull request 上运行的同一组步骤 `main` 和 `dev`，因此本地通过的 `check` 通常意味着 CI 也会通过。

{% hint style="info" %}
**视觉改动无法自我测试。** Node 测试运行器不会渲染 Vue 组件，也不会驱动浏览器。如果你的改动是视觉上的，请在 PR 中明确说明，并让人工在 `pnpm dev`。参见 [测试](/developer/zh/development/testing.md).
{% endhint %}

## 开发时的实用附加功能

* **移动端控制台。** 在手机或平板上， `pnpm dev` 会自动加载 vConsole——一个屏幕上的开发者工具面板。它仅用于开发且仅限移动端；不会随构建发布。
* **点击跳转源码。** 这个 `code-inspector-plugin` 已接入开发服务器，因此你可以从浏览器中的元素跳转到编辑器里的源码行。
* **额外的开发主机。** `vite.config.js` 允许 `dev.ipcheck.ing` 和 `test.ipcheck.ing` 除了 localhost 之外，还可用于针对真实主机名进行测试。

## 下一步

* [编码规范](/developer/zh/development/coding-conventions.md) ——你的改动应遵循的规则。
* [添加新工具](/developer/zh/development/adding-a-new-tool.md) ——端到端演练。
* [项目结构](/developer/zh/architecture/project-structure.md) ——哪些内容放在哪里。
* [如何贡献](/developer/zh/contributing/how-to-contribute.md) ——分支规范和 PR 指南。


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.ipcheck.ing/developer/zh/development/dev-environment.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
