Logo

site icon李瑞豪

一名前端開發工程師,hugo-fixit 的創建者,經常在 菠菜眾長 1 和 FixIt2 上撰寫文章和文檔。
请复制 RSS 到你的阅读器,或快速订阅到 :

Inoreader Feedly Follow Feedbin Local Reader

李瑞豪 RSS 预览

Command line tool for generating a changelog from git tags and commit history

2025-08-30 23:40:19

auto-changelog-plus

中文 | English

从 git 提交历史自动生成 changelog 的命令行工具。

基于 auto-changelog约定式提交 规范。

npm version

📦 安装

1
npm install -g auto-changelog-plus

🚀 用法

在 git 仓库根目录运行 auto-changelog-plus 或者 acp。工具会在后台运行 git log 来解析提交历史。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
Usage: auto-changelog-plus [options]

Options:
 -o, --output [file] # output file, default: CHANGELOG.md
 -c, --config [file] # config file location, default: .auto-changelog
 -t, --template [template] # specify template to use [compact, keepachangelog, json], default: compact
 -r, --remote [remote] # specify git remote to use for links, default: origin
 -p, --package # use version from package.json as latest release
 -v, --latest-version [version] # use specified version as latest release
 -u, --unreleased # include section for unreleased changes
 -l, --commit-limit [count] # number of commits to display per release, default: 3
 -b, --backfill-limit [count] # number of commits to backfill empty releases with, default: 3
 --commit-url [url] # override url for commits, use {id} for commit id
 --issue-url [url] # override url for issues, use {id} for issue id
 --merge-url [url] # override url for merges, use {id} for merge id
 --compare-url [url] # override url for compares, use {from} and {to} for tags
 --issue-pattern [regex] # override regex pattern for issues in commit messages
 --breaking-pattern [regex] # regex pattern for breaking change commits
 --merge-pattern [regex] # add custom regex pattern for merge commits
 --commit-pattern [regex] # pattern to include when parsing commits
 --ignore-commit-pattern [regex] # pattern to ignore when parsing commits
 --tag-pattern [regex] # override regex pattern for version tags
 --tag-prefix [prefix] # prefix used in version tags, default: v
 --starting-version [tag] # specify earliest version to include in changelog
 --starting-date [yyyy-mm-dd] # specify earliest date to include in changelog
 --ending-version [tag] # specify latest version to include in changelog
 --sort-commits [property] # sort commits by property [relevance, date, date-desc, subject, subject-desc], default: relevance
 --release-summary # display tagged commit message body as release summary
 --unreleased-only # only output unreleased changes
 --hide-empty-releases # hide empty releases
 --hide-credit # hide auto-changelog credit
 --handlebars-setup [file] # handlebars setup file
 --append-git-log [string] # string to append to git log command
 --append-git-tag [string] # string to append to git tag command
 --prepend # prepend changelog to output file
 --stdout # output changelog to stdout
 -V, --version # output the version number
 -h, --help # output usage information

以下是一些常见的使用示例:

1
2
3
4
5
6
7
8
# 在当前目录写入日志到 CHANGELOG.md
auto-changelog-plus

# 使用 keepachangelog 模板写入日志到 HISTORY.md
auto-changelog-plus --output HISTORY.md --template keepachangelog

# 禁用提交限制,渲染每个发布的所有提交
auto-changelog-plus --commit-limit false

执行 auto-changelog-plus -h 获取帮助或者参考 auto-changelog 文档。

📝 约定式提交

基于 约定式提交 规范,支持以下类型的提交:

  • feat: 新功能
  • fix: 修复问题
  • perf: 性能优化
  • refactor: 代码重构
  • docs: 文档变更
  • test: 测试相关
  • style: 代码格式调整
  • chore: 构建过程或辅助工具的变动
  • build: 构建系统变动
  • ci: 持续集成配置变动
  • revert: 代码回滚
  • 支持 scope:feat(api):, fix(ui):
  • 支持 emoji::sparkles: feat:, ✨ feat:
  • 支持 Breaking Changes:feat!:, feat(scope)!:, BREAKING CHANGE: 等格式
  • 自动忽略 WIP 提交:wip:, Wip: 等临时提交不会包含在变更日志中

⚙️ 自动化使用

auto-changelog-plus 安装到开发依赖:

