Skip to content

0.9.0-alpha1

Choose a tag to compare

@SisyphusZheng SisyphusZheng released this 08 May 19:33
· 578 commits to main since this release

LessJS 0.9.0-alpha1

@lessjs/content — 全新内容插件

Breaking Change: @lessjs/blog 已被 @lessjs/content 替代,不再提供向后兼容。

@lessjs/content 是一个统一的构建时内容插件,集成三个独立模块,按需启用:

模块 功能 状态
Blog Markdown 解析 + 前端元数据 + 动态路由生成 @lessjs/blog 迁移
Nav 自动扫描路由文件的 meta 导出,生成侧边栏导航数据 🆕
Sitemap 从 SSG 产物自动生成 sitemap.xml + robots.txt 🆕
import { lessContent } from '@lessjs/content';

export default defineConfig({
  plugins: [
    less(),
    lessContent({
      blog: { contentDir: 'content/blog', basePath: '/blog' },
      nav: { routesDir: 'app/routes', headerNav: [...] },
      sitemap: { hostname: 'https://lessjs.org' },
    }),
  ],
});

Blog 模块

@lessjs/blog 相同的 Markdown 解析能力(gray-matter + marked),但通过统一的 lessContent() 插件配置。支持自定义 Markdown 渲染器。

Nav 模块 🆕

自动从路由文件的 meta 导出提取导航数据,生成 virtual:less-nav 虚拟模块供 <less-layout> 侧边栏使用。无需手动维护 nav-data.ts

// app/routes/guide/getting-started.ts
export const meta = { section: 'Guide', label: 'Getting Started', order: 10 };

Sitemap 模块 🆕

SSG 构建完成后自动扫描 dist/ 目录,生成 sitemap.xmlrobots.txt。支持排除路径、自定义 changefreq/priority。

SSR 属性绑定保留

Breaking Change: @lessjs/adapter-litinterpolate() 函数现在将 Lit 属性绑定(.prop="${val}")序列化为 kebab-case HTML 属性,而不是直接丢弃。

之前 (v0.8.0) 之后 (v0.9.0)
.navItems="${data}" → 被丢弃 .navItems="${data}"nav-items="[{...}]"
嵌套组件收不到数据 嵌套组件在 SSR 阶段获得完整数据

renderNestedCustomElements() 中的 parseAttrsToProps() 也已更新:自动检测 JSON 格式的属性值并解析回 JS 对象/数组。

新增 camelToKebab() 辅助函数(adapter-lit/ssr.ts),将 navItemsnav-items 等属性名转换。

islandEffect() 泄漏修复

@lessjs/signalislandEffect() 修复了三个资源泄漏问题:

  • MutationObserver 未断开:组件移除后 MO 仍监听
  • setInterval 未清除:轮询回调持续执行
  • 重复清理:多个清理路径可能重复调用 dispose()

新实现使用统一的 teardown() 函数,保证 MO + interval + effect 三者只被清理一次。

SSG 管道增强

  • virtual:less-nav 修复:Phase 3 SSG server 现在包含 less:ssg-virtual-nav 插件,确保路由文件中 import 'virtual:less-nav' 正确解析
  • @lessjs/content 初始化:Phase 3 自动检测并初始化 content 插件的 blog 数据存储
  • Sitemap 生成:SSG 构建完成后自动调用 @lessjs/content/sitemap 生成 sitemap.xml

