Skip to content

配置参考 ​

说到"配置",这个仓库里其实混着两件容易搞混的事:一是编辑器自己的文档格式——样式档、界面意图档(ms-config)、项目信封,这些是用户数据的格式,改错一个键名就是数据兼容性事故;二是工程配置文件——vite、vitest、CI 这些,改坏了只是构建问题。这一页先讲前者(它是重点),工程配置和端点放最后速查。构建部署相关命令见构建与部署。

双档模型:样式档与 ms-config ​

先讲清楚这个仓库最重要的一条数据设计。编辑器里用户的每一次操作,最终落在两份文档上:

  • 样式档(StyleDocument):纯渲染语义,就是 MapLibre Style Specification 那个 JSON。导出给别人的就是它,里面一个 mapstudio:* 约定键都不许有。
  • ms-config(界面意图档):存"编辑器才知道的东西"——图层显示名、分组、底图注册、Import 卡片的值、雪/雨这类没有样式根可放的 UI 值。

为什么分两份?历史上界面意图以约定键塞进样式 metadata,结果导出的"纯净样式"里全是私货,别人加载会莫名其妙。v2 配置简化评审(ADR-12)之后收敛为独立文档,样式档从此干净。

机器可读的 schema 在 docs/spec/config-simplification/mapstudio-config.schema.json(additionalProperties: false,严格描述当前合法形态);TypeScript 类型投影在 core/config/config.model.ts;双向编解码在 core/config/config-codec.ts。三层由 tests/app/core/config/config-schema.test.ts 读盘对账,Schema 和运行时漂移会被测试抓出来。

保存与装载时双档怎么流转 ​

流程图

这里有个坑要记住:装载是程序化写入,而 autosave 的 effect 分不清"用户编辑"和"程序装载"。任何新的装载入口必须先 suppressNextSave() 布防,否则刚装载的内容又被存成草稿,"放弃草稿"会变成死循环。

ms-config 根字段速查 ​

format 恒为 mapstudio-config。字段枚举如下(完整定义以 Schema 为准):

字段存什么
version / valueVersion文档版本(当前 2)/ 值词表版本(当前 4),双轴独立演进
name / savedAt / note / $schema元信息
protected样式受保护标记(写通道全锁)
layers图层界面参数表,键 = 图层 id,只列需定制的:type 授权字段、name 显示名、group、note、tags、data(source/filter 骨架)、props(属性值,v4 词表)、interactions(三事件覆盖)
groups分组表:键 = 稳定组 ID,值 {name, note};成员由 layers[].group 派生
background背景底图段:preset / 四插槽 membership / theme / font 等
basemap底图导入注册(并存"并入了什么",与 background 分键)
styleImports条目化多槽样式导入清单
importsImport 卡片 UI 态(键 = source id)
globals无样式根的 Global 值(snow / rain / picking)
fonts / palette / interaction自定义字族 / 色板 / 交互高亮缺省色

版本双轴怎么演进 ​

加新键:version 不动,运行时读入忽略未知键。改键名或改语义:version 递增,在迁移注册表登记。值词表单独一个 valueVersion,因为值的形态演化和文档结构演化节奏不同。历史与未来的输入由装载管线消化,canonical Schema 只严格描述"当前合法形态"——两层职责分开,Schema 才敢用 additionalProperties: false。

值词表 v4:props 里能写什么 ​

layers.*.props 的值共用一套词表(core/config/layer-config-codec.ts),图层详情的 JSON 面板、持久化 config、表单缓存三处同源。以 form 判别:

形态结构说明
常量标量裸存(字符串/数字/布尔/null)数组和普通对象常量必须包成 {form:'literal', value}——v4 的关键变化,与 MapLibre 表达式数组划清界线
{form:'zoom'}base? stops跨缩放插值,stops 统一 {at, value}
{form:'step'}stops跨缩放阶梯
{form:'data'}field(或 input:{kind:'raw',expr})+ stops跨数据值
{form:'conditions'}field + conditions:[{when,value}] + fallback数据条件,when 收标量或同质数组
{form:'raw'}expr公式封存位

停靠点的 value 位可以递归嵌套另一个 form 对象(比如 zoom 停靠点里嵌数据条件),这是编辑器里"停靠点嵌套"功能的存储形态。base 缺省 1(线性)省略不写;note 键读入容忍但导出不产出;旧词表 v1/v2/v3 都能读入,读入路径归一,导出恒 v4。校验失败返回 {ok:false, error} 中文文案,不静默。

一段真实的 v4 片段(zoom 插值里嵌数据条件,外加 hover 交互覆盖):

