100行搭建一个node.js简单的静态站点生成器

  • 时间:2018-10-29 22:55 作者:前端嫣然呀呀呀 来源:前端嫣然呀呀呀 阅读:58
  • 扫一扫,手机访问
摘要:最近我的一个同事想开一个博客,问我有没有什么建议。在研究了少量静态站点生成器和博客引擎后,我觉得 Hugo 是个很不错的选择。然而,我同事还有少量其它需求,比方想让博客都有自己设置 URL 以及自己设置 CSS 主题。尽管用 Hugo 也能实现这些要求,但是我还是决定跳过学习使用 Hugo 这部分,

最近我的一个同事想开一个博客,问我有没有什么建议。在研究了少量静态站点生成器和博客引擎后,我觉得 Hugo 是个很不错的选择。然而,我同事还有少量其它需求,比方想让博客都有自己设置 URL 以及自己设置 CSS 主题。尽管用 Hugo 也能实现这些要求,但是我还是决定跳过学习使用 Hugo 这部分,看看假如我同事已经有随时可用的 HTML 而且在 HTML 中写博客没有问题,是否创立一个很简单的静态站点生成器。

接下来就教你使用 node.js >= 8.11.x 创立自己的静态站点生成器。我们首先设置项目:

npm init
npm i --save-exact bluebird chokidar fs-extra mustache
mkdir src
mkdir public

首先我们问一个问题——为什么需要静态站点生成器?答案是实际上你并不是很需要它。假如你的博客流量很小,只要要手工编写 HTML 页面而后发布就行了。实际上,在服务器端编程兴起之前,大部分 web 发布都是通过这种方式完成的。然而,假如你已经有了少量页面和内容,修改所有页面的共有部分(比方页脚)会很麻烦。因而,假如我们能有某种简单的模板引擎,可以分离出共有内容并将其插入需要的位置,那就再好不过了。

在讲解模板引擎前,首先设置我们的网站。我们会在项目根 src(当前网站所在的位置)和 public(包含我们生成的网站)下创立 2 个文件夹。将 src 的内容复制到 public,在你的项目根下创立如下 index.js:

const Promise = require("bluebird");
const fse = require("fs-extra");
Promise.resolve().then(async () => {
await main();
});
const main = async() => {
await generateSite();
};
const generateSite = async() => {
await copyAssets();
};
const copyAssets = async() => {
await fse.emptyDir("public");
await fse.copy("src", "public");
};

通过 node index.js 运行该脚本,而后坐等胜利的喜悦就完事儿了。

100行搭建一个node.js简单的静态站点生成器

图:恭喜,你现在是一名后台开发了!

在第二步,我们增加一个文件监视器,这样 src 文件夹内出现任何变动都会重新生成该网站。因为这会是个总共有 500-1000 个文件的博客(假设有 100 个博客条目),我们可以在任何变化时重新生成整个网站:

const chokidar = require("chokidar");
const main = async() => {
await generateSite();
watchFiles();
};
const watchFiles = () => {
const watcher = chokidar.watch(
[
"src"
],
{
ignored: /(^|[\/\\])\../, // chokidar will watch folders recursively
ignoreInitial: false,
persistent: true 前台交流;582735936

}
);
watcher.on("change", async path => {
console.log("changed " + path + ", recompiling");
await generateSite();
});
// catch ctrl+c event and exit normally
process.on("SIGINT", function() {
watcher.close();
});
};

上面的代码清楚的显示了为何最初的版本中有个叫 generateSite 的函数。我们现在可以通过 node index.js 启动我们的静态站点生成器,假如我们现在编辑 src 中的任何文件,产生的更改会在 public 中反映出来。在这里我们还会增加一个环境变量,用以区分开发和生产模式。在开发模式下,我们将监视产生的更改并重新生成网站,而在生产模式下,我们只重新生成:

const env = process.env.NODE_ENV || "dev";
const main = async () => {
console.log("Running app in " + env);
await generateSite();
if (env === "dev") {
watchFiles();
}
};

我们可以通过 export NODE_ENV=prod || set NODE_ENV=prod && node index.js 运行以上代码。注意监视更改的源目录,并不完全需要重新编译,可以跳过这一步,只要在每次进行更改时运行脚本,但编程就是要避免做重复工作。

我们快要完成了!现在我们回到创立静态站点生成器的初步阶段:建模。我们会使用 Mustache.js 用于创立模板,由于它是最简单的方法,我们的需求也不是很复杂。我们创立一个文件夹 src/patials,它会保存我们的共有部分。而后我们稍微修改网站结构,这样一律页面现在就出现在 src/pages中了。剩下的工作就是加载所有的 partials 文件、加载页面并用 Mustache 渲染它们:

const fs = require("fs");
const generateSite = async () => {
await copyAssets();
await buildContent();
};
const buildContent = async () => {
const pages = await compilePages();
await writePages(pages);
};
const compilePages = async () => {
const partials = await loadPartials();
const result = {};
const pagesDir = path.join("src", "pages");
const fileNames = await fs.readdirAsync(pagesDir);
for (const fileName of fileNames) {
const name = path.parse(fileName).name;
const fileContent = await fs.readFileAsync(path.join(pagesDir, fileName));
result[name] = Mustache.render(fileContent.toString(), {}, partials);
}
return result; 前台交流;582735936
};
const loadPartials = async () => {
const result = {};
const partialsDir = path.join("src", "partials");
const fileNames = await fs.readdirAsync(partialsDir);
for (const fileName of fileNames) {
const name = path.parse(fileName).name;
const content = await fs.readFileAsync(path.join(partialsDir, fileName));
result[name] = content.toString();
}
return result;
};
const writePages = async pages => {
for (const page of Object.keys(pages)) {
await fs.writeFileAsync(path.join("public", page + ".html"), pages[page]);
}
};

最终的代码版本参见 GitLab 上的 Software Dawg 项目( https:// gitlab.com/wheresvic/so ftware-dawg ),和教程中的内容有几处细微的不同:

脚本本身在 src 文件夹中。

稍微超过了 100 行,主要是因为干净的代码实践,即常量而不是文件夹路径的字符串等。

没有复制整个 src 文件夹,脚本只复制了必须的文件,比方 CSS,图像等。

项目还用了 node-sass 来编译模板 CSS,不过该环境依赖不是必须的。

另外,你还可以全局安装 browser-sync 包,通过提供的命令行 npm run live-reload 运行,这样你的浏览器会自动刷新所有页面。注意,因为我们是根据更改重新生成整个站点,所以在 Windows 上效果不太好。

通过本文的方法,几乎完美地满足了我同事的需求,不仅非常灵活,而且还能让她根据自己的喜好进行自己设置。

  • 全部评论(0)
手机二维码手机访问领取大礼包
返回顶部