Skip to content

Commit

Permalink
修复存在子目录编译导致目录错误
Browse files Browse the repository at this point in the history
  • Loading branch information
qianmoQ committed Jan 1, 2025
1 parent 024190b commit d465015
Show file tree
Hide file tree
Showing 5 changed files with 123 additions and 51 deletions.
76 changes: 76 additions & 0 deletions docs/content/getting-started/create-site/index.en.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
---
title: 创建网站
icon: folder-plus
---

安装 PageForge 后,你可以使用它来创建你的网站。您需要跳转到需要创建网站的文件夹,该文件夹必须是一个空文件夹。然后,您可以使用 PageForge 的命令行工具来创建网站。

我们假设您的文件夹是 `my-website`

```bash
pageforge init
```

或者

```bash
pageforge create-site .
```

或者指定文件夹路径

```bash
pageforge create-site my-website
```

安装完成后,它将是如下目录结构:

```
├── content
│   └── index.md
└── pageforge.yaml
```

## 配置文件

---

默认会在当前目录下创建名为 `pageforge.yaml` 的配置文件,该文件包含了默认配置。

```yaml
site:
title: PageForge
description: PageForge 是一款现代化的静态页面生成与部署平台,旨在帮助用户快速创建精美的静态网站,并一键部署到 GitHub Pages。 无论是个人博客、项目文档还是企业官网,PageForge 都能让你轻松实现高效构建、智能部署和即时上线。

nav:
- link: /
text: 首页
```
如果您想要更改默认配置,可以在 `pageforge.yaml` 文件中进行修改。

## 预览您的修改

---

PageForge 包括一个实时预览服务器,因此您可以在编写文档时预览您的更改。服务器将在保存时自动重建站点。从以下内容开始:

```bash
pageforge serve
```

