深入剖析 @emotion/hash:Emotion 的 MurmurHash2 哈希实现与 className 生成原理
深入剖析 emotion/hashEmotion 的 MurmurHash2 哈希实现与 className 生成原理【免费下载链接】emotion‍ CSS-in-JS library designed for high performance style composition项目地址: https://gitcode.com/gh_mirrors/em/emotionemotion/hash是 Emotion 系列包中一个极小却至关重要的基础模块它以 TypeScript 实现了经典的MurmurHash2非加密哈希算法。本文将以该包的 README 为骨架结合其 源码、测试 以及在serialize、babel-plugin、cache等包中的真实调用完整讲解它的 API 用法、算法逐段原理、base36 输出的设计考量以及它如何参与生成 Emotion 的css-*类名与 SSR 水合hydration过程。读完本文你将能独立读懂这段不到 70 行的哈希实现并理解为什么它是 Emotion 高性能样式组合体系的基石之一。一、emotion/hash 是什么根据 README 的定义emotion/hash就是A MurmurHash2 implementation——一个 MurmurHash2 算法的实现。它的源码源自经典的 murmurhash-js 项目garycourt/murmurhash-js 中的murmurhash2_gc.js并进一步对照 Austin Appleby 的原始smhasher仓库中MurmurHash2.cpp的参考实现移植而来这一移植关系在 packages/hash/src/index.ts 的源码注释中有明确记载。MurmurHash 是业界广泛使用的非加密哈希non-cryptographic hash算法族由 Austin Appleby 于 2008 年设计以雪崩效应好、分布均匀、速度极快著称特别适合字符串/键值哈希、哈希表、布隆过滤器以及为内容生成短标识符等场景。Emotion 之所以选中它正是因为样式字符串需要在每次渲染与构建时被快速哈希为稳定的短标识符而这恰好是 MurmurHash2 的强项。该包当前版本为 0.9.2见 packages/hash/package.json自 0.9.2 起源码已迁移为 TypeScript 编写见 packages/hash/CHANGELOG.md 中的迁移记录。二、快速上手API 与基本用法emotion/hash暴露的 API 极其简洁——一个默认导出函数入参为字符串返回该字符串的 MurmurHash2 哈希以 base36 字符串表示import hash from emotion/hash hash(some-string) // 12fj1d这一点从类型声明也能确认packages/hash/types/index.d.ts 只有一行将默认导出转发给包入口而 packages/hash/types/tests.ts 则对类型做了 dtslint 校验对应 package.json 中的test:typescript脚本。实际执行效果可以通过包自带的单元测试 packages/hash/tests/index.js 得到可复现的验证import hash from emotion/hash test(accepts a string and returns a string as a hash, () { expect(hash(something)).toBe(crsxd7) })也就是说输入字符串输出some-string12fj1dsomethingcrsxd7使用前提说明该函数只接受字符串输入返回固定长度通常 6 位左右取决于值的大小的 base36 字符串。它是同步、无状态的纯函数——相同的输入永远得到相同的输出这保证了 Emotion 生成的类名在不同环境浏览器、Node 服务端、构建期之间完全一致。三、MurmurHash2 算法原理源码逐段精读完整的算法实现位于 packages/hash/src/index.ts共 63 行函数签名与整体流程如下export default function murmur2(str: string): string { var h 0 // 初始化哈希值 var k, i 0, len str.length // ... 主循环每 4 字节一块混入哈希 // ... 尾部字节处理 // ... 最终混淆 return ((h ^ (h 15)) 0).toString(36) }3.1 常量与初始化算法注释中给出了两个混合常量mixing constants它们是通过离线调参得到的并非随手取的魔法数字注释原文为 Theyre not really magic, they just happen to work well// const m 0x5bd1e995; // const r 24; var h 0m 0x5bd1e995乘法混合常量r 24右移混合位数h初始为 0随后逐块累加混入。3.2 主循环每 4 字节一块for (; len 4; i, len - 4) { k (str.charCodeAt(i) 0xff) | ((str.charCodeAt(i) 0xff) 8) | ((str.charCodeAt(i) 0xff) 16) | ((str.charCodeAt(i) 0xff) 24) k (k 0xffff) * 0x5bd1e995 (((k 16) * 0xe995) 16) k ^ k 24 h ((k 0xffff) * 0x5bd1e995 (((k 16) * 0xe995) 16)) ^ ((h 0xffff) * 0x5bd1e995 (((h 16) * 0xe995) 16)) }这一步完成了三件事组块block用charCodeAt逐字符取出字节按小端序低字节在前拼成一个 32 位整数k。每个块为 4 字节。k 混合k乘以常量m然后异或k 24即乘以2^r再右移r位的复合效果。h 混合把混合后的k与当前的h各自乘m后异或得到新的h。值得注意的是由于 JavaScript 中的位运算会先把操作数转为 32 位整数而0x5bd1e995 * 0x5bd1e995这类乘法会超出 32 位安全范围因此源码采用了一个经典技巧用Math.imul的等价手写展开——即(k 0xffff) * m (((k 16) * (m 16)) 16)把 32 位乘法拆成高 16 位与低 16 位的组合乘法避免精度丢失。源码中的* 0x5bd1e995展开式中0xe995正是0x5bd1e995 16的十六进制表示。3.3 尾部字节处理当输入长度不足 4 的倍数时剩余 13 个字节进入switch分支注意 fall-through 的写法switch (len) { case 3: h ^ (str.charCodeAt(i 2) 0xff) 16 case 2: h ^ (str.charCodeAt(i 1) 0xff) 8 case 1: h ^ str.charCodeAt(i) 0xff h (h 0xffff) * 0x5bd1e995 (((h 16) * 0xe995) 16) }末尾字节同样按小端序放入h的高位case 3移 16 位、case 2移 8 位并在case 1处对h再做一次乘m的混合。3.4 最终混淆与输出h ^ h 13 h (h 0xffff) * 0x5bd1e995 (((h 16) * 0xe995) 16) return ((h ^ (h 15)) 0).toString(36)最后三段式混淆h ^ h 13→ 乘m→h ^ h 15用于确保末尾几个字节也被充分扩散源码注释 Do a few final mixes of the hash to ensure the last few bytes are well-incorporated。最终通过 0把结果强制转换为无符号 32 位整数再用.toString(36)转成base36 字符串返回。3.5 为什么输出用 base36toString(36)使用 0-9 与 a-z 共 36 个字符来编码一个 32 位无符号整数。这意味着更短32 位整数用十进制最多 10 位用 base36 通常只需 6 位如12fj1d、crsxd7可以直接拼接进css-xxx这样的类名而不显著增加 DOM 体积可读性全部为小写字母与数字避免大小写敏感问题也便于作为data-emotion属性值确定性同一字符串始终映射到同一短标识这是 Emotion 类名在客户端与服务端保持一致、从而支持 SSR 水合的前提。四、在 Emotion 生态中的实际应用emotion/hash的价值不在于它自身而在于它是 Emotion 类名生成链路的关键一环。仓库中有三个典型的使用点可以交叉印证。4.1 serializeStyles样式哈希生成类名在 packages/serialize/src/index.ts 中serializeStyles将插值处理后的完整样式字符串交给hashStringlet name hashString(styles) identifierName这里styles是经过插值、扁平化后的最终 CSS 文本identifierName则是从样式中的label:注释/label:\s*([^\s;{])\s*(;|$)/g提取出的可读标签。于是最终类名 样式内容的 MurmurHash2 base36 哈希 可读 label例如css-1rn8i3s或带 label 的css-1rn8i3s-Button。这正是 Emotion 中css与styled生成类名的底层机制。4.2 babel-plugin编译期生成稳定的目标类名在 Babel 插件的工具函数 packages/babel-plugin/src/utils/get-target-class-name.js 中emotion/hash被用来生成与文件路径无关、可预测的类名let hashArray (arr) hashString(arr.join()) // ... const stuffToHash [moduleName] if (finalPath) { stuffToHash.push(normalizePath(finalPath)) } else { stuffToHash.push(state.file.code) } const stableClassName e${hashArray(stuffToHash)}${positionInFile}实现会把包名 归一化后的相对文件路径拼成数组后交给hashString从而让同一源码文件在任意机器、任意绝对路径下都能编译出完全一致的类名这对于构建缓存与热更新非常重要。4.3 cache 测试SSR 水合中手动复算哈希cache 包的测试 展示了该哈希的可复现性如何被用于验证 SSR 水合测试直接用hashString(css)复算类名再断言插入的style标签内容与预期一致let hash hashString(css) expect(...).toEqual( style contenteditable="false">【免费下载链接】emotion‍ CSS-in-JS library designed for high performance style composition项目地址: https://gitcode.com/gh_mirrors/em/emotion创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

