Day.js 贡献者实战指南:从代码风格规范到 100% 测试覆盖率的完整工作流
2026/9/18 15:00:08 网站建设 项目流程

Day.js 贡献者实战指南:从代码风格规范到 100% 测试覆盖率的完整工作流

【免费下载链接】dayjs⏰ Day.js 2kB immutable date-time library alternative to Moment.js with the same modern API项目地址: https://gitcode.com/gh_mirrors/da/dayjs

本文基于 Day.js 仓库的 CONTRIBUTING.md 展开,系统梳理向 Day.js 提交贡献(PR、Bug 报告、locale/文档改进)的完整流程与硬性规范,并结合 package.json、ESLint/Jest 配置与 GitHub Actions 工作流源码,讲清楚代码风格、语义化提交、测试覆盖与 CI 校验的底层实现,帮助你在提交 Pull Request 前一次通过所有检查。

一、贡献入口:不只是写代码

CONTRIBUTING.md 开篇明确:贡献 Day.js 的方式远不止修代码一条路——提交 Bug 报告、改进 locale(本地化语言包)和文档、帮助社区成员,都是被欢迎的贡献形式。仓库中约 140 个 src/locale/ 语言文件(从 af.js 到 zh.js),本身就为 locale 类贡献提供了大量落点。

文档同时声明了社区基调:友好、欢迎、专业,不容忍辱骂、骚扰或其他不可接受的行为。

二、代码风格:ES6 + ESLint 的硬性约束

CONTRIBUTING.md 的 "Style" 章节给出三条规则:

  1. Day.js 使用 ES6 编写
  2. 使用 ESLint 检查代码,提交 PR 前运行npm run lint
  3. 使用语义化提交信息(semantic commit message)

2.1npm run lint到底检查什么

package.json 中 lint 脚本的定义为:

"lint": "./node_modules/.bin/eslint src/* test/* build/*"

即对src/test/build/三个目录做全量检查——这意味着你的新代码和改动涉及的测试文件都必须在风格上合规。

具体规则来自 .eslintrc.json,可以提炼出几个写代码时必须遵守的要点:

配置项取值实际含义
extendsairbnb-base以 Airbnb 基础风格为基线
semi["error", "never"]禁止使用分号
comma-dangle["error", "never"]禁止尾随逗号
no-param-reassign0允许给参数重新赋值
import/no-unresolved忽略dayjs测试中直接import dayjs from 'dayjs'不会被判为未解析依赖
pluginsjestjest/globals: trueit/expect等 Jest 全局可用,且启用 Jest 专用 lint 规则

注意globals中声明了window: truedayjs: true,这与 Day.js 面向浏览器/Node 双环境的测试方式一致。

2.2 更底层的编辑器约定

除了 ESLint,仓库还通过 .editorconfig 统一了最基本的编辑习惯:

  • 字符集utf-8
  • 换行符lf(LF,即 Unix 风格)
  • 文件末尾必须保留一个空行(insert_final_newline = true
  • 缩进 2 个空格

这些约定决定了你本地编辑器的默认行为应与仓库保持一致,避免 PR 中出现纯换行符/缩进类的"噪音 diff"。

2.3 提交前还有 pre-commit 兜底

package.json 中定义了 pre-commit 钩子:

"pre-commit": ["lint"]

配合 devDependencies 中的pre-commit包,安装依赖后每次git commit会自动触发 lint,风格问题在提交前即被拦截。

三、语义化提交:不只是规范要求,还驱动自动发版

"Please use semantic commit message" 在 Day.js 里并非形式主义。从 .releaserc 可以看到项目使用 semantic-release 做自动化发布:

  • 发布分支为master
  • 发布时自动更新并提交CHANGELOG.md@semantic-release/changelog+@semantic-release/git,assets 为CHANGELOG.md)。

也就是说,提交信息的 type(feat:fix:等)会被 semantic-release 用来判断版本号升级策略并生成 CHANGELOG.md 条目。此外 .github/workflows/release.yml 显示:推送到master后,CI 会先跑 lint + test,再执行npm run build && npm run babelnpm audit signatures验证产物签名,最后运行npx semantic-release完成发版。对贡献者而言,遵循语义化提交等于让自动化工具正确对待你的改动。

四、Bug 报告:先搜索,再按模板提交