将浏览器指向 [localhost:3000](http://localhost:3000 "localhost:3000" "_blank"),您应该会看到:

![img.png](img.png)

## 编译你的项目

---

完成编辑后,您可以使用以下方法从 Markdown 文件构建静态网站:

```bash
pageforge build
```

此目录的内容构成了您的项目文档。无需操作数据库或服务器,因为它是完全独立的。该站点可以托管在 GitHub Pages、GitLab Pages、您选择的 CDN 或您的私有 Web 空间上。
75 changes: 46 additions & 29 deletions lib/directory-processor.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,111 +12,128 @@ class DirectoryProcessor {
this.fileProcessor = new FileProcessor(this.config, this.pages, config.sourcePath, config.outputPath);
}

// 预加载所有页面数据
async preloadPages(sourceDir, baseDir = '') {
const files = fs.readdirSync(sourceDir);

for (const file of files) {
const sourcePath = path.join(sourceDir, file);
// 计算相对于源目录的路径
const relativePath = path.join(baseDir, file);
const stat = fs.statSync(sourcePath);

if (stat.isDirectory()) {
// 递归处理子目录
await this.preloadPages(sourcePath, relativePath);
}
else if (file.endsWith('.md')) {
// 处理 Markdown 文件
const {metadata} = this.fileProcessor.processMarkdown(sourcePath);
const pageUrlPath = getPagePath(relativePath);
this.pages.set(pageUrlPath, metadata);
}
}
}

// 判断特定功能是否启用
isFeatureEnabled(featureName) {
return this.config.feature?.[featureName]?.enable === true;
}

// 获取所有配置的语言信息
getAvailableLocales() {
// 如果国际化功能未启用,返回空数组
if (!this.isFeatureEnabled('i18n')) {
return [];
}

const i18n = this.config.i18n || {};
// 过滤掉 default 属性,只返回语言配置
return Object.entries(i18n)
.filter(([key]) => key !== 'default')
.map(([key, value]) => ({
key, // 语言代码 如 'en', 'zh-CN'
name: value.name, // 语言名称
flag: value.flag // 语言图标
key,
name: value.name,
flag: value.flag
}));
}

async processLanguageDirectory(sourceDir, baseDir = '') {
// 预加载所有页面数据
await this.preloadPages(this.config.sourcePath);

// 根据国际化处理目录
if (this.isFeatureEnabled('i18n')) {
console.log("\n📂 正在处理国际化");
for (const locale of this.getAvailableLocales()) {
const outputDir = path.join(this.config.outputPath, locale.key);
if (!fs.existsSync(outputDir)) {
fs.mkdirSync(outputDir, {recursive: true});
console.log(`\n📂 处理语言: ${locale.key}`);

// 创建语言目录
const localeOutputDir = path.join(this.config.outputPath, locale.key);
if (!fs.existsSync(localeOutputDir)) {
fs.mkdirSync(localeOutputDir, {recursive: true});
}

await this.processDirectory(sourceDir, baseDir, locale.key);
// 从源目录开始处理,保持相对路径结构
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(this.config.sourcePath);
await this.processDirectory(sourceDir, '', '', this.config.sourcePath);
}
}

async processDirectory(sourceDir, baseDir = '', locale = '', originalBaseDir = baseDir) {
async processDirectory(sourceDir, baseDir = '', locale = '', rootSourceDir) {
const files = fs.readdirSync(sourceDir);

if (files.length === 0) {
console.log(`📂 目录 ${sourceDir} 为空,忽略不做任何处理`);
return;
}

console.log(`\n📂 处理目录: ${sourceDir}`);

// 如果有国际化配置,则根据国际化配置构建相关目录
// 处理子目录
for (const file of files) {
const sourcePath = path.join(sourceDir, file);
if (fs.statSync(sourcePath).isDirectory()) {
await this.processDirectory(sourcePath, path.join(baseDir, locale, file), locale, path.join(baseDir, file));
const stat = fs.statSync(sourcePath);

if (stat.isDirectory()) {
// 计算相对于源根目录的路径
const relativeToSource = path.relative(rootSourceDir, sourcePath);
// 构建下一级目录的基础路径
const nextBaseDir = locale ? path.join(locale, relativeToSource) : relativeToSource;

await this.processDirectory(sourcePath, nextBaseDir, locale, rootSourceDir);
}
}

// 处理 Markdown 文件
const markdownFiles = files.filter(file => file.endsWith('.md'));
for (const file of markdownFiles) {
await this.fileProcessor.processMarkdownFile(sourceDir, baseDir, file, locale, sourceDir);
const relativeSourceDir = path.relative(rootSourceDir, sourceDir);
const relativeBaseDir = locale ? path.join(locale, relativeSourceDir) : relativeSourceDir;

await this.fileProcessor.processMarkdownFile(
sourceDir,
relativeBaseDir,
file,
locale,
rootSourceDir
);
}

// 最后复制其他文件
// 处理其他文件
const otherFiles = files.filter(file =>
!file.endsWith('.md') &&
!fs.statSync(path.join(sourceDir, file)).isDirectory()
);

for (const file of otherFiles) {
const sourcePath = path.join(sourceDir, file);
let outputPath = path.join(this.config.outputPath, baseDir, file);

// 如果是国际化要额外处理
if (isFeatureEnabled(this.config, 'i18n')) {
outputPath = path.join(this.config.outputPath, originalBaseDir, file)
}
const relativeSourceDir = path.relative(rootSourceDir, sourceDir);
const outputPath = path.join(
this.config.outputPath,
locale ? path.join(locale, relativeSourceDir) : relativeSourceDir,
file
);

// 确保输出目录存在
let outputDir = path.dirname(outputPath);
const outputDir = path.dirname(outputPath);
if (!fs.existsSync(outputDir)) {
fs.mkdirSync(outputDir, {recursive: true});
}
Expand Down
3 changes: 0 additions & 3 deletions lib/file-processor.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ class FileProcessor {
return;
}

console.log("📄 正在处理文件", sourcePath, " 到 ", relativePath);
try {
// 处理 Markdown 文件
const {metadata, content} = this.processMarkdown(sourcePath);
Expand Down Expand Up @@ -95,8 +94,6 @@ class FileProcessor {
const html = await this.templateEngine.renderWithLayout('layouts/page', pageData);

const outputFile = path.join(outputDir, outputFilename);
console.log("源文件", sourcePath, " 输出文件", outputFile, " Origina 文件", originalFilePath);

fs.writeFileSync(outputFile, html);

console.log(`✓ 编译 ${relativePath} 文件完成`);
Expand Down
18 changes: 0 additions & 18 deletions lib/site-generator.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
const fs = require('fs');
const path = require('path');
const yaml = require('js-yaml');
const FileProcessor = require('./file-processor');
const DirectoryProcessor = require('./directory-processor');
const TemplateEngine = require('./template-engine');
const AssetBundler = require('./asset-bundler');

class SiteGenerator {
Expand All @@ -14,7 +12,6 @@ class SiteGenerator {

initializeWithConfig(config) {
this.config = config;
this.fileProcessor = new FileProcessor(config.sourcePath, config.outputPath);
this.directoryProcessor = new DirectoryProcessor(this.config, config.sourcePath, config.outputPath);

this.config.templatePath = path.join(path.join(__dirname, '../templates'));
Expand Down Expand Up @@ -64,21 +61,6 @@ class SiteGenerator {
: path.resolve(process.cwd(), relativePath);
}

// 获取页面路径(用于侧边栏激活状态判断)
getPagePath(relativePath) {
// 移除 .md 或 .html 扩展名
const pathWithoutExt = relativePath.replace(/\.(md|html)$/, '');

// 如果是 index 文件,特殊处理
const normalizedPath = pathWithoutExt === 'index' ? '' : pathWithoutExt;

// 转换为 URL 风格的路径(使用正斜杠)
const urlPath = normalizedPath.split(path.sep).join('/');

// 确保路径以 / 开头
return urlPath.startsWith('/') ? urlPath : `/${urlPath}`;
}

// 复制资源目录,保持原始目录结构
async copyAssets() {
// 先执行资源打包
Expand Down
2 changes: 1 addition & 1 deletion templates/includes/header.ejs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ function isPathInNavItem(currentPath, navItem) {
<div class="flex items-center justify-between flex-1 lg:flex-none">
<div class="flex items-center space-x-4 shrink-0">
<% if (site.logo) { %>
<a href="/" class="flex items-center">
<a href="<%= page.language ? `/${page.language}` : '/' %>" class="flex items-center">
<img src="<%= basePath %>/<%= site.logo || '/assets/logo.svg' %>"
alt="<%= site.title %>"
class="h-10 w-auto object-contain transition-transform hover:scale-105">
Expand Down

0 comments on commit d465015

Please sign in to comment.