WT2605C串口转BLE数据透传:从UART到APP的全链路调试指南

WT2605C串口转BLE数据透传:从UART到APP的全链路调试指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/21 2:23:20 阅读更多 →
Handsontable 10.0 升级与迁移完全指南:Hook 体系重构、默认值变更与破坏性更新解析

Handsontable 10.0 升级与迁移完全指南:Hook 体系重构、默认值变更与破坏性更新解析

Handsontable 10.0 升级与迁移完全指南:Hook 体系重构、默认值变更与破坏性更新解析 【免费下载链接】handsontable JavaScript Data Grid / Data Table with a Spreadsheet Look & Feel. Works with React, Angular, and Vue. Supported by the Handsontable t…

2026/9/21 2:23:20 阅读更多 →
SF305000A冷水机控制器接线与故障排查:从参数到维修完整指南

SF305000A冷水机控制器接线与故障排查:从参数到维修完整指南

简介:《邦普SF305000A冷水机控制器.pdf》是一份完整的厂家使用说明书,面向冷水机设备安装、调试与维修人员,以及需要了解其控制逻辑的技术工程师。文档基于SF305000A控制器实际固件与硬件,系统列出安全要求、规格参数、安装尺寸图…

2026/9/21 2:22:19 阅读更多 →

最新新闻