CONTRIBUTING.md 的 "Bugs" 章节给出四条要求,逐条展开:

  1. 提交前先搜索已有 issues——你的问题可能已被讨论甚至解决;
  2. 即使 issue 已关闭,也欢迎补充评论;
  3. 标题和报告要详尽,不要遗漏重要细节;
  4. 请使用英文

仓库里为第 3 条提供了具体抓手:.github/ISSUE_TEMPLATE/--bug-report.md 是 Bug 报告模板,要求填写:

  • Describe the bug:清晰描述问题;
  • Expected behavior:期望行为;
  • Information:Day.js 版本号(如 v1.0.0)、操作系统、浏览器及版本(如 chrome 62)、时区(如 GMT-07:00 DST)。

特别要注意"时区"这一项。Day.js 是日期时间库,大量 Bug(尤其是 DST、跨时区 diff、startOf/endOf)与时区强相关;模板强制填写时区,与下文测试体系中的多时区验证思路一脉相承——缺少时区信息的日期 Bug 报告很难被复现。

五、测试规范:目录约定、100% 覆盖率与多时区策略

CONTRIBUTING.md 的 "Tests" 章节是全文最"硬核"的部分:

  • 如果现有测试文件都不适合你的用例,可以新建test/*.test.js文件
  • 帮我们保持 100% 测试覆盖率
  • 提交 PR 前运行npm run test

下面结合仓库配置逐条落地。

5.1 Jest 配置:哪些文件会被识别为测试

package.json 中的 Jest 配置:

"jest": { "roots": ["test"], "testRegex": "test/(.*?/)?.*test.js$", "testURL": "http://localhost", "coverageDirectory": "./coverage/", "collectCoverage": true, "collectCoverageFrom": ["src/**/*"] }

要点:

  • testRegex: "test/(.*?/)?.*test.js$"精确解释了 CONTRIBUTING 中"新建test/*.test.js"的含义:文件名必须以.test.js结尾、且放在test/目录(含子目录)下,才会被 Jest 识别。现有测试按主题分目录组织:核心行为(如 test/manipulate.test.js、test/get-set.test.js)、插件(test/plugin/ 下每个插件一个文件,如 test/plugin/weekday.test.js)、locale(test/locale/)以及针对具体 issue 的回归测试(test/issues/)。
  • collectCoverageFrom: ["src/**/*"]+collectCoverage: true:覆盖率统计范围是整个src/目录(含全部 locale 与 plugin 源码),这正是"100% 覆盖率"目标的范围定义。

5.2npm run test:四遍时区 + 100% 行覆盖门槛

test脚本比"跑一遍 Jest"复杂得多:

"test": "cross-env TZ=Pacific/Auckland npm run test-tz && cross-env TZ=Europe/London npm run test-tz && cross-env TZ=America/Whitehorse npm run test-tz && npm run test-tz && jest --coverage --coverageThreshold=\"{ \\\"global\\\": { \\\"lines\\\": 100} }\"", "test-tz": "date && jest test/timezone.test --coverage=false"

它分两步执行:

  1. 多时区预检:以TZ=Pacific/Auckland(新西兰)、Europe/London(伦敦)与America/Whitehorse(白horse,北美)依次运行 test/timezone.test.js(每轮前先date打印系统时间便于排查);最后一遍不设置 TZ,使用执行环境默认时区再跑一次。这三处时区恰好覆盖南半球与北半球的夏令时(DST)切换差异;
  2. 全量测试 + 覆盖门槛jest --coverage --coverageThreshold="{ \"global\": { \"lines\": 100 } }"——行覆盖率低于 100% 会直接导致测试命令失败,这就是 "Help us keep 100% test coverage" 的工程化保证:你的 PR 若没有为新代码补测试,本地npm run test就会红。

5.3 测试代码怎么写:从现有用例提取模式

阅读 test/timezone.test.js 与 test/plugin.test.js 可以归纳出仓库测试的通用模式,供你写新测试时参照:

(1)用 MockDate 冻结"现在"

几乎所有测试都用mockdate包在beforeEach/afterEach中控制时间:

import MockDate from 'mockdate' beforeEach(() => { MockDate.set(new Date()) }) afterEach(() => { MockDate.reset() })

(2)以 moment 为参照实现做行为对齐