1
2
3
4
5
npm install auto-changelog-plus --save-dev
# 或
yarn add auto-changelog-plus --dev
# 或
pnpm add -D auto-changelog-plus

在你的 package.jsonversion 脚本中添加 auto-changelog-plus -p && git add CHANGELOG.md

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
{
 "name": "my-awesome-package",
 "version": "1.0.0",
 "devDependencies": {
 "auto-changelog-plus": "*"
 },
 "scripts": {
 "version": "auto-changelog-plus -p && git add CHANGELOG.md"
 }
}

使用 -p--packagepackage.json 中的 version 用作最新发布,这样以前发布和现在之间的所有提交都成为该发布的一部分。基本上任何通常被解析为 Unreleased 的内容现在都会出现在 package.jsonversion 下。

现在每次运行 npm version 时,changelog 将自动更新并成为版本提交的一部分。

在不是 NPM 包的项目中,可以使用 npxpnpx 来运行 auto-changelog-plus,例如:

1
2
3
npx auto-changelog-plus
# 或
pnpx auto-changelog-plus

在 GitHub Actions 中,你可以使用以下工作流来自动生成发布说明:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
name: Release for new tag

on:
 push:
 tags:
 - 'v*.*.*'
 workflow_dispatch:

jobs:
 release:
 runs-on: ubuntu-latest
 steps:
 - name: Checkout repository
 uses: actions/checkout@v5
 with:
 fetch-depth: 0 # Fetch all history for generating release notes

 - name: Setup Node.js
 uses: actions/setup-node@v5
 with:
 node-version: 'lts/*'

 - name: Generate release notes
 run: |
 npx auto-changelog-plus --starting-version ${{ github.ref_name }}
 sed -i '1,4d' CHANGELOG.md

 - name: GitHub Release
 uses: softprops/action-gh-release@v2
 with:
 draft: true
 body_path: CHANGELOG.md

🔄 和 auto-changelog 的区别

auto-changelog-plusauto-changelog 的上层封装,完全兼容 auto-changelog 的所有用法和配置。

主要改进:

  • 优化默认模板:更好地适配 约定式提交 规范
  • 调整默认配置:提供更合理的开箱即用体验
  • 扩展模板功能:提供额外的模板辅助函数

如果你正在使用 auto-changelog,可以直接替换为 auto-changelog-plus,无需修改任何配置。

📄 许可证

MIT

让 Mermaid 图表自动跟随系统深浅色

2025-08-16 12:37:49

featured image

Mermaid 是目前最流行的「文本即图表」渲染库,但它对「系统深浅色自动切换」的支持一直暧昧不明。官方 Roadmap 里偶有提及,却始终没有一个简单、稳定、文档化的 API。
不过社区里已有大量站点(mermaid.live、Obsidian、Notion-like 产品等)实现了丝滑的 Light/Dark 自适应。本文把目前能落地的三条路线一次性梳理出来,并给出最小可运行示例,方便你按需取用。

背景:Mermaid 主题机制与痛点

flowchart LR
 A(["Start"])
 A --> B{"Decision"}
 B -->|Yes| C["Option A"]
 B -->|No| D["Option B"]
flowchart LR
 A(["Start"])
 A --> B{"Decision"}
 B -->|Yes| C["Option A"]
 B -->|No| D["Option B"]
flowchart LR
 A(["Start"])
 A --> B{"Decision"}
 B -->|Yes| C["Option A"]
 B -->|No| D["Option B"]

Mermaid 在初始化时通过 theme 字段选定配色,例如:

1
mermaid.initialize({ theme: 'dark' });

但这条配置 只在首次渲染时生效。当用户在操作系统层面切到 Light/Dark,或者网页本身提供手动开关时,Mermaid 并不会自动重绘。这就导致:

  • 暗黑系统 + 浅色图表 ⇒ 刺眼
  • 浅色系统 + 暗黑图表 ⇒ 同样刺眼

社区 Issue #2644 早在 2022 年就提出希望官方支持 prefers-color-scheme,但至今(2025-08)仍未合入主干。

顺便提一下,主题的切换一般都有两种主流方式:

  1. 利用 prefers-color-scheme 感知系统级别主题变化,matchMedia('(prefers-color-scheme: dark)')change 事件。
  2. 通过 dark class 手动切换,这种方式通常会在 html/body 上设置一个 class 或者 data-theme="dark" 这样。

