Semver

语义化版本控制规范(SemVer)
以下关键词 MUST、MUST NOT、REQUIRED、SHALL、SHALL NOT、SHOULD、SHOULD NOT、 RECOMMENDED、MAY、OPTIONAL 依照 RFC 2119 的叙述解读。

使用语义化版本控制的软件必须(MUST)定义公共 API。该 API 可以在代码中被定义或出现于严谨的文件内。无论何种形式都应该力求精确且完整。

标准的版本号必须(MUST)采用 X.Y.Z 的格式,其中 X、Y 和 Z 为非负的整数,且禁止(MUST NOT)在数字前方补零。X 是主版本号、Y 是次版本号、而 Z 为修订号。每个元素必须(MUST)以数值来递增。例如:1.9.1 -> 1.10.0 -> 1.11.0。

标记版本号的软件发行后,禁止(MUST NOT)改变该版本软件的内容。任何修改都必须(MUST)以新版本发行。

主版本号为零(0.y.z)的软件处于开发初始阶段,一切都可能随时被改变。这样的公共 API 不应该被视为稳定版。

1.0.0 的版本号用于界定公共 API 的形成。这一版本之后所有的版本号更新都基于公共 API 及其修改内容。

修订号 Z(x.y.Z | x > 0)必须(MUST)在只做了向下兼容的修正时才递增。这里的修正指的是针对不正确结果而进行的内部修改。

次版本号 Y(x.Y.z | x > 0)必须(MUST)在有向下兼容的新功能出现时递增。在任何公共 API 的功能被标记为弃用时也必须(MUST)递增。也可以(MAY)在内部程序有大量新功能或改进被加入时递增,其中可以(MAY)包括修订级别的改变。每当次版本号递增时,修订号必须(MUST)归零。

主版本号 X(X.y.z | X > 0)必须(MUST)在有任何不兼容的修改被加入公共 API 时递增。其中可以(MAY)包括次版本号及修订级别的改变。每当主版本号递增时,次版本号和修订号必须(MUST)归零。

先行版本号可以(MAY)被标注在修订版之后,先加上一个连接号再加上一连串以句点分隔的标识符来修饰。标识符必须(MUST)由 ASCII 字母数字和连接号 [0-9A-Za-z-] 组成,且禁止(MUST NOT)留白。数字型的标识符禁止(MUST NOT)在前方补零。先行版的优先级低于相关联的标准版本。被标上先行版本号则表示这个版本并非稳定而且可能无法满足预期的兼容性需求。范例:1.0.0-alpha、1.0.0-alpha.1、1.0.0-0.3.7、1.0.0-x.7.z.92。

版本编译信息可以(MAY)被标注在修订版或先行版本号之后,先加上一个加号再加上一连串以句点分隔的标识符来修饰。标识符必须(MUST)由 ASCII 字母数字和连接号 [0-9A-Za-z-] 组成,且禁止(MUST NOT)留白。当判断版本的优先层级时,版本编译信息可(SHOULD)被忽略。因此当两个版本只有在版本编译信息有差别时,属于相同的优先层级。范例:1.0.0-alpha+001、1.0.0+20130313144700、1.0.0-beta+exp.sha.5114f85。

版本的优先层级指的是不同版本在排序时如何比较。判断优先层级时,必须(MUST)把版本依序拆分为主版本号、次版本号、修订号及先行版本号后进行比较(版本编译信息不在这份比较的列表中)。由左到右依序比较每个标识符,第一个差异值用来决定优先层级:主版本号、次版本号及修订号以数值比较,例如:1.0.0 < 2.0.0 < 2.1.0 < 2.1.1。当主版本号、次版本号及修订号都相同时,改以优先层级比较低的先行版本号决定。例如:1.0.0-alpha < 1.0.0。有相同主版本号、次版本号及修订号的两个先行版本号,其优先层级必须(MUST)透过由左到右的每个被句点分隔的标识符来比较,直到找到一个差异值后决定:只有数字的标识符以数值高低比较,有字母或连接号时则逐字以 ASCII 的排序来比较。数字的标识符比非数字的标识符优先层级低。若开头的标识符都相同时,栏位比较多的先行版本号优先层级比较高。范例:1.0.0-alpha < 1.0.0-alpha.1 < 1.0.0-alpha.beta < 1.0.0-beta < 1.0.0-beta.2 < 1.0.0-beta.11 < 1.0.0-rc.1 < 1.0.0。

