教你使用 100 行 Node.js 代码,快速构建一个静态网站生成器!

  • 时间:2018-09-07 22:01 作者:CSDN 来源:CSDN 阅读:153
  • 扫一扫,手机访问
摘要:近日,我的一位同事向我寻求建议,她打算为自己构建一个博客。于是,我对静态网站生成器和博客引擎进行了一番研究,发现 Hugo 是一个很不错的选择。但是,我的同事还有少量特殊要求,比方,她想要一个自己设置的博客网址和 CSS 主题。虽然这些 Hugo 都可以实现,但我并不打算花时间来学习它。我想自己创立
教你使用 100 行 Node.js 代码,快速构建一个静态网站生成器!

教你使用 100 行 Node.js 代码,快速构建一个静态网站生成器!

近日,我的一位同事向我寻求建议,她打算为自己构建一个博客。于是,我对静态网站生成器和博客引擎进行了一番研究,发现 Hugo 是一个很不错的选择。但是,我的同事还有少量特殊要求,比方,她想要一个自己设置的博客网址和 CSS 主题。虽然这些 Hugo 都可以实现,但我并不打算花时间来学习它。我想自己创立一个简单的静态网站生成器,以便我的同事在她已经准备好的 HTML 中编写博客文章。

这个静态网站生成器的代码大约 100 行,非常简洁。它提供了详细代码和示例博客 。众所周知,GitLab 提供静态页面的免费托管服务,还带有 CI/CD 功能,它允许你在部署之前编译页面。

以下教程将带你用 Node.js 设置自己的静态网站生成器,Node.js 的版本需要 “>= 8.11.x”。

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

首先,设置项目:

开始之前,我们需要弄清楚一个问题:为什么需要静态网站生成器?由于某些情况并不需要静态网站生成器。如果你的博客访问量很小,你只要简单地手工创立 HTML 页面并发布它们就可。实际上,在服务器编程兴起之前,在很长时间内这就是大多数 Web 的发布方式。但是,一旦页面和内容添加,对这些页面中的通使用部分(例如页面底部)进行更改将会变得非常重复和乏味。因而,我们开始寻觅一种更加理想的方法,尝试用某种简单的模板引擎来分离常见内容,而后在特定的地方插入所需的内容。

开始研究模板引擎之前,先设置我们的网站。我们需要在项目根目录下创立 2 个文件夹 :

  1. SRC:我们当前网站所在的位置;
  2. Public:使用来存放我们生成的网站。

我们的目标是将 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 个文件,我们可以在任何变化发生时重新生成整个网站:

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
}
);
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/partials,使用来存放网站的公共部分。而后略微修改我们的网站结构,保证所有页面都存放在 src/pages 目录中。接下来加载页面并用 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;
};
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]);
}
};

想要理解最终版本,请查看 Software Dawg 项目(https://gitlab.com/wheresvic/software-dawg)。它与本教程有少量细微差别:

  • 脚本本身位于 src 目录下。
  • 代码略超过了 100 行,大约 130 行,为了遵循简洁的代码实践风格,用常量而不是文件夹路径的字符串。
  • 该脚本不会复制整个 src 文件夹,而只复制必要的资源,比方 CSS 文件、图片等。
  • 该项目用 node-sass 编译模板 CSS。然而,这种依赖性不是必须的,由于已编译的 CSS 文件也被提交到了 Git。

此外,你还可以安装 browser-sync 软件包,而后通过命令 npm run live-reload 运行它,如此一来,只需有任何更改发生浏览器就会自动刷新。请注意,因为任何更改都将重新生成整个网站,因而并不适使用于 Windows。

GitLab 提供静态网站免费托管,只要一个 .gitlab-ci.yml 配置文件就可。真正令人难以置信之处在于,你可以自己设置构建过程,这意味着在该例中,我们可以在部署之前生成网站!有关此功能的详细信息,请参见https://about.gitlab.com/features/pages/。

本教程到此结束,我的同事对此非常满意,该方案非常灵活,它允许她根据自己的喜好进行自己设置,也希望对你有所助益!

原文:https://smalldata.tech/blog/2018/08/16/building-a-simple-static-site-generator-using-node-js

作者简介:Victor Parmar,是一位全栈工程师,酷爱旅行,酷爱 DIY。

译者:安翔,责编:屠敏

  • 全部评论(0)
最新发布的资讯信息
【系统环境|服务器应用】前台开发入门到实战:HTML5语义化元素你真的用的正确吗?(2019-08-22 04:16)
【系统环境|服务器应用】Vue仿微信app页面跳转动画(2019-08-22 04:16)
【系统环境|服务器应用】webstorm使用快捷键快速修正单个文件的style(2019-08-22 04:16)
【系统环境|服务器应用】程序员从学生到阿里经历的5次蜕变:海阔凭鱼跃,天高任鸟飞(2019-08-22 04:16)
【系统环境|服务器应用】var、let、const的区别(2019-08-22 04:16)
【系统环境|服务器应用】mini-ui加载框Indicator 被遮挡问题(2019-08-22 04:15)
【系统环境|服务器应用】【对讲机的那点事】玩对讲机,对于对讲机的亚音你理解吗?(2019-08-22 04:15)
【系统环境|服务器应用】前台中高级面试,内功心法(上)(2019-08-22 04:15)
【系统环境|服务器应用】17、改进轮播图之功能封装(2019-08-22 04:15)
【系统环境|服务器应用】第10题- 你不知道的delete操作符(2019-08-22 04:15)
手机二维码手机访问领取大礼包
返回顶部