方案 1️⃣ Reinitialize

切换主题,重新 initialize + 重绘,这是目前来看大多数人的做法。

思路:

  1. 备份原始的 Mermaid code
  2. 设置 startOnLoad: false 避免 Mermaid 自动渲染,然后使用 mermaid.initialize({ theme: theme }) + mermaid.run() 完成初始化。
  3. 重新渲染时移除 data-processed,替换 .mermaid 的内容为原始 Mermaid code,使用 mermaid.initialize({ theme: newTheme }) + mermaid.run() 重新渲染

这份做法在 Issue #1945 里有完整代码,下面给出精简版:

优点是:

  • 利用现有官方 API

缺点是:

  • 每次切换都需要重新渲染,大图会闪一下
  • 如果页面里图表很多,性能损耗不可忽视
  • 还有异步处理带来的一系列问题

方案 2️⃣ CSS 滤镜

作为支持 prefers-color-scheme 和手动切换的一种简单的解决方案,可以使用 CSS 反转滤镜(inverthue-rotate 等)来实现。

例如:

1
2
3
4
5
6
7
8
9
[data-theme='dark'] .mermaid {
 filter: invert(0.88);
}

@media (prefers-color-scheme: dark) {
 :root:not([data-theme='light']) .mermaid {
 filter: invert(0.88);
 }
}

这条技巧是我在 Issue #2644 中看到的。

优点是:

  • 一行 CSS,无 JS
  • 不重新渲染,零延迟

缺点是:

  • 只是「反色」,并非官方暗黑主题
  • 对于红色、绿色等语义色会完全失真
  • 如果背景不是纯黑纯白,观感会很奇怪

由于太过简单,效果也很粗糙,适合做 Demo 或内部工具,不建议面向终端用户。

方案 3️⃣ 配置热替换