windowsserver2003怎么给网站做域名解析对比评测

windowsserver2003怎么给网站做域名解析对比评测

3步搞定Windows Server 2003域名解析,老手揭秘性能优化避坑指南 域名服务器搞不懂,是很多老运维和新入行建站人员共同的噩梦。尤其是面对 Windows Server 2003…

2026/9/21 4:45:53 阅读更多 →
不懂代码想建站?电子商务主要就业岗位里哪家好

不懂代码想建站?电子商务主要就业岗位里哪家好

不懂代码想建站?电子商务主要就业岗位里哪家好 自己不会代码,却硬要搭个网站,这是很多中小老板踩过的坑。 别急着被“技术门槛”吓退,也别盲目找外包,问一句 哪家好 才是正道。 其实,搭建网站这件事,早就不是程序员的专利了。 只要选对路子,普通人也能把网站稳稳当当地立起来。 今天咱们不聊虚的,就聊聊在…

2026/9/21 4:32:34 阅读更多 →
合肥建站公司排名前十名揭秘:保姆级建站教程与选型指南

合肥建站公司排名前十名揭秘:保姆级建站教程与选型指南

合肥建站公司排名前十名揭秘:保姆级建站教程与选型指南 域名服务器配置报错,SSL证书部署失败,ICP备案卡在初审?别慌,这往往是新手在寻找 合肥建站公司排名前十名…

2026/9/21 4:18:24 阅读更多 →
ARIS 工作流总览:从 idea 到 paper 的 13 条 pipeline 如何一次看全

ARIS 工作流总览:从 idea 到 paper 的 13 条 pipeline 如何一次看全

ARIS 工作流总览:从 idea 到 paper 的 13 条 pipeline 如何一次看全 【免费下载链接】Auto-claude-code-research-in-sleep ARIS ⚔️ (Auto-Research-In-Sleep) — Lightweight Markdown-only skills for autonomous ML research: cross-model review loops, idea …

2026/9/21 4:06:15 阅读更多 →
Roc 格式化器幂等性测试实战:从 issue 8851 快照看多行分发与字段访问的格式化处理

Roc 格式化器幂等性测试实战:从 issue 8851 快照看多行分发与字段访问的格式化处理

Roc 格式化器幂等性测试实战:从 issue 8851 快照看多行分发与字段访问的格式化处理 【免费下载链接】roc A fast, friendly, functional language. 项目地址: https://gitcode.com/GitHub_Trending/ro/roc 导读:本文以 Roc 编译器仓库中的快照测试…

2026/9/21 4:04:14 阅读更多 →
TypePHP编译器API参考:程序化调用PHP AOT编译器的完整指南

