Repository Wiki
jason5ng32/MyIP

本地开发、构建与运行

本页说明 MyIP 从本地依赖准备、双进程开发到前端构建和构建后运行的完整路径,重点解释不同启动入口、API 代理以及静态资源行为。

目的与范围

面向需要修改代码、验证构建或复现运行问题的开发者。本页覆盖包管理器与 Node.js 要求、项目脚本、Vite 配置、前端静态服务器和本地排错,不展开 IP 查询、DNS、认证等业务 API 的实现,也不替代容器部署、监控或国际化专题。

证据来自 package.json、vite.config.js 和 frontend-server.js。本页没有核验后端内部初始化、外部服务凭据要求和测试用例内容,因此不承诺“无需任何配置即可启用全部功能”。

概述:先选择正确的运行模式

目标入口前端服务后端启动方式
修改代码并联调pnpm run devVite 开发服务器nodemon,预加载 Sentry instrumentation
生成前端产物pnpm run build不启动服务器不启动后端
预览 Vite 产物pnpm run previewvite preview脚本不启动后端
运行已构建应用pnpm run startNode.js + Express 静态服务器Node.js,预加载 Sentry instrumentation
单独运行一端pnpm run start-frontend / pnpm run start-backend按所选脚本启动按所选脚本启动
测试后构建pnpm run check测试成功后运行构建不作为服务启动入口

这些入口是同一工程的不同执行路径,而不是彼此等价的命令。特别是 start 不包含构建,preview 也不等于完整的前后端启动。脚本定义见 package.json。

架构与进程边界

Loading diagram...

Sources: package.json、vite.config.js、frontend-server.js

开发时由 Vite 接收页面请求;构建后则由 Express 从 dist 提供文件。两种模式都设置了 /api 到本机后端的代理,使页面资源与 API 可以通过同一个前端入口访问。后端是独立进程,并不嵌入 Vite 或前端 Express 应用。

dev 和 start 使用 concurrently 启动两端,但脚本中没有后端就绪检查或启动顺序门控,不能把“前端已可访问”等同于“后端已准备好”。

环境准备与首次启动

工具链要求

项目元数据明确声明:

json
1 "type": "module", 2 "packageManager": "pnpm@12.4.2", 3 "engines": { 4 "node": "^24.15.0 || >=26.0.0" 5 },

Source: package.json

  • 使用项目指定的 pnpm 版本,避免把 npm 或其他包管理器的生命周期行为直接套用到该项目。
  • Node.js 范围不是简单的“24 以上”:允许 24.15.0 起的 24.x,或 26.0.0 及以上;25.x 不在声明范围内。
  • 工程以 ES module 运行。新增 Node.js 入口时应与该模块模式保持一致。
  • Vite、nodemon、Vue 编译插件等位于开发依赖中。本地开发和本地构建都需要安装开发依赖,不能只准备生产依赖。依赖划分见 package.json。

建议操作顺序

  1. 在仓库根目录准备符合声明范围的 Node.js 和 pnpm@12.4.2。
  2. 安装项目依赖;本地可使用 pnpm install。这是操作建议,不是新增的仓库脚本。
  3. 按需设置环境变量;Vite 配置和前端服务器都会调用 dotenv.config()。
  4. 运行 pnpm run dev,使用 Vite 实际打印的地址访问。配置请求的前端端口默认是 18966,开发服务器监听 0.0.0.0。
  5. 同时观察前后端进程输出,再验证需要的业务功能。代理目标端口默认是 11966,但本页未读取后端监听实现,不能据此推断后端初始化一定成功。

端口与环境加载依据:vite.config.js、vite.config.js、frontend-server.js。

开发模式的真实启动入口

json
"dev": "concurrently \"vite\" \"nodemon --import ./sentry-instrument.js backend-server.js\"",

Source: package.json

该脚本并行启动 Vite 与 nodemon。后端通过 --import 预加载 instrumentation,而不是等业务入口运行后再加载。其具体监控初始化和环境开关未在本页核验。脚本没有显式设置 nodemon 的监听目录、扩展名或忽略规则,因此这里不列出未经核实的自动重启范围。

