🥝FANMR.CN热爱,追求
基于Node的静态博客

设计思路

静态博客的最终产物为一个个HTML页面文件,为了实现该功能,可以利用Node来对文件进行读取和写入,根据自己的文件管理习惯,按照最后的产物设计相关的代码逻辑

如何接收终端命令

Node自带的process.argv参数提供了对命令的解析,因此可根据这个特点自定义服务的命令

本地预览

使用的是Node的http模块,启动端口对文件下的文件进行静态文件服务传输,这里需要注意的是,虽然实现了静态文件的浏览,但是无法实时更新,所以需要同时对重要的文件进行监听,代码示例:

function runServer() {
  // 先生成静态文件,防止没有文件进行访问
  startGenerate()
  // 需要访问的文件的存放目录(项目所在位置的文件夹路径)
  var documentRoot = './target'
  // 启动服务
  http.createServer(function (req, res) {
    var url = req.url
    if (url == '/') {
      url = '/index.html'
    }
    var file = documentRoot + url
    fs.readFile(file, function (err, data) {
      if (err) {
        // 配置404
        res.writeHeader(404, {
          'content-type': 'text/html;charset="utf-8"'
        })
        res.write(readFile('target/404.html'))
      } else {
        // 请求头设置
        // html的请求头 Content-Type : text/html ; charset=utf-8
        // CSS的请求头 content-type:  text/css; charset=utf-8
        // JavaScript的请求头 content-type:  text/javascrpt; charset=utf-8
        let contentType = 'text/html;charset="utf-8"'
        if (url.indexOf('.css') > -1) {
          contentType = 'text/css;charset=utf-8'
        } else if (url.indexOf('.js') > -1) {
          contentType = 'text/javascrpt;charset=utf-8'
        }
        res.writeHeader(200, {
          'content-type': contentType
        })
        res.write(data)
      }
      res.end()
    })
  }).listen(7981)

  // 监听文件变化(recursive开启深度监听)
  fs.watch('./docs', { recursive: true }, () => {
    startGenerate()
  })
  fs.watch('./source', { recursive: true }, () => {
    startGenerate()
  })
  console.log('服务器开启成功,访问http://localhost:7981/')
}

静态资源复制

对于静态资源文件,如文章的图片、logo等文件,可以将其复制到服务启动文件夹下,复制代码逻辑

/**
 * 文件夹复制(递归支持下级目录)
 */
function cpSync(source, destination) {
  let major = process.version.match(/v([0-9]*).([0-9]*)/)[1]
  let minor = process.version.match(/v([0-9]*).([0-9]*)/)[2]
  // 判断node版本不是16.7.0以上的版本
  // 则进入兼容处理
  // 这样处理是因为16.7.0的版本支持了直接复制文件夹的操作
  if (Number(major) < 16 || Number(major) == 16 && Number(minor) < 7) {
    // 如果存在文件夹 先递归删除该文件夹
    if (fs.existsSync(destination)) fs.rmSync(destination, { recursive: true })
    // 新建文件夹 递归新建
    fs.mkdirSync(destination, { recursive: true })
    // 读取源文件夹
    let rd = fs.readdirSync(source)
    for (const fd of rd) {
      // 循环拼接源文件夹/文件全名称
      let sourceFullName = source + "/" + fd
      // 循环拼接目标文件夹/文件全名称
      let destFullName = destination + "/" + fd
      // 读取文件信息
      let lstatRes = fs.lstatSync(sourceFullName)
      // 是否是文件
      if (lstatRes.isFile()) fs.copyFileSync(sourceFullName, destFullName)
      // 是否是文件夹
      if (lstatRes.isDirectory()) cpSync(sourceFullName, destFullName)
    }
  } else {
    fs.cpSync(source, destination, { force: true, recursive: true })
  }
}

如何与模板拼合

使用的方案是js的替换replace,在模板中自定义语法,例如${postName},在文件写入前对字符内容处理即可

部署问题

为了更加便捷的部署到Github,增加了一个脚本功能,需要将其复制到target

// 复制部署文件
fs.copyFileSync('./source/deploy.js', './target/deploy.js')

其中的内容为终端命令,根据实际情况做调整


const { execSync } = require("child_process")
var fs = require('fs')

/**
 * 部署
 */
if (fs.existsSync('.git')) {
  fs.rmSync('.git', { recursive: true })
}
console.log('执行命令 git init');
execSync('git init')
console.log('执行命令 git add article category images source index.html CNAME 404.html');
execSync('git add article images static index.html')
console.log('执行命令 git commit');
execSync('git commit -m commit')
console.log('执行命令 git branch -M main');
execSync('git branch -M main')
console.log('执行命令 git remote add origin');
execSync('git remote add origin https://github.com/fanmore/fanmore.github.io.git')
console.log('执行命令 git push -u -f origin main');
execSync('git push -u -f origin main')

执行方式为先进入target文件夹下,执行该脚本

Github访问慢问题

由于Github的服务器在国外,访问起来总有慢的时候,可以使用CDN解决,使用的前提条件是

  • 拥有自己的域名
  • 已经备案

这里推荐的是又拍云,操作上最为简单,大致步骤为

  • 登录注册又拍云
  • 创建CDN服务,并配置域名、源站、证书
  • 在Github的博客仓库上填写自定义域名(否则访问出现404),同时记得将CNAME文件保留

一开始尝试了阿里云的CDN,在域名那个步骤需要到github.com下放置文件,放弃了

问题

部署可能因为网络原因,无法成功部署,与Github有关