Nodejs(甲方来了)个人博客+wiki需求报告
Nodejs(甲方来了)个人博客+wiki需求报告
最近想扔掉 wordpress,于是……
需求报告:(你需要做到这里描述的表观行为,而具体实现随意)
我要的是一个基于 nodejs 的个人博客 + wiki 系统。我用一个 git repo 来维护它的内容。使用 master 分支的最新内容。
这个 repo 里有若干目录,其中,.common
目录放置公共文件(如 HTML 模板),src
目录放置静态资源文件(如 css),blog
目录放置博客日志,其他的页面则是其他静态页,用于 wiki。
用来存储内容的主要是一种 HTML 替代格式,比如 markdown,或者我自己的 eido。.common
目录之外的所有文件彼此无关(因此不会一个 “内容文件” 依赖其他的 “内容文件”),他们都只依赖 .common
里的文件。
这个 node 应用是一个服务器,当访问非 html 的文件,比如静态资源时,直接返回之。当访问 /path/to/file.html
时,会调用(可配置的,见下文)生成器处理 /path/to/file.xx
,生成一个 html,然后由服务器作为响应。我们假定只要整个目录里的每个文件都没有修改,生成的 html 内容一定是相同的。
文档生成器是另一个外部程序,比如 eidoc
或者 markdownc
。启动这些程序的命令行任意,只要它正常退出后,.html 文件出现就行。
blog
目录里的所有「内容文件」由 git 的最后更新时间排序,且自动生成一个 index.html 作为文件列表;其他目录必须手动维护 index。
整个服务器必须尽可能优化性能(例如使用缓存或者静态文件),同时保持正确性。
(博客的评论使用 disqus 之类的服务因此不用考虑。)
Nodejs(甲方来了)个人博客+wiki需求报告
背景
最近想扔掉 WordPress,所以决定自己搭建一个基于 Node.js 的个人博客 + Wiki 系统。为了便于管理和版本控制,内容将通过 Git 仓库进行维护。
需求概述
- 使用 Node.js 构建一个个人博客 + Wiki 系统。
- 使用 Git 仓库管理内容,master 分支作为最新内容。
blog
目录下的内容按 Git 更新时间排序,并自动生成index.html
。- 其他目录需要手动维护
index.html
。 - 支持 Markdown 或自定义的 eido 语法。
- 生成的 HTML 文件应通过缓存优化性能。
目录结构
repo/
├── .common/ # 公共文件,如 HTML 模板、CSS、JS
│ ├── templates/
│ └── static/
├── src/ # 静态资源文件
│ ├── css/
│ └── js/
├── blog/ # 博客日志
└── wiki/ # Wiki 页面
功能需求
- 静态文件服务:
- 访问非 HTML 文件时,直接返回该文件内容。
- 动态生成 HTML:
- 当访问
/path/to/file.html
时,根据配置调用生成器处理/path/to/file.xx
并生成 HTML 文件。
- 当访问
- 缓存机制:
- 缓存生成的 HTML 文件以优化性能。
- 博客内容排序:
blog
目录下的文件按 Git 更新时间排序,并生成index.html
。
- Wiki 手动维护:
- 其他目录中的
index.html
需手动维护。
- 其他目录中的
示例代码
const express = require('express');
const fs = require('fs');
const path = require('path');
const spawn = require('child_process').spawn;
const app = express();
const PORT = 3000;
const CONTENT_DIR = path.join(__dirname, 'repo');
app.use(express.static(path.join(CONTENT_DIR, 'src')));
app.get('/blog', (req, res) => {
const blogPath = path.join(CONTENT_DIR, 'blog');
const files = fs.readdirSync(blogPath);
const sortedFiles = files.sort((a, b) => {
const aStat = fs.statSync(path.join(blogPath, a));
const bStat = fs.statSync(path.join(blogPath, b));
return bStat.mtime - aStat.mtime;
});
let content = '<ul>';
sortedFiles.forEach(file => {
content += `<li><a href="/blog/${file}">${file}</a></li>`;
});
content += '</ul>';
res.send(content);
});
app.get('/wiki/:dir/:file.html', (req, res) => {
const { dir, file } = req.params;
const filePath = path.join(CONTENT_DIR, dir, `${file}.xx`);
const outputPath = path.join(CONTENT_DIR, dir, `${file}.html`);
// 假设生成器为 markdownc
const generator = spawn('markdownc', [filePath, '-o', outputPath]);
generator.on('close', () => {
fs.readFile(outputPath, 'utf8', (err, data) => {
if (err) throw err;
res.send(data);
});
});
});
app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});
解释
- 静态文件服务:
- 使用 Express 的
express.static
中间件提供静态文件服务。
- 使用 Express 的
- 动态生成 HTML:
- 当访问
/blog
时,读取blog
目录下的文件并按更新时间排序,生成 HTML 列表。 - 当访问
/wiki/:dir/:file.html
时,调用外部生成器(如markdownc
)处理.xx
文件并生成.html
文件。
- 当访问
- 缓存机制:
- 在实际应用中,可以使用中间件或框架提供的缓存功能来优化性能。
- 博客内容排序:
- 通过读取文件状态信息(mtime)来排序文件。
- Wiki 手动维护:
- 其他目录的
index.html
需手动维护,不在代码中体现。
- 其他目录的
通过上述设计,可以构建一个高效且灵活的个人博客 + Wiki 系统。
什么情况? 是自己做的项目还是花钱找别人实现?
围观, 看着像 Jekyll, 好像现在还没看到好用的 Node 版本的, 楼主打算做?
搜了下发现一个项目 petrify,考察中。
但是发现 petrify 太长时间没更新……
针对您提到的需求报告,我们可以设计一个简单的 Node.js 应用程序来实现个人博客+wiki系统。以下是具体的设计思路与部分代码示例:
-
项目结构:
/my-blog-wiki ├── .common │ └── templates ├── src │ └── styles.css ├── blog │ └── blog-post-1.md │ └── blog-post-2.md ├── wiki │ └── page-1.md │ └── page-2.md ├── app.js └── package.json
-
应用逻辑:
- 使用 Express.js 作为 Web 服务器。
- 静态资源服务 (
src
和.common
)。 - 动态生成 HTML (
blog
和wiki
目录)。 - 使用 Git 获取文件的最后更新时间。
-
示例代码:
// app.js
const express = require('express');
const fs = require('fs');
const path = require('path');
const childProcess = require('child_process');
const app = express();
const PORT = process.env.PORT || 3000;
app.use(express.static(path.join(__dirname, '.common')));
app.use('/src', express.static(path.join(__dirname, 'src')));
app.get('/blog/:file', (req, res) => {
const filePath = path.join(__dirname, 'blog', req.params.file);
generateHTML(filePath, '.md', '.html', res);
});
app.get('/wiki/:file', (req, res) => {
const filePath = path.join(__dirname, 'wiki', req.params.file);
generateHTML(filePath, '.md', '.html', res);
});
function generateHTML(filePath, inputExt, outputExt, res) {
if (!fs.existsSync(filePath)) return res.status(404).send('File not found');
const outputPath = filePath.replace(inputExt, outputExt);
if (fs.existsSync(outputPath)) {
// Check if the content is cached and has not changed
const inputStat = fs.statSync(filePath);
const outputStat = fs.statSync(outputPath);
if (inputStat.mtimeMs <= outputStat.mtimeMs) {
return fs.readFile(outputPath, 'utf8', (err, data) => {
if (err) return res.status(500).send(err.message);
res.send(data);
});
}
}
const command = `markdownc ${filePath} > ${outputPath}`;
childProcess.exec(command, (error, stdout, stderr) => {
if (error) return res.status(500).send(stderr);
fs.readFile(outputPath, 'utf8', (err, data) => {
if (err) return res.status(500).send(err.message);
res.send(data);
});
});
}
app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});
- 优化与注意事项:
- 使用缓存策略来避免重复生成 HTML 文件。
- 可以进一步扩展为使用数据库存储生成的 HTML 文件路径,并根据需求添加更多功能,如自动索引生成、用户权限管理等。
这个简单的示例展示了如何构建一个基本的 Node.js 个人博客+wiki系统。实际开发中可能需要更多的细节优化和错误处理。