Vite 开发入口配置如下:

javascript
1 server: { 2 host: '0.0.0.0', 3 port: frontEndPort, 4 proxy: { 5 '/api': `http://localhost:${backEndPort}` 6 }, 7 allowedHosts: ['dev.ipcheck.ing', 'test.ipcheck.ing'], 8 }

Source: vite.config.js

allowedHosts 是 Vite 配置中的显式允许项,不应将它理解为整个生产服务器的域名策略。使用自定义开发域名时应检查该配置及 Vite 的主机校验行为;开发服务绑定所有网卡,也应注意本机防火墙和共享网络的可达性。

构建、检查与预览

构建链路

build 执行 vite build。项目另外定义 postbuild:先检查 scripts/purge-index-cache.js 是否存在;存在则用当前 Node.js 可执行文件同步运行它,继承标准输入输出,并使用子进程状态退出,状态缺失时按 1 处理;不存在则跳过。该脚本的实际缓存服务、凭据和清理对象未读取,不能仅凭名称保证缓存已刷新。

check 使用 && 串联测试和构建,测试失败时不会继续构建:

json
"test": "node --import ./tests/setup.js --test tests/*.test.js", "check": "pnpm run test && pnpm run build", "preview": "vite preview",

Source: package.json

测试入口采用 Node.js 内置测试运行器,预加载测试初始化模块,再执行 tests/*.test.js。这只能证明测试执行方式,不能证明某个功能已有测试覆盖,也不能证明测试在当前环境通过。

Vite 编译行为

以下配置会直接影响本地修改与构建结果:

配置 / 插件实际行为与开发影响
Vue 插件将 pwa-install 识别为自定义元素,避免按普通 Vue 组件解析
Tailwind CSS 插件参与 Vite 样式处理链
@ 路径别名映射到 /frontend
siteUrlHtmlPlugin()读取 VITE_SITE_URL,去除首尾空白及结尾斜杠;为空时删除特定 HTML 标记块,否则替换 __SITE_URL__
localeStripPlugin()在内置 JSON 处理之前,把 frontend/locales 下 JSON 交给 stripPack 处理;设计目标是让未翻译空字符串触发运行时回退
localePreloadPlugin()从构建 bundle 找到语言包 chunk,并向 HTML 注入预加载脚本;没有匹配 chunk 时不注入
CodeInspectorPlugin指定 Vite bundler,隐藏 DOM 路径属性,并将复制行为设为文件路径
Sentry Vite 插件条件启用且位于插件链末尾,以处理最终输出 chunk

依据:vite.config.js、vite.config.js。

语言包预加载优先使用保存的偏好,然后匹配 ?hl= 或浏览器语言,最后使用 en;预加载语言变体、基础语言和英语组成的回退链。其目的在源码注释中明确:让语言包下载与主 bundle 并行,减少应用挂载前的串行网络等待。开发模式没有构建 bundle,不应期待相同的 HTML 注入结果。详见 vite.config.js。

分包、资源命名与告警

manualChunks(id) 先统一路径分隔符,再优先按第三方包分组,随后按源码路径分组;不命中时返回 undefined,交给打包器继续决定。第三方分组包含 vendor、chart、speedtest、browser-detect,源码分组包含 utils-getips 和 utils-auth。

普通资源采用 assets/[name]-[hash][extname];字体在命中 .woff / .woff2 判断时采用 fonts/[name][extname];JS chunk 采用带 hash 的名称,utils- 开头的 chunk 额外放入 assets/utils/。这些命名与运行服务器的长缓存策略相关。

配置将 chunkSizeWarningLimit 设为 1000,并只过滤来自 @vueuse/core 的 INVALID_ANNOTATION 告警,其他告警仍交给默认处理器。文件还声明了 splitChunks 字段,但本页没有通过构建验证其在当前 Vite 版本中的生效情况,不能把这些值当作已验证的产物大小保证。

依据:vite.config.js、vite.config.js、vite.config.js。

预览与完整运行的区别

pnpm run preview 只调用 vite preview。已读取配置没有单独的 preview 设置,因此本页不把开发模式的监听地址、端口和代理行为当作已验证的预览契约。

需要验证仓库自带 Express 静态服务器及其代理、缓存和 SPA 路由行为时,应先完成构建,再使用 pnpm run start。不要把 dev 和 start 同时当作同一套默认端口上的服务运行。

构建后运行:请求如何经过前端服务器

启动与 API 代理

构建后运行脚本直接启动两个 Node.js 进程,不会自动生成新产物:

json
"start-backend": "node --import ./sentry-instrument.js backend-server.js", "start-frontend": "node frontend-server.js", "start": "concurrently \"node frontend-server.js\" \"node --import ./sentry-instrument.js backend-server.js\"",

Source: package.json

前端服务器以自身文件位置确定 dist 路径,然后按顺序注册 API 代理、静态文件服务和 SPA 回退。API 代理先注册,避免被后面的页面回退吞掉:

javascript
1frontendApp.use('/api', createProxyMiddleware({ 2 target: `http://localhost:${backEndPort}/api`, 3 changeOrigin: true 4}));

Source: frontend-server.js

这里的代理目标显式带有 /api,与 Vite 配置中只指定后端 origin 的写法不同。修改时应尊重各自中间件挂载语义,不要为了形式一致直接互换。前端服务最后调用 listen(frontEndPort, callback) 并记录就绪日志;该调用没有显式传入 host,不能把日志中的 localhost 当作只监听回环地址的保证。见 frontend-server.js。

请求处理流程

Loading diagram...

Source: frontend-server.js

这套顺序区分了真实资源与客户端路由:页面深链接没有对应文件时,可以返回应用入口;丢失的 JS/CSS 文件则不应得到 HTML 响应,否则浏览器会把资源缺失表现为脚本解析错误。

实际回退条件如下:

javascript
1frontendApp.use((req, res, next) => { 2 if (req.method !== 'GET' || !req.accepts('html')) return next(); 3 if (req.path.split('/').pop().includes('.')) return next(); 4 res.setHeader('Cache-Control', 'no-store, no-cache, must-revalidate'); 5 res.sendFile(path.join(distDir, 'index.html')); 6});

Source: frontend-server.js

注意实现检查的是“路径最后一段包含点号”,并非严格识别文件扩展名。因此客户端路由最后一段如果含点,也会跳过 SPA 回退。非 GET 请求同样不会回退。

静态缓存与更新验证

setStaticHeaders(res, filePath) 将文件路径转为相对 dist 的路径,再按以下优先级设置响应头:

资源类别缓存策略本地验证含义
assets/、fonts/public,365 天,immutable带 hash 资源可通过新 URL 更新;稳定字体文件名需谨慎替换
favicons/public,30 天同名替换可能继续命中旧缓存
PNG/JPG/JPEG/WebP/SVG/ICOpublic,7 天判断不区分扩展名大小写;源码注释要求更新此类图片时重命名
HTML、manifest.webmanifest、根级 SEO 文件浏览器 max-age=0,共享缓存 s-maxage=86400,must-revalidate浏览器缓存与代理/CDN 缓存要分开检查
其他静态文件public,1 小时不属于上述分类时的默认策略
SPA 回退页面no-store, no-cache, must-revalidate与静态层命中的 /、/index.html 不同

根级 SEO 集合包含 llms.txt、llms-full.txt、sitemap.xml、robots.txt。缓存策略依据 frontend-server.js。缓存刷新与浏览器实际请求 URL 应一起验证,不能仅以构建退出成功判断页面一定更新。

配置选项

下表仅列出已读取入口直接使用的环境变量,不是整个应用的完整环境配置清单。

选项类型默认值 / 条件作用阶段
FRONTEND_PORT字符串,按十进制解析为整数18966Vite 开发端口、Express 前端监听端口
BACKEND_PORT字符串,按十进制解析为整数11966Vite 和 Express 的 API 代理目标端口;后端监听实现未在本页核验
VITE_SITE_URL字符串空字符串HTML 转换时使用;为空则删除站点 URL 条件块
SENTRY_AUTH_TOKEN字符串未设置时不启用上传构建期 source map 上传凭据
SENTRY_ENVIRONMENT字符串未设置或空时按 production 判断必须恰为 production 才满足上传环境条件
SENTRY_ORG字符串未提供代码级默认值Sentry 插件组织参数
SENTRY_PROJECT_FRONTEND字符串未提供代码级默认值Sentry 插件前端项目参数

依据:vite.config.js、vite.config.js、vite.config.js、frontend-server.js。

Sentry 构建开关的边界

上传启用条件同时要求 token 非空以及环境判断为 production:

javascript
const sentryUploadEnabled = !!process.env.SENTRY_AUTH_TOKEN && (process.env.SENTRY_ENVIRONMENT || 'production') === 'production';

Source: vite.config.js

启用时生成 hidden source map,插件配置为上传后删除 dist/**/*.map,并忽略没有可映射源码的 Rolldown runtime chunk;未启用时完全不生成 source map。这段判断没有检查 NODE_ENV 或 Vite mode:本地构建如果带有 token 且未设置 SENTRY_ENVIRONMENT,同样满足上传条件。上传与删除在失败场景中的最终效果取决于插件执行结果,应检查日志和实际产物,而不是只看配置意图。

