后端前端云原生【免费下载链接】hedgedocHedgeDoc - Ideas grow better together项目地址https://gitcode.com/gh_mirrors/he/hedgedoc点击查看免费下载HedgeDoc 内置了经典的MotDMessage of the Day每日消息功能用于在用户打开实例时展示一条可定制的公告。本指南以仓库中 frontend/public/public/motd.md与 backend/public/motd.md 内容一致为核心入口完整讲解 MotD 文件的默认内容、后端静态服务的提供方式、前端获取与缓存去重逻辑、Markdown 渲染管线以及覆盖该功能的端到端测试让读者既能直接上手自定义公告也能理解其底层工作原理。一、MotD 文件默认内容与文件定位motd.md是 HedgeDoc 中 MotD 消息的载体文件当前仓库中前后端各保留了一份完全相同的副本默认内容只有两行This is the test motd text :smile:第一行是一段普通的纯文本公告内容语义上等价于“这是一条测试用 MotD 文本”第二行的:smile:是 GitHub 风格的 emoji 短码表明 MotD 正文以完整的 Markdown 语法解析emoji 短码会被渲染为对应的表情符号。两份文件分别位于后端静态资源目录backend/public/motd.md前端公共资源目录frontend/public/public/motd.md从源码结构看真正对外提供服务的版本是后端目录中的那份后端通过 Fastify 静态文件插件把public文件夹整体映射到/public/URL 前缀详见下文而前端目录中的副本主要用于 Next.js 构建期的本地化场景。默认内容即为测试文本实例管理员在实际部署时应将其替换为自己的公告内容。二、后端如何提供 motd.md静态文件服务挂载HedgeDoc 后端NestJS Fastify在应用启动装配阶段注册静态文件服务相关实现位于 backend/src/app-init.tslogger.log(Serving the local folder public under /public, AppBootstrap); const path await import(path); await app.register(import(fastify/static), { root: path.resolve(public), prefix: /public/, decorateReply: false, });关键配置点root指向后端工作目录下的public文件夹motd.md即位于该目录内prefix/public/因此motd.md的最终访问 URL 为http(s)://实例地址/public/motd.mddecorateReply: false避免 Fastify 静态插件覆盖 reply 对象上的默认装饰。代码注释中还保留了开发团队的说明目前public文件夹的主要使用场景就是intro.md与motd.md两个文件未来也可能考虑将其改为 API 端点见 backend/src/app-init.ts 的 TODO 注释。得益于fastify/static对静态文件的处理浏览器请求该 URL 时响应头会自动携带Last-Modified或etag标识这为前端判断“MotD 是否更新过”提供了依据。三、前端获取 MotDfetch-motd 与变更检测前端通过 frontend/src/components/global-dialogs/motd-modal/fetch-motd.ts 完成 MotD 的拉取。其核心逻辑如下export interface MotdApiResponse { motdText: string lastModified: string } export const fetchMotd async (baseUrl: string): PromiseMotdApiResponse | undefined { if (isBuildTime) { return } const motdUrl ${baseUrl}public/motd.md const response await fetch(motdUrl, { ...defaultConfig, cache: undefined, next: { revalidate: 60 } }) if (response.status ! 200) { return } const lastModified response.headers.get(Last-Modified) || response.headers.get(etag) if (lastModified null) { return } return { lastModified, motdText: await response.text() } }可以提炼出如下要点请求地址${baseUrl}public/motd.mdbaseUrl为后端实例地址与后端/public/前缀一一对应构建期短路isBuildTime为真时直接返回undefined避免在静态构建阶段发起网络请求缓存策略显式设置cache: undefined并配合next: { revalidate: 60 }Next.js 增量静态再验证60 秒兼顾实时性与缓存开销变更标识从响应头中优先读取Last-Modified缺失时回退到etag两者皆无则不返回数据响应契约最终返回{ motdText, lastModified }其中motdText为原始 Markdown 文本lastModified供后续去重判断使用。获取结果通过 frontend/src/components/motd/motd-context.tsx 中定义的MotdProvider与useMotdContextValue注入全局 React Context供模态框与 About 页面共享。四、展示与缓存去重CachedMotdModal 的工作机制MotD 弹窗的“只在内容变化时展示一次”行为由 frontend/src/components/global-dialogs/motd-modal/cached-motd-modal.tsx 实现其关键逻辑const [cachedLastModified, saveLocalStorage] useLocalStoragestring(MOTD_LOCAL_STORAGE_KEY, undefined, { raw: true }) const show useMemo(() { const lastModified contextValue?.lastModified if (cachedLastModified IGNORE_MOTD isTestMode) { return false } if (cachedLastModified lastModified || lastModified undefined) { return false } return !dismissed }, [cachedLastModified, contextValue?.lastModified, dismissed])判断流程若localStorage中缓存的上次修改标识与当前lastModified相同说明 MotD 未更新弹窗不展示若后端未返回lastModified同样不展示测试模式下可通过特殊值IGNORE_MOTD强制屏蔽弹窗。用户点击“Dismiss关闭”后doDismiss会将当前lastModified写入 localStorage此后即使刷新页面也不再弹窗直到管理员修改了motd.md导致Last-Modified变化。相关存储键定义在 frontend/src/components/global-dialogs/motd-modal/local-storage-keys.tsexport const MOTD_LOCAL_STORAGE_KEY: string motd.lastModified export const IGNORE_MOTD: string IGNORE_MOTD弹窗本体由 frontend/src/components/global-dialogs/motd-modal/motd-modal.tsx 渲染使用CommonModal承载标题引用 i18n 键motd.title正文区包裹EditorToRendererCommunicatorContextProvider后渲染MotdContent底部提供common.dismiss翻译键对应的成功样式按钮同时只有motdText非空时才真正显示show (contextValue?.motdText.length ?? 0) 0。五、Markdown 渲染MotdContent 与 RendererIframeMotD 之所以支持 Markdown 与 emoji 短码是因为它复用了 HedgeDoc 的渲染器。核心组件 frontend/src/components/motd/motd-content.tsx 的实现const lines useMemo(() { const rawLines contextValue?.motdText.split(\n) if (rawLines undefined || rawLines.length 0) { return [] } return rawLines }, [contextValue?.motdText]) return ( RendererIframe frameClasses{w-100} rendererType{RendererType.SIMPLE} markdownContentLines{lines} adaptFrameHeightToContent{true} showWaitSpinner{true} / )要点将motdText按\n拆分为行数组传入RendererIframerendererType使用RendererType.SIMPLE即简化渲染模式adaptFrameHeightToContent{true}让 iframe 高度自适应内容避免出现滚动条渲染在 iframe 中完成正文区域加载时显示等待指示器。这意味着用户可以在motd.md中自由使用标题、列表、链接、粗体等 Markdown 语法包括:smile:这类 emoji 短码其渲染能力与普通笔记保持一致。此外frontend/src/components/about-page/motd-card.tsx 在“关于About”页面中以卡片形式复用了同一MotdContent让管理员和用户在不打开弹窗时也能查看当前公告。六、测试验证从单元测试到端到端MotD 功能拥有完整的测试覆盖可作为理解其行为契约的权威参考端到端测试frontend/cypress/e2e/motd.spec.ts 验证了完整用户旅程const motdMockHtml This is the test motd text describe(Motd, () { it(shows, dismisses and wont show again a motd modal, () { window.localStorage.removeItem(MOTD_LOCAL_STORAGE_KEY) cy.visitHistory() cy.getSimpleRendererBody().should(contain.text, motdMockHtml) cy.getByCypressId(motd-dismiss).click() cy.getByCypressId(motd-modal).should(not.exist) cy.reload() cy.get(main).should(exist) cy.getByCypressId(motd-modal).should(not.exist) }) })该用例完整覆盖了“首次访问显示弹窗 → 点击关闭 → 弹窗消失 → 刷新后不再显示”的完整流程与CachedMotdModal中基于lastModified的去重逻辑相互印证。测试断言正文中包含This is the test motd text与默认motd.md的测试文本完全对应。单元测试frontend/src/components/global-dialogs/motd-modal/fetch-motd.spec.ts 则针对请求地址拼接、响应状态码判断、Last-Modified/etag读取等分支进行验证。七、运维实践如何自定义你的 MotD综合以上机制实例管理员自定义公告的操作路径非常清晰修改文件编辑后端目录下的 backend/public/motd.md替换默认的测试文本支持完整的 Markdown 语法与 emoji 短码重新部署由于静态文件由后端进程直接读取修改后需要重新构建/重启后端容器参考 backend/docker/Dockerfile 与根目录 README.md 中的部署说明或根据部署方式挂载该文件为外部卷生效与去重用户端会在请求时通过响应头Last-Modified/etag感知到文件变更即使老用户已关闭过旧公告也会因为标识变化而再次看到新内容测试模式前端测试环境下可通过 localStorage 特殊值IGNORE_MOTD屏蔽弹窗不影响开发调试。结语HedgeDoc 的 MotD 功能虽然入口文件只有寥寥两行但其背后是一套完整的“静态文件服务 → 前端拉取 → Context 分发 → localStorage 去重 → iframe Markdown 渲染”链路。理解 motd.md 与 backend/src/app-init.ts、fetch-motd.ts、cached-motd-modal.tsx 等实现之间的协作关系既能帮助管理员快速定制公告也能为二次开发提供清晰的切入点。赞分享后端前端云原生【免费下载链接】hedgedocHedgeDoc - Ideas grow better together项目地址https://gitcode.com/gh_mirrors/he/hedgedoc点击查看免费下载相关推荐Ceph Dashboard MOTDMessage of the Day插件配置、过期机制与前端展示完全指南Ceph Dashboard MOTDMessage of the Day插件配置、过期机制与前端展示完全指南 导读 Ceph Dashboard 的 M存储分布式文件系统对象存储后端高可用Instructor 原生缓存机制全解析从 AutoCache 到自定义缓存后端的零配置性能优化Instructor 原生缓存机制全解析从 AutoCache 到自定义缓存后端的零配置性能优化 Instructor 从 v1.9.1 起内置了覆盖所有 P人工智能大模型AI 应用HedgeDoc 前端 Changelog 解读从 HedgeDoc 1 到 2 的功能演进、弃用与迁移指南HedgeDoc 前端 Changelog 解读从 HedgeDoc 1 到 2 的功能演进、弃用与迁移指南 本指南以 frontend/CHANGELOG.后端前端云原生上一篇Winhance界面全导览软件、优化、自定义三大模块一文看懂下一篇React 360 SEO终极指南让你的VR内容轻松被搜索引擎收录创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考