jsonc
{
  "layers": {
    "water": {
      "type": "fill",
      "name": "水域",
      "props": {
        "fill-color": { "form": "zoom", "base": 1.5, "stops": [
          { "at": 5, "value": "#aad3df" },
          { "at": 12, "value": { "form": "conditions", "field": "class",
            "conditions": [{ "when": ["lake", "pond"], "value": "#45cfdd" }],
            "fallback": "#aad3df" } }
        ] }
      },
      "interactions": { "hover": { "props": { "fill-color": "#fbb03b" } } }
    }
  }
}

项目信封:.ms-project.json v2 ​

单文件项目是三(四)段信封:format: 'map-style-project' + version: 2 + style(渲染真源)+ config(ms-config 段)+ 可选 interactions(附属交互档)和 history(撤销条目,随草稿落盘、redo 除外)。

版本迁移只有一个入口:core/persistence/migrations.ts 的注册表。PROJECT_MIGRATIONS[v] 负责把 v 升到 v+1,消费方一律调 migrateAlong 沿链升级,缺迁移器直接抛错。纪律是注册表式、禁止散落 if:新版本在这里登记,v2 起不许用"可选加法字段"绕过版本号。当前登记的 v1→v2 迁移做四件事:styleName 改写 config.name、抽取旧约定键入 config、样式一次性剥离全部 mapstudio:* 键、v1 的 form 段装载即弃。

装载链对坏数据的态度是"宽松但响亮":坏 history 条目逐条丢弃、坏 interactions 条目逐条过滤,绝不因坏条目拒整档;域外版本或非整数 version 用中文报错拒绝。保存链单源在 composeProjectJson(core/persistence/project-format.ts),autosave 草稿和 ⌘S 导出共用;序列化超 2MB 上限先去 history 降级重试。

autosave 的行为:三文档任一变更 800ms 防抖后落 localStorage(键 ms-project-draft);pagehide 强制落盘;恢复走启动检测弹提示,不自动覆盖;旧 v1 草稿经同通道自动迁移。

FormDoc 和 ms-config 什么关系 ​

core/form/form.model.ts 的 FormDoc 是面板表单形态的运行时派生缓存:样式经 styleToFormDoc 派生,编辑经 FormStore.setProp 族乐观写入、effect 回灌收敛。它不持久化(v1 时代的 form 段装载即弃),持久的事实档只有 ms-config。正常保存时两者经 codec 恒等一致;所以改表单逻辑不用碰持久化格式,改词表才要两边同步。

约定字面量单源(数据兼容性锚点) ​

这些键名是数据兼容性的锚点,必须从 shared/style-conventions.ts 引用,禁止在业务代码里写字面量:

  • BASEMAP_META_KEY(mapstudio:basemap)与 MAPSTUDIO_META_PREFIX(mapstudio:)
  • STYLE_PROTECTED_META_KEY(受保护标记)
  • UI_ONLY_LAYER_KEYS(UI-only 图层键集)
  • 底图注册名派生 basemapMarkerOf(两处消费共用,口径改动只改这一处)
  • 交互事件元组 INTERACTION_EVENT_KEYS(在 shared/interaction-layer)

改任何一个键名都等于改用户数据格式,必须走迁移器,并在评审里明说。

工程配置速查(editor/) ​

文件要点
vite.config.ts端口 4230(strictPort);插件链 tailwind + analog + mock 插件 + maplibreWorkerAssetsPlugin;manualChunks 分包 angular/maplibre/monaco/vendor
vitest.config.tsnode 环境;include 为 tests/** + mock/**;覆盖率阈值 95/90/95/95 仅 --coverage 时加载
tsconfig.jsonstrict + isolatedModules;noEmit:false 是 analog 约束,零产物检查走 npm run typecheck
tsconfig.mfe.jsonmfe 入口专项类型检查,姊妹仓在场时启用
stryker.config.json突变试点仅四个纯函数域;incremental 缓存本地留存

mock 端点(/mock/klokantech.json、/mock/planet、/mock/terrain/*、字体与 sprite 等,清单在 editor/mock/README.md)是 dev/preview 的 vite 插件,不进构建产物,生产由 Rust server 承接——这是部署时最常见的 404 来源,详见构建与部署。

环境变量 ​

变量作用域用途
MS_URLe2e / 用例套件覆盖被测基址(默认 dev :4230)
VISUAL_TOLERANCE_PCT视觉基线差异像素阈值(默认 0.4%,nightly Linux 放宽 3%)
E2E_SKIP_BUILD / E2E_FORCE_BUILD / E2E_PARALLELtools/e2e.mjs跳过/强制重建 dist、并行度控制