排错、边界与并发运行

现象 / 风险源码支持的检查方向
页面可打开但 /api 不可用两端是独立并行进程;检查后端输出与代理目标端口,不要只看前端就绪日志
修改源码后 start 页面仍旧start 不构建,静态服务器读取 dist;重新构建并检查浏览器及共享缓存
同时运行 dev 和 start二者默认请求同一个前端端口,并各自启动后端;避免重复启动整套进程
自定义开发域名被拒绝检查 Vite allowedHosts;不要误认为生产 Express 自动继承此配置
深链接刷新失败检查 GET、HTML Accept、路径末段点号和 dist/index.html 是否存在
丢失的 JS 文件没有返回首页这是点号检查的预期行为,用来避免将 HTML 作为脚本返回
构建后出现额外缓存清理输出或非零退出检查 postbuild 子进程;该阶段与 Vite 编译不是同一操作
非法端口配置入口直接使用 parseInt,没有显式范围校验或友好错误包装,应自行保证整数有效
本地构建尝试上传 source map检查 token 和 SENTRY_ENVIRONMENT;默认环境判断为 production

前端入口未定义自有代理重试策略、就绪探针、优雅退出处理或统一错误中间件,本页不推断依赖库的默认超时与异常响应。进程启动脚本也没有声明 cluster 或 worker 数量;这里的“并发”指前后端两个命令并行运行,不代表多实例部署支持。依据:package.json、frontend-server.js。

扩展与验证建议

  • 更改代理路径时同步核对两种模式。 开发代理在 Vite 中,构建后代理在 Express 中,修改其中一处不会自动改变另一处。
  • 新增构建插件时保留顺序约束。 locale JSON 清理使用 enforce: 'pre';站点 URL 转换在 HTML 的 pre 阶段;语言包注入使用 post 阶段;Sentry 插件按注释放在末尾。
  • 更改资源命名时检查缓存策略。 分包和文件名由 Vite 决定,而长缓存由前端服务器按路径分类设置;引入稳定文件名后不能仍假设所有资源都通过 hash 自动失效。
  • 修改后执行 pnpm run check,再按目标模式验证。 check 只证明命令链的检查结果,不能替代 API 联调、深链接访问或缓存行为验证。本文未实际运行这些命令,不报告测试通过或构建成功。

以上扩展入口分别见 vite.config.js 与 frontend-server.js。

相关链接

容器部署、外部服务接入、监控运行期配置和业务 API 行为应查阅对应专题;当前上下文未提供这些 Wiki 页的实际路径,因此不构造未经确认的页面链接。