mermaid.live 站点能在用户切主题时瞬间完成切换,且颜色完全与官方暗黑主题对齐。从 源码 和 DevTools 推测,它大概做了三件事:

  1. 自己维护一份 themeCSS 字符串(而非仅用名字 'dark'
  2. prefers-color-scheme 变化时,直接把新的 CSS 注入到 <svg> 里的 <style> 节点
  3. 通过 mermaid.render('id', code) 拿到 SVG string 后,用正则替换掉旧 <style>,再 DOMParser 塞回页面

Issue #2644 中有提到,在 mermaid.live 中,目前是根据配色方案在配置中切换主题。

优点:

  • 无闪烁
  • 完全复用官方配色

缺点:

  • 需要内部维护主题 CSS,Mermaid 每升级一次都要同步
  • 实现细节依赖私有 API,官方一旦改动就会崩

如果你极度追求体验,可以照着源码抄一份,但要做好长期维护的心理准备。

#2644 中提到,在 mermaid.live 中,目前正在根据配色方案在配置中切换主题。这种方案暂时未找到更多的细节披露。我又懒得去深扒 mermaid.live 的实现细节。

方案 4️⃣ Reinitialize + CSS 结合

在我的实践中,FixIt 主题 是通过 data-theme 的方式手动切换网站主题的,我一开始走的思路和方案 1️⃣总体一致,为了处理这个方案的缺点,我多次迭代,有了最终的版本:

首先通过 type=module 引入 Mermaid:

1
2
3
4
5
import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.esm.min.js';
import zenuml from 'https://cdn.jsdelivr.net/npm/@mermaid-js/mermaid-zenuml/dist/mermaid-zenuml.esm.min.mjs';
await mermaid.registerExternalDiagrams([zenuml]);
mermaid.startOnLoad = false;
window.mermaid = mermaid;

然后在主题的切换逻辑中处理:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
initMermaid() {
 if (!this.config.mermaid) return;

 const themes = this.config.mermaid.themes ?? ['default', 'dark'];
 let processing = false;
 let delayTask = null;

 const loadMermaid = async () => {
 processing = true;
 // https://mermaid.js.org/config/schema-docs/config.html
 window.mermaid.initialize({
 startOnLoad: false,
 darkMode: this.isDark,
 theme: this.isDark ? themes[1] : themes[0],
 securityLevel: this.config.mermaid.securityLevel,
 look: this.config.mermaid.look,
 fontFamily: this.config.mermaid.fontFamily,
 altFontFamily: this.config.mermaid.fontFamily
 });
 await window.mermaid.run({
 querySelector: '.mermaid',
 suppressErrors: true,
 });
 processing = false;
 if (delayTask && typeof delayTask === 'function') {
 delayTask();
 delayTask = null;
 // console.log('Delayed task executed');
 }
 };

 const reloadMermaid = async () => {
 await this.util.forEach(document.querySelectorAll('.mermaid[data-processed]'), (el) => {
 el.removeAttribute('data-processed');
 el.parentElement.replaceChild(el.nextElementSibling.content.cloneNode(true), el);
 });
 await loadMermaid();
 };

 const waitForMermaid = () => {
 return new Promise((resolve) => {
 const timer = setInterval(() => {
 if (window.mermaid && window.mermaid.initialize) {
 clearInterval(timer);
 resolve();
 }
 }, 100);
 });
 };

 waitForMermaid().then(() => {
 loadMermaid();
 this.switchThemeEventSet.add(() => {
 if (processing) {
 console.warn('Mermaid is still processing, delaying the reload.');
 delayTask = reloadMermaid;
 return;
 }
 // console.log('reload immediately');
 reloadMermaid().catch(console.error);
 });

 this.beforeprintEventSet.add(() => {
 // Optionally set theme to 'neutral' for printing if required
 });
 })
}

为了缓解闪屏问题,利用 CSS 增加一个 Loading 效果,过度一下。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
.mermaid {
 position: relative;
 overflow: hidden !important;

 &[data-processed] {
 text-align: center;
 }

 &:not([data-processed])::before {
 content: '';
 position: absolute;
 top: 0;
 left: 0;
 width: 100%;
 height: 100%;
 backdrop-filter: blur(0.5rem);
 background-position: center;
 background-repeat: no-repeat;
 background-image: var(#{$rootPrefix}loading-img);
 background-size: 60px;
 }

 svg {
 max-width: 100%;
 height: auto; 
 }
}

说实话,虽然勉强达到了目的,这里的 delayTaskwaitForMermaid() 算得上妥妥的 Dirty Hack。也属实是无奈之举。


睡觉前我灵光乍现,为了避免每次切换主题时都要重新渲染 Mermaid 图表,我尝试一开始直接把 Mermaid 的 Light 和 Dark 主题的两个图都渲染了,然后由 data-theme 控制显示哪个图表。

尝试后发现 Mermaid 在渲染图时,如果这个元素是 display: none; 则会报错。

于是,我改成初始化时只渲染 Light/Dark SVG,等到主题切换时才渲染 Dark/Light SVG,并隐藏另一个 SVG。

这样同一个图只需要渲染两次,后续多次主题切换,就能够通过 CSS 非常丝滑的控制切换了,狠狠戳这里查看效果

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
<!DOCTYPE html>
<html lang="en">
<head>
 <meta charset="UTF-8">
 <meta name="viewport" content="width=device-width, initial-scale=1.0">
 <title>Mermaid Light/Dark Mode switching</title>
 <style>
 .diagrams-container {
 display: flex;
 justify-content: space-evenly;
 }
 .mermaid-container {
 .mermaid-dark {
 display: none;
 }

 [data-theme="dark"] & {
 .mermaid {
 display: none;
 }
 .mermaid-dark {
 display: block;
 }
 }
 }
 </style>
</head>
<body>
 <script>
 function toggleTheme() {
 const currentTheme = document.body.dataset.theme;
 const newTheme = currentTheme === 'dark' ? 'default' : 'dark';
 document.body.dataset.theme = newTheme;
 }
 </script>
 <button id="toggler">切换主题</button>
 <div class="diagrams-container">
 <div class="mermaid-container">
 <pre class="mermaid">graph TD;
 A[开始] --> B{是否完成?};
 B -- 是 --> C[结束];
 B -- 否 --> D[继续];
 D --> B;
 </pre>
 <pre class="mermaid-dark">graph TD;
 A[开始] --> B{是否完成?};
 B -- 是 --> C[结束];
 B -- 否 --> D[继续];
 D --> B;
 </pre>
 </div>
 </div>

 <script type="module">
 import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.esm.min.mjs';

 async function loadMermaid(theme) {
 const isDark = theme === 'dark';
 const querySelector = isDark ? '.mermaid-dark' : '.mermaid';
 mermaid.initialize({ startOnLoad: false, darkMode: isDark, theme });
 // Mermaid run 函数内部会跳过 data-processed 的元素,所以这样不会重复渲染
 await mermaid.run({ querySelector });
 }

 await loadMermaid('default')

 document.getElementById('toggler').addEventListener('click', () => {
 const currentTheme = document.body.dataset.theme || 'default';
 const newTheme = currentTheme === 'dark' ? 'default' : 'dark';
 document.body.dataset.theme = newTheme;
 loadMermaid(newTheme);
 });
 </script>
</body>
</html>

小结与选型建议

毋庸置疑,想要完美的体验,方案 3️⃣ 是最优选择, 方案 4️⃣ 作为方案 1️⃣ 的升级版,整体体验也相对较好。

方案 实现成本 体验 是否官方可维护
Reinitialize 中等(闪屏)
CSS invert 极低
mermaid.live 热替换 极佳
Reinitialize + CSS 较好
  • 内部文档 / 博客 / 小工具 ⇒ 方案 4️⃣
  • 赶时间的 MVP ⇒ 方案 2️⃣
  • 面向 C 端、对体验极端敏感 ⇒ 方案 3️⃣,但要准备长期跟进

黑盒出关・三把钥匙定江湖

2025-08-05 11:31:52

featured image

江湖传言,西土浏览器界有隐世高人,名曰“原生老祖”。老祖膝下三徒,各执一柄钥匙,开得了黑盒,锁得住乾坤。今日大话,诸位英雄且把耳洞放大,听我一一道来!

第一折・黑盒现世

昔日,React 少侠仗虚拟 DOM 之剑,Vue 剑仙携响应式绫罗,双雄争霸,血溅前端。

忽一日,电闪雷鸣,Chrome 山、Firefox 谷、Safari 崖三地同时金光乍现——一只乌漆嘛黑的小盒破空而出,盒上无门无派,只刻八字:

不拜山头,自成一派。

盒盖一开,三股真气冲天而起,惊得 React 剑锋一抖,Vue 绫罗乱颤。众修士齐呼:

“此乃何物?”

盒中悠悠传出一声:

“Web Components——浏览器亲儿子,江湖诨号:黑盒扫地僧。”


第二折・三把钥匙镇山门

铸兵符・Custom Elements

凡得此符者,可铸自家神兵。

1
<my-dog food="hotpot" mood="happy"></my-dog>

今日起,标签随你姓,语义随你编,浏览器照单全收,不查户口。

影分身・Shadow DOM

此术一开,样式、DOM、事件皆入黑屋,外头 CSS 千军万马,休想踏进半步。

“兄弟,你的 !important 呢?”
“抱歉,进了影分身,天王老子也得排队。”

袖里乾坤・HTML Templates & Slots

袖中一抖,模板千军万马;插槽轻点,内容各就各位。

无需编译,无需打包,一颗 <template> 漂洋过海,落地即插即用。

这是真正意义上的“一次编写,到处运行”——比 Java 当年喊的口号还真。


第三折・风云再起

黑盒既出,江湖格局瞬变:

  • 微前端:Vue2、Vue3、React18、Angular 同屏共舞,互不打脸。
  • 设计系统:按钮、输入框、LOGO 化身“原子暗器”,任何门派伸手即取。
  • 长尾奇袭:Chrome 插件、VS Code 插件、微信小程序、低代码山寨,皆呼“真香”。
  • 长寿秘籍:框架蜜月三年,黑盒随浏览器升级十年,npm 弃坑它不弃。

第四折・范式转移・浏览器登堂入室

当日头西斜,江湖忽然风起。众侠回头一看,浏览器老馆主身披龙袍、脚踏赤霄,一步跨上金銮殿。

旧朝遗诏:从“虚拟机”到“原生执政”

过去二十年,前端史是一部“夺权史”:

  • jQuery 夺的是 DOM 的刀;
  • Angular 夺的是模块的印;
  • React 夺的是渲染的剑;
  • Vue 夺的是状态的符。

四把大印加身,浏览器反成“空壳天子”。

而今,老馆主一声令下:“朕即框架,诸卿退班!”

三权分立:新标准下的江湖秩序

权柄 归属 职责 口号
立法权 WHATWG/W3C 写圣旨(HTML、CSS、DOM 标准) “凡入典章,万世不易。”
执法权 浏览器内核 掌御林军(渲染管线、沙箱、安全) “有朕一日,天下无刀兵。”
行政权 开发者 & 工具链 管民生(DX、脚手架、调试器) “百姓只用敲锣,不必造炮。”

Web Components 正是老馆主钦点的 “锦衣卫”

去框架化的三重暗涌

  1. 编译终点迁移

    昨日:Babel/Vite → React/Vue 运行时;

    今日:Babel/Vite → Web Components 原生指令。

    框架退居“DX 大臣”,不再染指最终字节码。

  2. 生态颗粒度下沉

    UI 库不再打包成“全家桶”,而是 CDN 单文件组件:

    1
    
    https://unpkg.com/@ui/button.js

    按需即取,HTTP 缓存即版本管理,npm install 沦为可选项。

  3. 生命周期归一

    React 的 useEffect、Vue 的 onMounted、Svelte 的 onMount

    最终都得翻译成同一套浏览器生命周期:

    connectedCallbackdisconnectedCallbackattributeChangedCallback

    框架语法糖越甜,底层 API 越收敛,直至“糖衣”可有可无。

未来图景:十年后的登基大典

  • 2027:浏览器内置 signals 提案落地,状态管理回归原生;
  • 2029:CSS @scope + @state 双剑合璧,Shadow DOM 自带响应式;
  • 2031:HTTP/4 多路复用 + Import Map 2.0,让“一行 <script type=importmap> 即 CDN 全图”成为标配。

届时,开发者只需写:

1
2
<my-app></my-app>
<script type="module" src="app.js"></script>

框架?

“哦,那是旧朝遗老,偶尔进宫讲史罢了。”

老馆主抚须长笑:
“昔日你们借我地基起高楼,今日我把高楼收归国有。

范式逆流,不是革命,是回家。”


尾声・血雨腥风

“老衲不挑框架,不拒工具,但有一语相赠:
十年之后,你迁移的是框架,还是我?”

江湖血雨腥风,黑盒已开。

要么守着旧山门,十年后再为迁移埋单;

要么此刻随扫地僧下山,让代码像 HTML 一样长青。

下回分解

“5 分钟,一指定乾坤——纯原生撸一只可复用计数器,再扔进 React、Vue、Svelte 乱炖!”


注意

哈哈哈哈哈哈哈,以抖机灵的形式简单聊了一下 Web Components 的发展历程和未来趋势。

我对 Web Components 充满了浓厚的兴趣,决定花点时间研究研究。
剩余的内容在 Web Components 系列文章 将会持续更新,敬请期待!

Code Playground

2025-08-04 11:37:24

以下是常见的在线代码演示和开发环境服务,适合不同场景使用:

名称 特点与适用场景 网址
CodeSandbox 支持前后端全栈开发,内置 Docker,支持 React、Vue、Node、Python 等,适合复杂项目 https://codesandbox.io
CodePen 专注于前端小效果演示,社区活跃,适合分享和展示 HTML/CSS/JS 片段 https://codepen.io
JSFiddle 轻量级前端代码片段运行环境,适合快速测试和分享小 demo https://jsfiddle.net
JS Bin 类似 JSFiddle,支持实时协作和分享,适合调试和教学 https://jsbin.com
Playcode.io 无需登录即可运行 JS/TS,界面类似本地 IDE,适合快速原型开发 https://playcode.io
Replit 支持多语言(如 Python、Java、C++),适合教育用途和全栈开发 https://replit.com
StackBlitz 基于浏览器的全栈 IDE,支持 Node、React、Angular 等框架,自动部署到 Vercel,适合快速原型和教程 https://stackblitz.com
Gitpod 基于 VS Code 的云端 IDE,适合 GitHub 项目快速启动和协作 https://gitpod.io
码上掘金 国内版轻量 Playground,支持 React、Vue 等框架,适合中文用户 https://code.juejin.cn

A custom web component that embeds caniuse.com browser compatibility data for a specific feature.

2025-07-22 11:40:45

<caniuse-embed> Element

npm version License

A lightweight, customizable web component that embeds caniuse.com browser compatibility data for specific web features. Built with Lit and designed to seamlessly integrate into any web project.

🌟 Live Demo

✨ Features

  • 🎯 Easy Integration: Drop-in web component that works with any framework or vanilla HTML
  • 🎨 Theme Support: Auto, light, and dark themes that adapt to your design
  • 📱 Responsive: Automatically adjusts height based on content
  • Lightweight: Built with Lit for minimal bundle size
  • 🛠️ Customizable: Configure data source, time range, and appearance
  • 🔒 Type Safe: Full TypeScript support with comprehensive type definitions

🚀 Quick Start

CDN (Recommended)

Add the script tag to your HTML:

1
<script src="https://unpkg.com/@cell-x/caniuse-embed-element/dist/caniuse-embed-element.iife.js"></script>

Then use the component:

1
<caniuse-embed feature="css-grid"></caniuse-embed>

NPM Installation

1
npm install @cell-x/caniuse-embed-element
1
import '@cell-x/caniuse-embed-element'

📖 Usage Examples

Basic Usage

1
<caniuse-embed feature="css-grid"></caniuse-embed>

With Custom Configuration

1
2
3
4
5
6
7
<caniuse-embed
 feature="flexbox"
 theme="dark"
 past="3"
 future="2"
 origin="https://caniuse.lruihao.cn"
></caniuse-embed>

Framework Integration

Here’s an example using Vue.js. For more framework integration examples, see FRAMEWORK_INTEGRATION.md.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
<script setup>
import '@cell-x/caniuse-embed-element'
</script>

<template>
 <div>
 <caniuse-embed
 feature="css-grid"
 theme="dark"
 :past="3"
 :future="2"
 />
 </div>
</template>

⚙️ API Reference

Attributes/Properties

Attribute Type Default Description
feature string '' Required. The caniuse feature identifier (e.g., ‘css-grid’, ‘flexbox’)
past 0 - 5 2 Number of past browser versions to display
future 0 - 3 1 Number of future browser versions to display
origin string 'https://caniuse.lruihao.cn' Base URL of the caniuse embed service
theme 'auto' | 'light' | 'dark' 'auto' Color theme for the embedded content
loading 'eager' | 'lazy' 'lazy' Loading strategy for the iframe (eager or lazy)
meta string auto-generated Unique identifier for the embed instance

Finding Feature Names

Feature names correspond to the identifiers used on caniuse.com. You can find them in:

  • The URL path: https://caniuse.com/css-grid → feature name is css-grid
  • The search results on caniuse.lruihao.cn
  • The caniuse-db repository

Common Feature Examples

  • css-grid - CSS Grid Layout
  • flexbox - Flexible Box Layout
  • arrow-functions - Arrow Functions
  • webp - WebP Image Format
  • css-variables - CSS Custom Properties
  • async-functions - Async/Await Functions

CSS Classes

  • .ciu-embed-iframe - The embedded iframe element
  • .ciu-embed-empty - Empty state when no feature is specified

🌐 Browser Support

This web component works in all modern browsers that support:

  • Custom Elements v1
  • Shadow DOM v1
  • ES2015+ features

🔧 Development

Prerequisites

  • Node.js 20+
  • pnpm 10+

Setup

1
2
3
4
5
6
7
8
9
# Clone the repository
git clone https://github.com/Lruihao/caniuse-embed-element.git
cd caniuse-embed-element

# Install dependencies
pnpm install

# Start development server
pnpm dev

Build

1
2
3
4
5
6
7
# Build all formats
pnpm build:all

# Build specific formats
pnpm build:lib # ES modules and types
pnpm build:iife # IIFE for CDN usage
pnpm build # Demo build

Scripts

  • pnpm dev - Start development server
  • pnpm build - Build demo
  • pnpm build:lib - Build library (ES modules + types)
  • pnpm build:iife - Build IIFE bundle for CDN
  • pnpm build:all - Build all formats
  • pnpm lint - Run ESLint
  • pnpm preview - Preview built demo

📦 Distribution

The package provides multiple build formats:

  • ES Modules (dist/) - For modern bundlers
  • IIFE Bundle (dist/caniuse-embed-element.iife.js) - For CDN usage
  • TypeScript Definitions (dist/types/) - For TypeScript projects

🤝 Contributing

Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add some amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

📄 License

This project is licensed under the MIT License. See the LICENSE file for details.

🙏 Acknowledgements


Made with ❤️ by Lruihao