「BLOG」 项目治理 (上) - 工程化

Posted on October 24, 2020

背景

初代的「BLOG」项目基于 Jekyll 进行搭建,将 Markdown、Liquid 和 HTML & CSS 构建为可发布的静态网站。

但相较于常用的 React、NPM 等工具,整体对于 Jekyll 的开发方式、插件体系不太熟悉(不想研究了…,所以对项目进行了一番改造。

目标

  • 一方面 保留了原来 post 的开发编译方式(Markdown -> HTML),可以通过 md 快速编写 BLOG。
  • 另一方面 可以快速通过 React 开发组件或者页面,进行扩展。

方案

将原来的 Jekyll 项目命名为 pangu,用于创建新的 blog;基于 create-react-app 新增项目 shennong。两个项目通过 monorepo 进行管理。

monorepo

monorepo 的优点:

  • 代码集中管理,方便共享和调试
  • 版本管理方便
  • 共享依赖、工程配置
  • 方便代码复用
  • 多个项目相互协作时原子提交
  • ……

整体的目录结构

.
├── packages
│      ├─ pangu
│      └─ shennong
├── scripts
│      ├─ build.sh            # 项目构建脚本
│      └─ sitemap.js          # 自动生成 sitemap.xml
├── .prettierrc               # 全局 prettier 配置
├── .prettierignore
├── .gitignore                # 全局 .gitignore
├── node_modules              # 整个项目只有一个外层 node_modules
├── README.md
└── package.json

scripts

global build

主要流程:ClearBuild panguBuild shennongMoveBuild sitemap

#!/usr/bin/env bash

# Clear
rm -rf build
CWD="$(pwd)" # /kyuch4n.github.io

# Pangu
# Build
cd $CWD/packages/pangu
yarn build
# Copy Build Files
cp -rf _site $CWD/build

# Shennong
# Build
cd $CWD/packages/shennong
yarn build
# Copy Build Files
cp -rf build $CWD/build/lab

# Regen Sitemap (Not Real Time)
echo '>>>>>>>>>>>>>>>>>>>>'
echo 'generate sitemap ...'
node $CWD/scripts/sitemap.js

在 build.sh 中分布调用 sub-package 各自的 build 脚本。

构建完成后会通过 cp 将各个 package 的 build 文件拷贝至项目根目录的 /build 文件夹中。

pangu build

通过 npm init 创建了 package.json,通过 npm scripts 进行构建。

{
  "private": true,
  "name": "@kyu/pangu",
  "version": "1.0.0",
  "scripts": {
    "watch:less": "nodemon -e less -x \"yarn build:less\"",
    "watch:widgets": "nodemon -e jsx -x \"yarn build:jsx\"",
    "watch:jekyll": "jekyll serve --watch",
    "start": "run-p watch:less watch:widgets watch:jekyll",
    "build:less": "lessc less/framework.less css/framework.css",
    "build:jsx": "npx babel widgets --out-dir js --presets react-app/prod",
    "build:sw": "node scripts/gen-sw.js",
    "build:jekyll": "jekyll build",
    "build": "run-s build:sw build:less build:jsx build:jekyll"
  },
  "dependencies": {
    "babel-cli": "6",
    "babel-preset-react-app": "3",
    "less": "^3.12.2",
    "nodemon": "^2.0.6",
    "npm-run-all": "^4.1.5"
  }
}

并行构建 less & jsx & service-worker & jekyll。

react for pangu

额外解决的一个小问题是如何快速在 Pangu(Jekyll) 中开发 React 小组件呢?方案是通过 CDN 加载 react 脚本。

具体方式可以参考 add-react-to-a-website。基于该方式成功开发并引入了 table-of-contents(Post 目录)小组件。

<script src="https://unpkg.com/react@16/umd/react.production.min.js" crossorigin></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js" crossorigin></script>
<!-- widgets -->
<script src="/js/table-of-content.js"></script>
'use strict';

const { createElement, useState, useEffect } = React;

const TableOfContent = () => {
  useState();

  // find all h1-h6 doms
  useEffect(() => {
  }, []);

  // listen page scroll
  useEffect(() => {
    const scrollHandler = () => {};
    window.addEventListener('scroll', scrollHandler);
    return () => window.removeEventListener('scroll', scrollHandler);
  }, []);

  return <div>...</div>;
};

// Mount
window.addEventListener('load', () => {
  const tableOfContentContainer = document.querySelector('#table-of-content');
  if (tableOfContentContainer) {
    ReactDOM.render(createElement(TableOfContent), tableOfContentContainer);
  }
});

成果

最终改造项目可见 Github Pro