TypePHP编译器API参考:程序化调用PHP AOT编译器的完整指南

TypePHP编译器API参考:程序化调用PHP AOT编译器的完整指南 【免费下载链接】typephp Compile PHP to Native Binaries 项目地址: https://gitcode.com/GitHub_Trending/ty/typephp TypePHP 是一款用 PHP 编写的原生 AOT 编译器(tpc)&a…

2026/9/21 4:04:14 阅读更多 →

日新闻

agents-generator 决策矩阵全解析:从项目检测到 AGENTS.md 规则生成的 16 步判定流程

agents-generator 决策矩阵全解析:从项目检测到 AGENTS.md 规则生成的 16 步判定流程

agents-generator 决策矩阵全解析:从项目检测到 AGENTS.md 规则生成的 16 步判定流程 【免费下载链接】agentic-awesome-skills AAS Core is the local, agent-first control plane for complete catalog discovery, agent-owned selection, stack validation, and …

2026/9/21 0:00:01 阅读更多 →
gin-vue-admin 前端工具函数全景指南:src/utils 复用规范与源码级解析

gin-vue-admin 前端工具函数全景指南:src/utils 复用规范与源码级解析

gin-vue-admin 前端工具函数全景指南:src/utils 复用规范与源码级解析 【免费下载链接】gin-vue-admin 🚀ViteVue3Gin拥有AI辅助的基础开发平台,企业级业务AI开发解决方案,内置mcp辅助服务,内置skills管理,…

2026/9/21 0:00:01 阅读更多 →
Wox 全功能插件开发实战指南:基于 Python / Node.js 宿主与 WebSocket 的持久化插件体系

Wox 全功能插件开发实战指南:基于 Python / Node.js 宿主与 WebSocket 的持久化插件体系

桌面应用AI 应用插件系统 【免费下载链接】Wox A cross-platform launcher that simply works 项目地址: https://gitcode.com/gh_mirrors/wo/Wox 点击查看 免费下载 全功能插件(Full-featured Plugin)是 Wox 三类插件实现方式中能力最完整的…

2026/9/21 0:00:01 阅读更多 →

周新闻

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

直接铺开项目本身吧。这几个月我一直在折腾一件事:用Flutter给OpenHarmony做一款游戏集合类的App,说白了就是把若干小游戏塞进一个壳里,用统一入口分发。这个方向本身不算新鲜,真正让我花了不少心思的,是首页那堆游戏卡…

2026/9/21 3:13:20 阅读更多 →
Word表格编号全攻略:从列表编号到题注交叉引用

Word表格编号全攻略:从列表编号到题注交叉引用

写Word文档,最让人头疼的往往是那些“看起来不起眼”的小问题。比如表格编号这事:今天在表后面多加了两个空白行,明天给客户交稿前发现整个章节的编号全部错位,光是挨个改序号就能耗掉大半个下午。我前阵子帮人整理一份上百页的技…

2026/9/21 2:19:36 阅读更多 →
从第一个站到第二个站:独立开发者的静态网站选型与落地实践

从第一个站到第二个站:独立开发者的静态网站选型与落地实践

1. 项目概述1.1 核心需求解析做独立开发者这几年,说实话,第一个网站上线的那天晚上我兴奋得没睡着。但等它跑了半年,流量惨淡、功能臃肿、代码自己都懒得看第二遍之后,我才慢慢琢磨明白一个道理:第一个网站是练手&…

2026/9/21 4:51:05 阅读更多 →

月新闻

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能分类:[AI/大模型]细分主题:AI 增强型 CI/CD 流水线自动化与 GitOps 实践:Agent 工作流、工具调用与任务拆解:从原型到生产的验收清单很多团队在尝试用大…

2026/9/19 23:01:36 阅读更多 →
容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场分类:[工程技术]细分主题:Kubernetes 生产环境运维与排障实战:可复制的项目复盘模板与决策记录大部分团队的事故复盘报告,最后都变成了躺在 Confluence 或钉…

2026/9/19 17:50:38 阅读更多 →
容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步分类:[工程技术]细分主题:Docker 容器化技术与镜像安全管理:核心链路的逐步实现与关键代码取舍面对一个积累了五六年历史包袱的单体架构应用(包含 Web 接口、后台…

2026/9/19 23:35:34 阅读更多 →