devDependencies 中固定了moment: 2.29.2moment-timezone: 0.5.31,用途是"对照基准":test/timezone.test.js 中大量断言形如

expect(dayjs('2018-04-01').add(1, 'd').format()).toBe(moment('2018-04-01').add(1, 'd').format())

即验证 Day.js 在 DST 边界、diff、utcOffset 等场景下与 moment 行为一致。写涉及边界行为的测试时,这是仓库认可的做法。

(3)插件测试直接调用dayjs.extend

test/plugin.test.js 展示了最小插件测试的写法:定义一个会修改c.prototype(注入实例方法)和d(注入静态方法)的插件函数,再断言dayjs().newApi()dayjs.newFunc()的行为——这与 src/plugin/ 下所有插件的(o, c, d) => ...签名一致,也是你为新插件写测试时的模板。

(4)dayjs依赖通过 mock 指回源码

test/mocks/dayjs.js 仅两行:

const dayjs = require('../../src') module.exports = dayjs

它让测试中import dayjs from 'dayjs'实际解析到本地src/,保证测试始终针对仓库当前代码而非已发布的 npm 版本。

六、提交前的本地验证清单与 CI 校验

把 CONTRIBUTING.md 的要求落成一份可执行的提交前清单:

# 1. 安装依赖(含 pre-commit 钩子注册) npm install # 2. 代码风格检查(等价于 lint 脚本:eslint src/* test/* build/*) npm run lint # 3. 多时区测试 + 全量测试 + 100% 行覆盖门槛 npm run test

CI 侧会再做一次同样的校验。从 .github/workflows/check.yml 与 .github/workflows/lint-test.yml 可见:

  • 触发时机:推送到dev分支或指向dev的 Pull Request;
  • 环境:ubuntu-latest+ Nodelts/*(启用 npm 缓存);
  • 步骤:npm installnpm run lintnpm test,可选上传覆盖率到 Codecov。

也就是说,本地清单里任何一项失败,PR 在 CI 中同样会失败——提交前本地跑通npm run lint && npm run test是最省时间的做法。

七、其他相关规范与工具速查

围绕 CONTRIBUTING.md 的核心流程,仓库中还有几处值得贡献者了解的配套设施:

  • 文档格式:package.json 中prettier脚本为prettier --write "docs/**/*.md",配合 prettier.config.js,用于统一docs/下文档的排版;改进 docs/en/、docs/zh-cn/ 等多语言文档时可用它保持一致风格。
  • 构建与体积约束build脚本为cross-env BABEL_ENV=build node build && npm run size,babel.config.js 中build环境使用@babel/preset-envmodules: false, loose: true);同时 package.json 的size-limitdayjs.min.js上限锁在2.99 KB——任何可能增大核心包体的改动都需要格外谨慎,这也是 Day.js 保持 2kB 体量的工程化手段之一。
  • 自动发版:.releaserc + release.yml + patches/ 中的@semantic-release+github+11.0.4.patch(经npx patch-package应用),共同构成"master 推送即自动发版"的流水线;贡献者理解这一点,就能明白语义化提交与 PR 合入master之间的关系。

八、总结

环节CONTRIBUTING.md 要求仓库中的落地证据
代码风格ES6 + ESLint,PR 前npm run lint.eslintrc.json(airbnb-base、禁分号/尾逗号)、.editorconfig、pre-commit 钩子
提交信息语义化提交.releaserc 的 semantic-release 配置、release.yml
Bug 报告先搜索 issues、信息详尽、使用英文ISSUE_TEMPLATE 要求版本/OS/浏览器/时区
测试可新建test/*.test.js,保持 100% 覆盖,PR 前npm run testpackage.json Jest 配置(collectCoverageFrom: src/**/*、行覆盖门槛 100%)、四遍多时区test-tz预检

遵循上述流程——按 ES6 + ESLint 风格写代码、用语义化信息提交、按模板提交 Bug、为新代码补足让行覆盖率维持在 100% 的测试,并在本地跑通npm run lintnpm run test——你的 Pull Request 就能在 Day.js 的 CI(lint + 多时区测试 + 覆盖率门槛)中顺利通过,这也是仓库对每位贡献者的完整技术期待。

【免费下载链接】dayjs⏰ Day.js 2kB immutable date-time library alternative to Moment.js with the same modern API项目地址: https://gitcode.com/gh_mirrors/da/dayjs

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询