文档与仓库清理

  • 删除 demo/ 目录(v0.4.0 遗留代码,无 CI、无引用)
  • 删除 /docs/routes/demo//docs/routes/examples/(mock 展示页)
  • 合并 /ui + /styling/less-ui → 单一 /ui 页面
  • @lessjs/blog@lessjs/content 全局替换
  • 删除 deliverables/(审计报告 + PRD,不属于源码仓库)
  • 删除 docs/package.jsondocs/CNAME(遗留配置)
  • 迁移 e2e/docs/e2e/(Playwright 测试定位到 docs 站点)
  • 删除 playwright-report/test-results/(构建产物,已加入 .gitignore

包版本

旧版本 新版本
@lessjs/core 0.8.1 0.9.0
@lessjs/adapter-lit 0.6.4 0.7.0
@lessjs/content 0.1.0 (原 @lessjs/blog) 0.2.0
@lessjs/rpc 0.6.1
@lessjs/signal 0.6.1 0.6.2
@lessjs/ui 0.6.2
@lessjs/create 0.6.1

已知问题

  • serializeAttributes()@lessjs/core/render-dsd.ts 中缺少 camelToKebab 转换,currentPath 被输出为 currentpath 而非 current-path#1
  • route-scanner.tsawait import(pkg) 变量动态导入触发 JSR unanalyzable-dynamic-import 警告(不影响功能,仅影响发布提示)

升级指南

  1. 替换 @lessjs/blog → @lessjs/content

    - import { lessBlog } from '@lessjs/blog';
    + import { lessContent } from '@lessjs/content';
    - lessBlog({ contentDir: 'posts' })
    + lessContent({ blog: { contentDir: 'posts' } })
  2. 侧边栏导航迁移:删除手动维护的 nav-data.ts,在路由文件中添加 meta 导出,配置 lessContent({ nav: { routesDir: 'app/routes', headerNav: [...] } })

  3. Sitemap 启用:添加 lessContent({ sitemap: { hostname: 'https://yoursite.com' } })

  4. SSR 属性绑定:如果之前有依赖属性绑定被丢弃的行为(不太可能),现在这些绑定会以 kebab-case 属性形式保留在 HTML 中


LessJS v0.9.0-alpha1

@lessjs/content — New Unified Content Plugin

Breaking Change: @lessjs/blog has been replaced by @lessjs/content with no backward compatibility.

@lessjs/content is a unified build-time content plugin that integrates three independent modules, each opt-in:

Module Purpose Status
Blog Markdown parsing + frontmatter + dynamic route generation Migrated from @lessjs/blog
Nav Auto-scans route files for meta exports, generates sidebar navigation data 🆕
Sitemap Auto-generates sitemap.xml + robots.txt from SSG output 🆕
import { lessContent } from '@lessjs/content';

export default defineConfig({
  plugins: [
    less(),
    lessContent({
      blog: { contentDir: 'content/blog', basePath: '/blog' },
      nav: { routesDir: 'app/routes', headerNav: [...] },
      sitemap: { hostname: 'https://lessjs.org' },
    }),
  ],
});

Blog Module

Same Markdown parsing capabilities as @lessjs/blog (gray-matter + marked), but configured through the unified lessContent() plugin. Supports custom Markdown renderer via the markdown option.

Nav Module 🆕

Automatically extracts navigation data from route file meta exports, generating a virtual:less-nav virtual module consumed by <less-layout> sidebar. No more manually maintained nav-data.ts.

// app/routes/guide/getting-started.ts
export const meta = { section: 'Guide', label: 'Getting Started', order: 10 };

Sitemap Module 🆕

Automatically scans dist/ after SSG build completes, generating sitemap.xml and robots.txt. Supports path exclusion, custom changefreq/priority.

SSR Property Binding Preservation

Breaking Change: @lessjs/adapter-lit's interpolate() now serializes Lit property bindings (.prop="${val}") as kebab-case HTML attributes instead of stripping them entirely.

Before (v0.8.0) After (v0.9.0)
.navItems="${data}" → stripped .navItems="${data}"nav-items="[{...}]"
Nested components receive no data Nested components get full data during SSR

parseAttrsToProps() in renderNestedCustomElements() also updated: auto-detects JSON attribute values and parses them back to JS objects/arrays.

Added camelToKebab() helper in adapter-lit/ssr.ts for navItemsnav-items style conversions.

islandEffect() Leak Fix

@lessjs/signal's islandEffect() fixed three resource leaks:

  • MutationObserver not disconnected: MO continued observing after element removal
  • setInterval not cleared: Polling callback kept running indefinitely
  • Duplicate cleanup: Multiple cleanup paths could call dispose() more than once

New implementation uses a unified teardown() function guaranteeing MO + interval + effect are cleaned exactly once.

SSG Pipeline Enhancements

  • virtual:less-nav fix: Phase 3 SSG server now includes less:ssg-virtual-nav plugin, ensuring import 'virtual:less-nav' in route files resolves correctly
  • @lessjs/content initialization: Phase 3 auto-detects and initializes content plugin's blog data store
  • Sitemap generation: After SSG build completes, automatically invokes @lessjs/content/sitemap to generate sitemap.xml

Docs & Repository Cleanup

  • Removed demo/ directory (v0.4.0 legacy, no CI, no references)
  • Removed /docs/routes/demo/ and /docs/routes/examples/ (mock showcase pages)
  • Merged /ui + /styling/less-ui → single /ui page
  • @lessjs/blog@lessjs/content global replacement
  • Removed deliverables/ (audit reports + PRDs, not source code)
  • Removed docs/package.json, docs/CNAME (legacy configs)
  • Relocated e2e/docs/e2e/ (Playwright tests target docs site)
  • Removed playwright-report/, test-results/ (build artifacts, added to .gitignore)

Package Versions

Package Old New
@lessjs/core 0.8.1 0.9.0
@lessjs/adapter-lit 0.6.4 0.7.0
@lessjs/content 0.1.0 (was @lessjs/blog) 0.2.0
@lessjs/rpc 0.6.1
@lessjs/signal 0.6.1 0.6.2
@lessjs/ui 0.6.2
@lessjs/create 0.6.1

Known Issues

  • serializeAttributes() in @lessjs/core/render-dsd.ts lacks camelToKebab conversion — currentPath is output as currentpath instead of current-path (#1)
  • await import(pkg) variable dynamic import in route-scanner.ts triggers JSR unanalyzable-dynamic-import warning (does not affect functionality, publish advisory only)

Upgrade Guide

  1. Replace @lessjs/blog → @lessjs/content:

    - import { lessBlog } from '@lessjs/blog';
    + import { lessContent } from '@lessjs/content';
    - lessBlog({ contentDir: 'posts' })
    + lessContent({ blog: { contentDir: 'posts' } })
  2. Sidebar navigation migration: Delete manually maintained nav-data.ts, add meta exports to route files, configure lessContent({ nav: { routesDir: 'app/routes', headerNav: [...] } })

  3. Enable sitemap: Add lessContent({ sitemap: { hostname: 'https://yoursite.com' } })

  4. SSR property bindings: If you previously relied on property bindings being stripped (unlikely), they are now preserved as kebab-case HTML attributes

Full Changelog: v0.8.1...0.9.0-alpha1