diff --git a/docs/content/release/2026.0.0.md b/docs/content/release/2026.0.0.md new file mode 100644 index 0000000..8b8619b --- /dev/null +++ b/docs/content/release/2026.0.0.md @@ -0,0 +1,25 @@ +--- +title: 2026.0.0 +--- + +我们很高兴地宣布 PageForge 2026.0.0 正式发布。PageForge 是一款现代化的静态页面生成与部署平台,致力于为用户提供从创建到部署的一站式解决方案。此版本主要增强了阅读体验相关功能。 + +## 新增功能 + +- 支持默认 h 标签渲染 +- 优化构建速度 +- 修复由于未获取 nav + banner 高度导致页面抖动 +- 优化修改文件重新编译效率 + +## 链接 + +- GitHub: https://github.com/devlive-community/pageforge +- 官网: https://pageforge.devlive.org + +## 反馈与支持 + +如果您在使用过程中遇到任何问题,请通过 GitHub Issues 向我们反馈。您的建议对我们至关重要! + +--- + +此版本重点优化了构建效率,建议所有用户升级到此版本。 \ No newline at end of file diff --git a/docs/pageforge.yaml b/docs/pageforge.yaml index 02695a3..2e85264 100644 --- a/docs/pageforge.yaml +++ b/docs/pageforge.yaml @@ -208,6 +208,7 @@ nav: - Technology: - /technology/extension - ReleaseNotes: + - /release/2026.0.0 - /release/2025.1.7 - /release/2025.1.6 - /release/2025.1.5 diff --git a/lib/commands/build.js b/lib/commands/build.js index be2d1cb..e458f7a 100644 --- a/lib/commands/build.js +++ b/lib/commands/build.js @@ -9,6 +9,8 @@ class BuildCommand { } async execute(options = {}) { + const startTime = Date.now(); + try { let config = this.configManager.getConfig(); @@ -40,7 +42,8 @@ class BuildCommand { const generator = new SiteGenerator(config); await generator.generate(); - console.log('🎉 项目编译完成'); + const duration = ((Date.now() - startTime) / 1000).toFixed(2); + console.log(`🎉 项目编译完成,耗时: ${duration}s`); } catch (error) { throw new Error(`Build failed: ${error.message}`); diff --git a/lib/dev-server.js b/lib/dev-server.js index 5e9d516..7ac426f 100644 --- a/lib/dev-server.js +++ b/lib/dev-server.js @@ -13,8 +13,10 @@ class DevServer { async start() { // 首先构建一次 + const startTime = Date.now(); await this.generator.generate(); - console.log('🎉 项目编译完成'); + const duration = ((Date.now() - startTime) / 1000).toFixed(2); + console.log(`🎉 项目编译完成,耗时: ${duration}s`); const home = this.config?.version ? this.config.outputPath.replace(this.config.version, '') : this.config.outputPath; // 设置静态文件服务 @@ -65,19 +67,81 @@ class DevServer { async handleFileChange(filepath) { try { - if (filepath.endsWith('pageforge.yaml')) { - console.log('📝 配置文件已更新,重新加载配置并重新编译...'); - await this.generator.reloadConfig(); + const startTime = Date.now(); + + // 配置文件或模板文件变化 - 全量编译 + if (filepath.endsWith('pageforge.yaml') || + filepath.includes('/templates/') || + filepath.includes('\\templates\\')) { + console.log('📝 配置/模板文件已更新,全量重新编译...'); + if (filepath.endsWith('pageforge.yaml')) { + await this.generator.reloadConfig(); + } + await this.generator.generate(); + } + // Markdown 文件变化 - 增量编译 + else if (filepath.endsWith('.md')) { + console.log(`📄 Markdown 文件已更新: ${filepath}`); + await this.compileSingleMarkdown(filepath); + } + // 资源文件变化 - 复制资源 + else if (this.config.assetsPath && filepath.startsWith(this.config.assetsPath)) { + console.log(`📦 资源文件已更新: ${filepath}`); + await this.generator.copyAssets(); } + // 其他文件 - 全量编译 else { - console.log(`📄 文件 ${filepath} 已更新,正在重新编译...`); + console.log(`📄 文件已更新: ${filepath},全量重新编译...`); + await this.generator.generate(); } - await this.generator.generate(); - console.log('✓ 项目重新编译完成'); + const duration = ((Date.now() - startTime) / 1000).toFixed(2); + console.log(`✓ 编译完成,耗时: ${duration}s`); } catch (error) { - console.error('🤯 项目文件重新编译失败 ', error); + console.error('🤯 编译失败:', error); + } + } + + async compileSingleMarkdown(filepath) { + const fs = require('fs'); + + // 检查文件是否在源目录中 + if (!filepath.startsWith(this.config.sourcePath)) { + console.log('文件不在源目录中,跳过编译'); + return; + } + + // 计算相对路径 + const relativePath = path.relative(this.config.sourcePath, filepath); + const sourceDir = path.dirname(filepath); + const filename = path.basename(filepath); + + // 判断是否启用国际化 + if (this.config.feature?.i18n?.enable) { + // 多语言模式 - 为每个语言编译 + const locales = Object.keys(this.config.i18n || {}).filter(key => key !== 'default'); + for (const locale of locales) { + const relativeDir = path.relative(this.config.sourcePath, sourceDir); + const baseDir = path.join(locale, relativeDir); + await this.generator.directoryProcessor.fileProcessor.processMarkdownFile( + sourceDir, + baseDir, + filename, + locale, + this.config.sourcePath + ); + } + } else { + // 单语言模式 + const relativeDir = path.relative(this.config.sourcePath, sourceDir); + await this.generator.directoryProcessor.fileProcessor.processMarkdownFile( + sourceDir, + relativeDir, + filename, + '', + this.config.sourcePath + ); } } } diff --git a/lib/directory-processor.js b/lib/directory-processor.js index cfe8ead..95803f1 100644 --- a/lib/directory-processor.js +++ b/lib/directory-processor.js @@ -183,7 +183,8 @@ class DirectoryProcessor { // 创建根目录重定向 this.createRootRedirect(); - for (const locale of this.getAvailableLocales()) { + // 并发处理多语言 + await Promise.all(this.getAvailableLocales().map(async (locale) => { console.log(`\n📂 处理语言: ${locale.key}`); // 创建语言目录 @@ -196,7 +197,7 @@ class DirectoryProcessor { const relativeToSource = path.relative(this.config.sourcePath, sourceDir); const initialBaseDir = path.join(locale.key, relativeToSource); await this.processDirectory(sourceDir, initialBaseDir, locale.key, this.config.sourcePath); - } + })); } else { await this.processDirectory(sourceDir, '', '', this.config.sourcePath); @@ -223,8 +224,8 @@ class DirectoryProcessor { console.log(`\n📂 处理目录: ${sourceDir}`); - // 处理子目录 - for (const file of files) { + // 并发处理子目录 + await Promise.all(files.map(async (file) => { const sourcePath = path.join(sourceDir, file); const stat = fs.statSync(sourcePath); @@ -233,11 +234,11 @@ class DirectoryProcessor { const nextBaseDir = locale ? path.join(locale, relativeToSource) : relativeToSource; await this.processDirectory(sourcePath, nextBaseDir, locale, rootSourceDir); } - } + })); - // 处理 Markdown 文件 + // 并发处理 Markdown 文件 const markdownFiles = files.filter(file => file.endsWith('.md')); - for (const file of markdownFiles) { + await Promise.all(markdownFiles.map(async (file) => { const relativeSourceDir = path.relative(rootSourceDir, sourceDir); const relativeBaseDir = locale ? path.join(locale, relativeSourceDir) : relativeSourceDir; @@ -248,7 +249,7 @@ class DirectoryProcessor { locale, rootSourceDir ); - } + })); // 处理其他文件 const otherFiles = files.filter(file => diff --git a/package.json b/package.json index 2acb8cb..3bcba26 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "pageforge", - "version": "2025.1.7", + "version": "2026.0.0", "description": "PageForge 是一款现代化的静态页面生成与部署平台,旨在帮助用户快速创建精美的静态网站,并一键部署到 GitHub Pages。 无论是个人博客、项目文档还是企业官网,PageForge 都能让你轻松实现高效构建、智能部署和即时上线。", "homepage": "https://pageforge.devlive.org", "repository": { diff --git a/templates/components/header.js b/templates/components/header.js index 6265d59..8932267 100644 --- a/templates/components/header.js +++ b/templates/components/header.js @@ -1,28 +1,9 @@ module.exports = function template(item) { - const divClass = () => { - const baseClasses = 'font-bold tracking-tight text-gray-900 dark:text-white my-3 [&_span]:!font-inherit [&_span]:!text-inherit [&_code]:!text-inherit'; - - switch (item.level) { - case 1: - return `text-3xl sm:text-4xl ${baseClasses} [&_span]:!text-3xl [&_span]:sm:!text-4xl`; - case 2: - return `text-2xl sm:text-3xl ${baseClasses} [&_span]:!text-2xl [&_span]:sm:!text-3xl`; - case 3: - return `text-xl sm:text-2xl ${baseClasses} [&_span]:!text-xl [&_span]:sm:!text-2xl`; - case 4: - return `text-lg sm:text-xl ${baseClasses} [&_span]:!text-lg [&_span]:sm:!text-xl`; - case 5: - return `text-md sm:text-lg ${baseClasses} [&_span]:!text-md [&_span]:sm:!text-lg`; - case 6: - return `text-sm sm:text-md ${baseClasses} [&_span]:!text-sm [&_span]:sm:!text-md`; - default: - return `text-base sm:text-lg ${baseClasses} [&_span]:!text-base [&_span]:sm:!text-lg`; - } - } + const tag = `h${item.level}`; return ` -
-
${item.text}
-
+ <${tag} id="${item.slug}"> + ${item.text} + `; }; \ No newline at end of file diff --git a/templates/components/span.js b/templates/components/span.js index 50b6805..6506183 100644 --- a/templates/components/span.js +++ b/templates/components/span.js @@ -1,5 +1,5 @@ module.exports = function template(item) { return ` - ${item.text} + ${item.text} `; }; \ No newline at end of file diff --git a/templates/includes/header-banner.ejs b/templates/includes/header-banner.ejs index 3808f98..ebd40be 100644 --- a/templates/includes/header-banner.ejs +++ b/templates/includes/header-banner.ejs @@ -1,6 +1,6 @@ <% if (locals.siteData?.banner?.content) { %> -
-
+
+
<% if (Array.isArray(locals.siteData.banner.content)) { %>