hexojs / hexojs/hexo

‌支持引入 Hexo Component System

Open
#5,798 1 comment 0 reactions 0 assignees View on GitHub
Dominant language
TypeScript
Stars
41.8k
Forks
41
PR merge metrics
No merged PRs in 30d

Description

### Check List

- [x] I have already read [Docs page](https://hexo.io/docs/).
- [x] I have already searched existing issues.

### Feature Request

目前hexo作用的最细粒度是整个页面,而vue和astro等现代框架的最细粒度是组件,astro还引入了群岛架构的概念。这是Hexo显得比较落后不够现代的原因之一。

### Others

我咨询了 DeepSeek,它给出了一套路线图,不确定这是否有用。

路线图

引入“组件化”概念,本质上是要‌在静态生成阶段,将页面拆解为可独立开发、组合和复用的组件单元‌,同时保留 Hexo 的极速生成和 Markdown 中心化体验。这套方案可以称为 ‌Hexo Component System (HCS)‌。

以下是技术实现路径和关键设计:

1. 扩展核心概念:定义“组件”为一级资源

在 Hexo 的现有架构中,source/ 目录下只有 _posts、_drafts、_data 等预定义资源类型。我们需要新增一个 _components 目录,作为组件的物理载体。

```text
source/
_components/
my-card/
template.njk # 组件模板(支持 Nunjucks/EJS/Pug)
style.styl # 组件样式(Stylus/Sass/CSS)
script.js # 组件逻辑(可选的编译时辅助函数)
config.yml # 组件元数据(名称、分类、属性声明)
```

组件通过 config.yml 声明其接口(props),例如:

```yaml
# config.yml
name: my-card
props:
title: string
image: string
link: string
```

这样,组件就拥有了‌明确的输入约定‌,类似于 Vue 的 props。

2. 注册与解析机制:利用 Hexo 的插件系统

Hexo 已具备强大的扩展能力(hexo.extend),我们可以通过几个新增的扩展点来接管组件生命周期:

hexo.extend.component.register(name, handler)‌:注册组件处理器,负责编译模板、合并样式、封装逻辑。
hexo.extend.filter.register('after_render:component', callback)‌:允许插件在组件渲染后对内容进行后处理(如注入 CSS 变量、添加作用域标识)。
hexo.extend.generator.register('component_assets')‌:生成组件的静态资源(样式、脚本),并自动注入到页面中。

核心实现流程:

Hexo 启动时,扫描 source/_components/ 下的所有组件目录。
读取每个组件的 config.yml,将其注册为 hexo.component 实例。
编译组件模板(使用已有的模板引擎),生成一个‌渲染函数‌,该函数接收 props 并返回 HTML 片段。
收集组件的样式和脚本,合并后通过注入器(injector)嵌入到最终页面中。
3. 在模板中使用组件:引入自定义标签

为了让用户像使用 Vue 组件一样在 Markdown 或模板中调用组件,我们需要扩展 Hexo 的‌标签插件(Tag Plugin)‌ 系统。

现有标签插件语法为 {% tagName %},我们可以升级为 {% component %}:

```njk
{% component "my-card", title="Hello", image="/img/card.jpg", link="/post/hello" %}
```

这个标签插件在编译时:

找到对应的组件渲染函数。
传入 props,执行渲染,得到 HTML。
将 HTML 替换到页面中。

对于更复杂的场景,支持‌插槽(slot)‌ 机制,让组件内部可以嵌套内容:

```njk
{% component "layout-wrapper" %}
{% slot "main" %}
## 这是文章内容
{% endslot %}
{% endcomponent %}
```

这需要增强标签解析器,使其能识别嵌套标签并传递 slots 数据。

4. 作用域隔离与样式管理

传统 Hexo 主题的样式是全局的,这在组件化中容易引起冲突。我们可以借鉴 ‌CSS Modules‌ 或 ‌BEM‌ 的思想,但更适合静态站点的方案是‌自动添加组件前缀‌。

在编译组件模板时,为每个 HTML 标签增加一个 data-component="my-card" 属性,同时将组件样式中的选择器自动转换为:

```stylus
.my-card {
// 预设样式
}
// 编译后:
[data-component="my-card"] .my-card {
// 自动加前缀,避免污染
}
```

这可以通过一个 after_render:component 过滤器实现,对组件 CSS 进行 AST 转换。

5. 数据驱动与响应式支持(编译时)

Hexo 是静态生成器,无法像 Vue 那样在浏览器端响应数据变化,但我们可以实现‌编译时的响应式‌——即组件数据来源于 _data 目录、配置文件或前端 matter,构建时一次性计算。

组件可以声明自己的数据源:

```yml
# 组件 config.yml
data:
posts: site.posts # 引用 Hexo 的站点变量
```

Hexo 在生成时会将 site 变量注入到组件渲染上下文中,实现类似 Vue 的 computed 效果,但完全在构建阶段完成。

如果需要客户端交互,组件可附带一个 script.js,该脚本在浏览器端通过 hexo.component.init() 自动挂载,实现简单的交互逻辑(如折叠、轮播)。这相当于一个‌轻量级的渐进式增强‌。

6. 主题与插件集成

为了让生态顺利过渡,我们提供:

主题开发者‌:可以将 layout/ 中的部分结构重构为组件,提升可维护性。主题的 _components 目录会覆盖站点级组件,实现主题定制。
插件开发者‌:可以通过 hexo.extend.component.register 直接注册纯逻辑组件(无模板),例如生成友情链接、动态归档等。
用户‌:安装 hexo-component 官方插件,即可在现有博客中启用组件系统,无需改动主题。
7. 性能与兼容性保障
增量编译‌:组件有独立的缓存键(基于 props 和模板版本),Hexo 的 --watch 模式只会重新编译发生变化的组件,未改变的部分直接复用上次渲染结果。
向后兼容‌:不强制使用组件,传统 Markdown 页面和模板依然有效。组件系统作为可选增强,通过 hexo.config.components.enable: true 开启。
资源去重‌:多个页面使用同一组件时,其样式和脚本只会被注入一次,避免重复加载。

通过以上改造,Hexo 将从一个“页面级”的静态博客框架,进化为‌组件驱动的静态站点生成器‌,既保留 Markdown 的书写便利性,又获得现代前端框架的模块化开发体验。这正是 Hexo 在下一个大版本中需要迈出的关键一步。

Contributor guide

Open the contributing guide

Research direction

The proposal spans source/_components, hexo.extend component and filter hooks, the tag-plugin system, injectors, themes, and --watch mode, but names no existing implementation files or tests. Start by reading the existing plugin and tag-plugin entry points, then agree on one narrowly scoped milestone. Done should be defined by that milestone and its tests before implementation begins.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript, nodejs, typescript
Domain
tooling, web-dev
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Needs clarification
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.