参考资料:
Semantic Versioning 2.0.0
npm semver
package semver
Understanding Maven Version Numbers
Maven Artifact
Use Java 9’s own builtin Version class
How does maven sort version numbers?

在 docker 中设置 node.js 时区

CI 使用 Docker 打包前端代码,流程中有使用 Shell 和 Node.js 两种方式输出时间。
Shell 脚本用 $(date ‘+%F %T’) 输出的是东 8 区字符串 2021-05-27 14:43:23
Node.js 用 new Date().toString() 输出的是 0 时区字符串 Thu May 27 2021 06:43:09 GMT+0000 (Coordinated Universal Time)

经验证,虽然已将宿主机 /etc/localtime 挂载至 Docker 同路径,但仍需要配置环境变量 TZ=Asia/Shanghai 才可生效。
似乎是 V8 引擎在浏览器环境与服务器环境的实现方案不一致造成的。该 TZ 参数暂时不支持 Windows 但很快就会支持。

另外,顺便发现 new Date() 在解析不带时区的时间字符串时,ES5 和 ES6 有不同的规范。

参考资料:
https://github.com/nodejs/node/issues/19480
https://github.com/nodejs/node/issues/28743
https://github.com/nodejs/node/issues/4230
https://github.com/nodejs/docker-node/issues/626
https://github.com/gliderlabs/docker-alpine/issues/136
https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
https://www.gnu.org/software/libc/manual/html_node/TZ-Variable.html
https://docs.microsoft.com/en-us/cpp/c-runtime-library/time-management?view=msvc-160
https://github.com/nodejs/node/blob/4ebb88fea5a9d83f2c4ec566e958d735f1fca138/deps/v8/src/base/platform/platform-win32.cc#L131

Apple M1 CPU 踩到的坑

  1. Homebrew 安装后未生效
    解决方案:
    在安装后手动执行(注意安装日志最后输出的提示)
    echo ‘eval $(/opt/homebrew/bin/brew shellenv)’ >> ~/.zprofile
    参考资料:
    https://github.com/Homebrew/install/blob/master/install.sh#L745
  2. Node.js Check failed: allocator->SetPermissions
    解决方案:
    升级到 14.17.0 或 15.9.0
    参考资料:
    https://github.com/nodejs/node/issues/37061#issuecomment-770863819
    https://github.com/nodejs/node/issues/37061#issuecomment-780499544
    https://github.com/nodejs/node/pull/38507
    https://github.com/nodejs/node/pull/38051
    https://github.com/nodejs/node/issues/37309

Chrome 85 的 content-visibility 会影响 position: absolute 的策略。

Chrome 85 之后,提供了 content-visibility 属性,用于优化渲染性能,放弃布局或绘制不可见元素。
经测试,对于长列表等结构,优化大幅提升。还不用修改业务逻辑,性价比极高。不过要注意,还是副作用的。
目前已经发现,应用了该属性的元素会影响绝对定位子元素的布局策略:
原 absolute 的元素会相对于最近的非 static 祖先元素定位,现会相对于当前元素定位。

参考:
content-visibility: the new CSS property that boosts your rendering performance
Cascading Style Sheets position

Chrome 88 似乎启用了对 ::selection:not() 的支持?

升级到 Chrome 88 后,发现选中文本后的蓝色背景没有了。
经过排查后发现 87 和 88 版本的差异在于一个代码中存在很久的 CSS 伪类 ::selection:not(input) { background: rgba(0,0,0,0); }
87 版本的 Styles 中不存在该伪类,但 88 版本中存在,造成蓝色背景丢失,白色字体配白色背景看上去好像文字丢失了一样。