@hyacine/vercount 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,196 @@
1
+ # @hyacine/vercount
2
+
3
+ 一个集成 Vercount 网站统计服务的 Hyacine 插件,是不蒜子 (Busuanzi) 的现代化替代方案。
4
+
5
+ ## 功能
6
+
7
+ - 🚀 **极速响应**:服务器响应时间在 100ms 以内
8
+ - 📊 **精准统计**:支持页面浏览量 (page_pv)、站点访问量 (site_pv) 和访客数 (site_uv)
9
+ - 🔒 **安全可靠**:采用 POST 请求,杜绝 CSRF 攻击风险
10
+ - 🌐 **全球 CDN**:Vercel 全球分发,99.99% 可用性
11
+ - 🔄 **无缝迁移**:支持不蒜子数据自动迁移
12
+ - ⚙️ **高度可定制**:可自定义显示内容、前缀后缀文本
13
+ - 💻 **Runtime-only**:客户端加载,无需服务器端渲染
14
+
15
+ ## 关于 Vercount
16
+
17
+ Vercount 是 [EvanNotFound](https://github.com/EvanNotFound) 开发的开源网站计数器服务,解决了不蒜子以下问题:
18
+
19
+ - ❌ 速度慢,容易出现 502 错误
20
+ - ❌ 使用过时的 Referrer 方法,移动端统计不准确
21
+ - ❌ JSONP 回调存在安全隐患
22
+
23
+ 更多信息请访问:[vercount.one](https://vercount.one/)
24
+
25
+ ## 安装
26
+
27
+ ```bash
28
+ bun add @hyacine/vercount
29
+ ```
30
+
31
+ ## 使用方法
32
+
33
+ ### 基础用法
34
+
35
+ 在 `hyacine.plugin.ts` 中配置:
36
+
37
+ ```typescript
38
+ import vercount from "@hyacine/vercount";
39
+
40
+ export default [vercount()];
41
+ ```
42
+
43
+ 这将使用默认配置,在 `post-footer` 注入点插入统计信息,显示格式为:
44
+
45
+ ```
46
+ 本文总阅读量 <数字> 次 | 本站总访问量 <数字> 次 | 本站总访客数 <数字> 人
47
+ ```
48
+
49
+ ### 自定义配置
50
+
51
+ ```typescript
52
+ import vercount from "@hyacine/vercount";
53
+
54
+ export default [
55
+ vercount({
56
+ // 只显示站点总访问量和访客数
57
+ showPagePV: false,
58
+ showSitePV: true,
59
+ showSiteUV: true,
60
+
61
+ // 自定义文本
62
+ sitePVPrefix: "访问量",
63
+ sitePVSuffix: "次",
64
+ siteUVPrefix: "访客数",
65
+ siteUVSuffix: "人",
66
+
67
+ // 使用自托管的 Vercount 实例
68
+ scriptUrl: "https://your-vercount-instance.com/js",
69
+ }),
70
+ ];
71
+ ```
72
+
73
+ ### 完整配置选项
74
+
75
+ ```typescript
76
+ export interface VercountOptions {
77
+ /**
78
+ * 自定义 Vercount 脚本 URL
79
+ * @default "https://events.vercount.one/js"
80
+ */
81
+ scriptUrl?: string;
82
+
83
+ /**
84
+ * 是否显示页面浏览量
85
+ * @default true
86
+ */
87
+ showPagePV?: boolean;
88
+
89
+ /**
90
+ * 是否显示站点总访问量
91
+ * @default true
92
+ */
93
+ showSitePV?: boolean;
94
+
95
+ /**
96
+ * 是否显示站点总访客数
97
+ * @default true
98
+ */
99
+ showSiteUV?: boolean;
100
+
101
+ /**
102
+ * 页面浏览量的前缀文本
103
+ * @default "本文总阅读量"
104
+ */
105
+ pagePVPrefix?: string;
106
+
107
+ /**
108
+ * 页面浏览量的后缀文本
109
+ * @default "次"
110
+ */
111
+ pagePVSuffix?: string;
112
+
113
+ /**
114
+ * 站点总访问量的前缀文本
115
+ * @default "本站总访问量"
116
+ */
117
+ sitePVPrefix?: string;
118
+
119
+ /**
120
+ * 站点总访问量的后缀文本
121
+ * @default "次"
122
+ */
123
+ sitePVSuffix?: string;
124
+
125
+ /**
126
+ * 站点总访客数的前缀文本
127
+ * @default "本站总访客数"
128
+ */
129
+ siteUVPrefix?: string;
130
+
131
+ /**
132
+ * 站点总访客数的后缀文本
133
+ * @default "人"
134
+ */
135
+ siteUVSuffix?: string;
136
+ }
137
+ ```
138
+
139
+ ## 注入点
140
+
141
+ 此插件默认将统计信息注入到 `post-footer` 注入点。如果你使用的主题或框架支持自定义注入点,请确保已定义 `post-footer` 注入点。
142
+
143
+ ## 统计方式
144
+
145
+ - **页面浏览量 (page_pv)**:每访问一次加一
146
+ - **站点访问量 (site_pv)**:所有页面的访问量总和
147
+ - **独立访客量 (site_uv)**:通过用户的 UserAgent 和 IP 地址判断
148
+
149
+ ## 从不蒜子迁移
150
+
151
+ Vercount 兼容不蒜子的数据格式,首次访问时会自动同步不蒜子的数据。你只需要:
152
+
153
+ 1. 使用此插件替换不蒜子
154
+ 2. 首次访问时数据会自动迁移
155
+ 3. 无需手动操作
156
+
157
+ ## 样式自定义
158
+
159
+ 插件生成的 HTML 结构:
160
+
161
+ ```html
162
+ <div class="vercount-stats">
163
+ <span>本文总阅读量 <span id="vercount_value_page_pv">Loading</span> 次</span> |
164
+ <span>本站总访问量 <span id="vercount_value_site_pv">Loading</span> 次</span> |
165
+ <span>本站总访客数 <span id="vercount_value_site_uv">Loading</span> 人</span>
166
+ </div>
167
+ ```
168
+
169
+ 你可以通过 CSS 自定义样式:
170
+
171
+ ```css
172
+ .vercount-stats {
173
+ text-align: center;
174
+ font-size: 0.9em;
175
+ color: #666;
176
+ padding: 1em 0;
177
+ }
178
+
179
+ .vercount-stats span {
180
+ margin: 0 0.5em;
181
+ }
182
+ ```
183
+
184
+ ## 数据管理
185
+
186
+ 如需编辑统计数据或验证域名,请访问 [vercount.one](https://vercount.one/) 进行操作。
187
+
188
+ ## 许可证
189
+
190
+ MIT
191
+
192
+ ## 相关链接
193
+
194
+ - [Vercount 官网](https://vercount.one/)
195
+ - [Vercount GitHub](https://github.com/EvanNotFound/vercount)
196
+ - [Hyacine Plugins](https://github.com/your-repo/hyacine-plugins)
package/package.json ADDED
@@ -0,0 +1,38 @@
1
+ {
2
+ "name": "@hyacine/vercount",
3
+ "version": "0.0.1",
4
+ "description": "A Hyacine plugin that integrates Vercount website statistics - a modern alternative to Busuanzi",
5
+ "keywords": [
6
+ "analytics",
7
+ "busuanzi",
8
+ "counter",
9
+ "hyacine",
10
+ "plugin",
11
+ "statistics",
12
+ "vercount"
13
+ ],
14
+ "files": [
15
+ "dist",
16
+ "src"
17
+ ],
18
+ "type": "module",
19
+ "exports": {
20
+ ".": {
21
+ "types": "./src/index.ts",
22
+ "default": "./src/index.ts"
23
+ }
24
+ },
25
+ "scripts": {
26
+ "build": "tsc",
27
+ "lint": "bunx --bun oxlint --type-aware --type-check . --fix",
28
+ "format": "bunx oxfmt ."
29
+ },
30
+ "dependencies": {
31
+ "@hyacine/core": "workspace:*",
32
+ "@hyacine/helper": "workspace:*"
33
+ },
34
+ "devDependencies": {
35
+ "@types/bun": "latest",
36
+ "typescript": "^5"
37
+ }
38
+ }
package/src/index.ts ADDED
@@ -0,0 +1,91 @@
1
+ import type { PluginManifest } from "@hyacine/core";
2
+
3
+ export interface VercountOptions {
4
+ /**
5
+ * 自定义 Vercount 脚本 URL
6
+ * @default "https://events.vercount.one/js"
7
+ */
8
+ scriptUrl?: string;
9
+
10
+ /**
11
+ * 是否显示页面浏览量
12
+ * @default true
13
+ */
14
+ showPagePV?: boolean;
15
+
16
+ /**
17
+ * 是否显示站点总访问量
18
+ * @default true
19
+ */
20
+ showSitePV?: boolean;
21
+
22
+ /**
23
+ * 是否显示站点总访客数
24
+ * @default true
25
+ */
26
+ showSiteUV?: boolean;
27
+
28
+ /**
29
+ * 页面浏览量的前缀文本
30
+ * @default "本文总阅读量"
31
+ */
32
+ pagePVPrefix?: string;
33
+
34
+ /**
35
+ * 页面浏览量的后缀文本
36
+ * @default "次"
37
+ */
38
+ pagePVSuffix?: string;
39
+
40
+ /**
41
+ * 站点总访问量的前缀文本
42
+ * @default "本站总访问量"
43
+ */
44
+ sitePVPrefix?: string;
45
+
46
+ /**
47
+ * 站点总访问量的后缀文本
48
+ * @default "次"
49
+ */
50
+ sitePVSuffix?: string;
51
+
52
+ /**
53
+ * 站点总访客数的前缀文本
54
+ * @default "本站总访客数"
55
+ */
56
+ siteUVPrefix?: string;
57
+
58
+ /**
59
+ * 站点总访客数的后缀文本
60
+ * @default "人"
61
+ */
62
+ siteUVSuffix?: string;
63
+ }
64
+
65
+ export default (options: VercountOptions = {}): PluginManifest => {
66
+ return {
67
+ name: "@hyacine/vercount",
68
+ version: "0.0.1",
69
+ minRenderCapability: "runtime-only",
70
+ entry: [
71
+ {
72
+ type: "runtime-only",
73
+ injectPoint: "post-footer",
74
+ path: new URL("./runtime.ts", import.meta.url).href,
75
+ name: "vercount-runtime",
76
+ options: {
77
+ scriptUrl: options.scriptUrl || "https://events.vercount.one/js",
78
+ showPagePV: options.showPagePV !== false,
79
+ showSitePV: options.showSitePV !== false,
80
+ showSiteUV: options.showSiteUV !== false,
81
+ pagePVPrefix: options.pagePVPrefix || "本文总阅读量",
82
+ pagePVSuffix: options.pagePVSuffix || "次",
83
+ sitePVPrefix: options.sitePVPrefix || "本站总访问量",
84
+ sitePVSuffix: options.sitePVSuffix || "次",
85
+ siteUVPrefix: options.siteUVPrefix || "本站总访客数",
86
+ siteUVSuffix: options.siteUVSuffix || "人",
87
+ },
88
+ },
89
+ ],
90
+ };
91
+ };
package/src/runtime.ts ADDED
@@ -0,0 +1,95 @@
1
+ import type { PluginInitFunction } from "@hyacine/helper/runtime";
2
+ import { getInjectPointSelector } from "@hyacine/helper/runtime";
3
+
4
+ interface VercountRuntimeOptions {
5
+ scriptUrl: string;
6
+ showPagePV: boolean;
7
+ showSitePV: boolean;
8
+ showSiteUV: boolean;
9
+ pagePVPrefix: string;
10
+ pagePVSuffix: string;
11
+ sitePVPrefix: string;
12
+ sitePVSuffix: string;
13
+ siteUVPrefix: string;
14
+ siteUVSuffix: string;
15
+ }
16
+
17
+ /**
18
+ * 加载 Vercount 脚本
19
+ * @param scriptUrl Vercount 脚本 URL
20
+ * @returns Promise<void>
21
+ */
22
+ function loadVercountScript(scriptUrl: string): Promise<void> {
23
+ return new Promise((resolve, reject) => {
24
+ // 检查脚本是否已加载
25
+ const existingScript = document.querySelector(`script[src="${scriptUrl}"]`);
26
+ if (existingScript) {
27
+ resolve();
28
+ return;
29
+ }
30
+
31
+ const script = document.createElement("script");
32
+ script.src = scriptUrl;
33
+ script.defer = true;
34
+
35
+ script.onload = () => resolve();
36
+ script.onerror = () => reject(new Error("Failed to load Vercount script"));
37
+
38
+ document.head.appendChild(script);
39
+ });
40
+ }
41
+
42
+ /**
43
+ * 创建统计元素的 HTML
44
+ * @param options VercountRuntimeOptions
45
+ * @returns HTML 字符串
46
+ */
47
+ function createStatsHTML(options: VercountRuntimeOptions): string {
48
+ const parts: string[] = [];
49
+
50
+ if (options.showPagePV) {
51
+ parts.push(
52
+ `<span>${options.pagePVPrefix} <span id="vercount_value_page_pv">Loading</span> ${options.pagePVSuffix}</span>`,
53
+ );
54
+ }
55
+
56
+ if (options.showSitePV) {
57
+ parts.push(
58
+ `<span>${options.sitePVPrefix} <span id="vercount_value_site_pv">Loading</span> ${options.sitePVSuffix}</span>`,
59
+ );
60
+ }
61
+
62
+ if (options.showSiteUV) {
63
+ parts.push(
64
+ `<span>${options.siteUVPrefix} <span id="vercount_value_site_uv">Loading</span> ${options.siteUVSuffix}</span>`,
65
+ );
66
+ }
67
+
68
+ return parts.join(" | ");
69
+ }
70
+
71
+ export const init: PluginInitFunction<VercountRuntimeOptions> = async (options) => {
72
+ try {
73
+ // 加载 Vercount 脚本
74
+ await loadVercountScript(options.scriptUrl);
75
+
76
+ // 获取注入点元素
77
+ const selector = getInjectPointSelector("post-footer");
78
+ const targetElement = document.querySelector(selector);
79
+
80
+ if (!targetElement) {
81
+ console.warn(`[vercount] Inject point not found: ${selector}`);
82
+ return;
83
+ }
84
+
85
+ // 创建容器元素
86
+ const container = document.createElement("div");
87
+ container.className = "vercount-stats";
88
+ container.innerHTML = createStatsHTML(options);
89
+
90
+ // 插入到注入点
91
+ targetElement.appendChild(container);
92
+ } catch (error) {
93
+ console.error("[vercount] Failed to initialize:", error);
94
+ }
95
+ };