umi脚手架搭建的项目_15天零成本搭建静态博客,托管于Github Page

博客地址
技术栈概览
- 前台:Umi(路由) + Antd(视图) + TypeScript(增加项目可维护性以及规范性)
- 后台:Umi(路由) + Antd(视图) + TypeScript(增加项目可维护性以及规范性) + Rematch(数据管理)
- 服务:Egg.js(基于koa的下一代企业级应用框架) + MongoDB
搭建思路
启动本地Mongo以及Egg服务,随后启动博客后台,编辑文章,将文章数据保存在本地Mongo数据库。将本地Mongo数据导出为JSON,前台页面用静态JSON渲染,通过webpack将前台工程打包成静态页,所有静态资源托管于github page。通过github page提供的映射域名即可访问静态页index.html。
优点
- 不需要购买域名以及服务器
- 可以通过issue参与文章评论互动
- 整个搭建流程有利于提高对项目的理解与认知
缺点
- github服务器响应速度慢,导致页面响应速度慢
- 域名晦涩难记
- 无法实现登录注册留言等交互功能,缺乏互动性
总结
该静态博客搭建适合有一定基础,需要项目练手的初级前端开发工程师。博客搭建省时省力,堪称居家必备良品。一方面有利用提升自身综合实力,另一方面不用为域名和服务器的到期而堪忧。当文章质量得到保证时,有利于提高github知名度。
搭建流程
一、 前台
UI设计
由于博主本人对设计领域着实没有建树,所以该博客的UI设计借鉴了一位小姐姐的博客UI
路由设计

搭建工程目录
├── config
│ ├── config.js
│ └── proxyConfig.js
├── package.json
├── src
│ ├── assets
│ ├── common
│ ├── components
│ ├── global.less
│ ├── layouts
│ ├── pages
│ ├── plugins
│ │ └── rematchPlugin
│ │ ├── createPlugin.d.ts
│ │ ├── createPlugin.js
│ │ ├── index.js
│ │ ├── runtime.ts
│ │ ├── template
│ │ │ ├── RematchContainer.tsx
│ │ │ └── Store.ts
│ │ └── ulits.js
│ ├── services
│ ├── store.ts
│ ├── types
│ └── utils
├── tsconfig.json
├── tslint.json
├── typings.d.ts
响应式设计
博客响应式设计主要采用了Antd的栅格化系统以及enquire-js来判断浏览设备窗口大小
封装工具类:
/*** @name 判断浏览设备*/
export function distingIsMobile<T>(): boolean {let isMobile = false;enquireScreen(value => {isMobile = value;});return isMobile;
}
技术难点
- markdown语法的渲染。
我首先采用了react-markdown来渲染markdown语法。但是该组件存在一定的问题:
code代码块语法高亮无法实现,网上的一些解决办法并不生效。 于是我放弃了使用这个组件。转向了markdown-it。同时结合markdown-it-highlightjs实现code语法高亮,以此做了一个简单的封装,实现自己的markdown组件。
import React, { Component, Fragment } from 'react';
import { Basic } from 'src/types';
const marked = require('markdown-it')().use(require('markdown-it-highlightjs'));
interface Props extends Basic.BaseProps {source: string;
}
export default class ReactMarkdown extends Component<Props> {renderMarkdown = () => {const source = this.props.source;return <div dangerouslySetInnerHTML={{ __html: marked.render(source) }} />;};render() {return <Fragment>{this.renderMarkdown()}</Fragment>;}
}
一切搞定之后,发现code标签内的代码已经成功分割为独立的标签,但是css并未生效,是因为还未定义高亮的css样式,于是我找到highlight.js官网,选了一个中意的高亮样式,然后在github中找到这个样式的css文件,copy到项目中,搞定!
- 动画的设计。博客采用Antd Animotion来实现动画效果。该博客的动画花费了博主大量的时间去设计和实现。
- 简历模块采用react-fullpage来实现单页滚动效果。其中,第三板块的技术栈详情弹窗采用了antd的modal,弹窗实例化后,改变了body的overflow值,导致单页滚动失效。博主通过按钮的点击事件手动设置body的overflow样式得以解决该问题。
- md引用语法不生效。通过手动设置blockquote元素的css样式。blockquote { padding: 0 1rem; margin-left: 0; color: #819198; border-left: .3rem solid #dce6f0; }
二、 后台
模块设计

最终效果

代理配置
const devPath = 'http://127.0.0.1:7001'; // 代理地址指向本地egg服务运行地址
export default {'/api/': {target: devPath,changeOrigin: false}
};
技术难点
- MarkDown编辑器选型
博主最终采用SimpleMDE。
效果图:

实例化:
componentDidMount() {this.renderContEditorNode(); // 实例化内容编辑器this.renderSumEditorNode(); // 实例化摘要编辑器}renderContEditorNode() {this.contEditNode = new SimpleMDE({element: document.getElementById('contEditor').childElementCount,...simpleMdConfig});}renderSumEditorNode() {this.sumEditNode = new SimpleMDE({element: document.getElementById('sumEditor').childElementCount,...simpleMdConfig});}
编辑器simpleMdConfig配置:
/**
* @name SimpleMDE配置
*/
export const simpleMdConfig = {
autofocus: true,
autosave: true,
shortcuts: {drawTable: 'Cmd-Alt-T'
},
showIcons: ['code', 'table'],
tabSize: 4,
placeholder: '在这里编辑',
toolbar: ['bold','italic','strikethrough','heading','code','quote','unordered-list','ordered-list','clean-block','link','image','table','horizontal-rule','preview','side-by-side','fullscreen','guide'
],
previewRender(plainText) {return marked(plainText, {renderer: new marked.Renderer(),gfm: true,pedantic: false,sanitize: false,tables: true,breaks: true,smartLists: true,smartypants: true,highlight(code) {return highlight.highlightAuto(code).value; // 采用highlight.js实现代码块语法高亮}});
}
};
遇见的问题:
{key: 'summary',label: '摘要 - 内容',node: (<textareastyle={{ maxHeight: '300px', overflow: 'auto' }}id="sumEditor"/>)},{key: 'content',node: (<textareaid="contEditor"style={{ maxHeight: '300px', overflow: 'auto' }}/>)},
由于我采用了自己封装的表单组件,组件内部存在一定的异步渲染,因此在页面渲染结束时,无法找到实例化的textarea元素,因此报错。
解决办法:
在render函数内写入两个隐藏的textarea元素,保障组件实例化后能够找到对应的dom元素,从而成功实例化编辑器。
<textarea id="contEditor" style={{ display: 'none', maxHeight: '300px', overflow: 'auto' }} />
<textarea id="sumEditor" style={{ display: 'none', maxHeight: '300px', overflow: 'auto' }} />
- 图片资源的存放 博客选用ipic第三方软件来存放图片资源库。

通过简单的拖拽就可以实现图片的上传,上传成功后返回图片地址。
三、服务
通过官方脚手架叫快速生成
$ npm i egg-init -g
$ egg-init egg-example --type=simple
$ cd egg-example
$ npm i
修改配置
'use strict';module.exports = appInfo => {const config = (exports = {});// use for cookie sign key, should change to your own and keep securityconfig.keys = appInfo.name + '_1544961945990_6105';// add your config hereconfig.middleware = [];/*** @name mongo配置,通过egg-mongoose连接mongo*/config.mongoose = {url: 'mongodb://127.0.0.1:27017/MingShined',options: {useMongoClient: true,autoReconnect: true,reconnectTries: Number.MAX_VALUE,bufferMaxEntries: 0}};/*** @name 关闭csrf*/config.security = {csrf: {enable: false}};return config;
};
启动项目
$ npm run dev
$ open localhost:7001
数据库设计

restfulApi风格的路由设计
'use strict';
module.exports = app => {const { router, controller } = app;/*** @name 新增文章*/router.post('/api/article', controller.article.article.createArticle);/*** @name 导出文章*/router.get('/api/article/download',controller.article.article.downloadArticle);/*** @name 获取文章列表*/router.get('/api/article', controller.article.article.queryArticleList);/*** @name 编辑文章*/router.put('/api/article', controller.article.article.updateArticle);/*** @name 获取文章详情*/router.get('/api/article/:id', controller.article.article.findArticle);/*** @name 获取文章详情*/router.delete('/api/article/:id', controller.article.article.deleteArticle);/*** @name 获取关于我*/router.get('/api/about', controller.article.article.getAbout);/*** @name 保存关于我*/router.post('/api/about', controller.article.article.createAbout);/*** @name 下载关于我*/router.get('/api/about/download', controller.article.article.downloadAbout);
};
技术难点
- 导出本地mongo数据为JSON
/*** @name 下载文章*/async downloadArticle() {const json = await this.service.article.queryArticleList();this.ctx.attachment('article.json'); this.ctx.set('Content-Type', 'application/json');this.ctx.body = JSON.stringify(json);}
总结
总的来说,纯手撸一个静态博客还是挺有成就感。整个过程遇到种种问题,在这个过程中,不断总结进步,提升较大。搭建成功后,也为自己开拓了一个属于自己的平台,通用的md语法也可以同步到知乎,掘金等社区。对博主以及博主的文章有什么意见建议,欢迎联系博主。
- QQ:996578843
相关文章:

[maven] 使用问题及思考汇总
(1)Maven坐标 maven坐标可以唯一标识一个项目,包含四个元素 groupId , artifactId, packaging, version。 groupId:一般为团体,公司,项目。如 oceanic-web, oceanic-dal, oceanic-biz 同属一个 groupId。 artifactId:在…

VS调试时提示此项目已经过期
问题出因: 1.先前卸载VS重新安装时不全面 解决办法: 1.VS应安装两个C的组件 2.首先在“生成”-》 “生成解决方案”完成编译,问题解决。

(DBA之路【五】)关于锁的故事
首先很抱歉:这篇文章我其实整合了很多别人的文章,但是因为太多,一开始被没留意出处所以很难声明来源,很抱歉,但是这篇文章只用来作为学习笔记,作为新手,我以后会注意的。(一…
Android Studio Day03-1(Android studio 系统界面简介)
IDE(integrated Development Environment)的主要的目的就是用来编辑文本的。 在界面中的分布如下(以下的两张图片均为的《Android studio实战快速高效地构建Android应用》一书中的)

全流程游戏模型制作学习教程
尤金彼得罗夫|时长:36小时 |视频:H264 19201080 |音频:AAC 44,1 kHz 2ch |大小解压后 35 GB 含课程文件 |语言:英语 (无字幕,) 在本教程中,我将介绍为现代FPS视频游戏创建游戏就绪武器资产的整个过程。我将展示我的工作管道,使用…

requirednew基于xml配置日志不回滚_Elasticsearch配置IK分词器的远程词库
在生活中很多很多地方都涉及到了全文检索,最常见的就好比日常使用到的百度搜索等搜索引擎,也都是基于全文检索来实现的;全文检索种类较多,就好比Elasticsearch、Sorl等。为Ealsticsearch配置词库,可以很好的解决生活中…

PS切图篇(一)---界面设置
#工作区设置 四大主要面板:信息 字符 图层 历史记录 打开必要属性: 选择工具设置 选择图层的方式:ctrl鼠标左击想选择的图层转载于:https://www.cnblogs.com/yinzf/p/5339873.html
简单解决用VS编写hello world时命令行一闪而过
一、在return 0;前一行加一个getchar(); 二、使用项目模板为 windows 桌面向导 c 3、命令行控制台一闪而过。这是我们使用空文件夹加载的项目,默认不是控制台应用程序,新建控制台程序,或者在代码中加入system(“pause”);这种通过代码人为的…

粒子群算法(1)----粒子群简要
一、历史粒子群算法从复杂适应系统衍生PSO算法(Complex Adaptive System,CAS)。CAS理论于1994年正式提出,CAS中的成员称为主体。比方研究鸟群系统,每一个鸟在这个系统中就称为主体。主体有适应性,它能够与环境及其它的…
Android Studio Day03-2(常用操作)
(1)选择文本 1.CtrlA 选中全文 2.在将光标置于任意的单词中时按住CtrlW,选中整个词 继续按CtrlW 选中的区域将扩大,扩大至包含任意数量的相邻的单词 按CtrlwShift 进行区域的缩小 (2)Undo和Redo&…

Blender数字雕刻终极指南学习教程
CGBoost–Blender中的3D雕刻大师–数字雕刻终极指南 大小:29G 含课程项目文件 Master 3D Sculpting in Blender – The Ultimate Guide to Digital Sculpting 本课程教你所有重要的Blender雕刻基础知识,以及如何仅使用免费工具从头开始创建令人惊叹的3D雕…

生产指挥调度系统_市安全生产应急救援指挥中心将大型装载机械设备储备信息纳入应急指挥调度系统...
为拓展应急救援力量体系,发挥社会力量在开展全市重特大突发事件应急救援中的重要作用,近日,市安全生产应急救援指挥中心在加强应急指挥信息平台“一网七库”建设的基础上,成功对接甘肃省非道路移动机械监管平台,做到数…

java.sql.Exception:setString 只能处理少于 32766 个字符的字符串
java.sql.Exception:setString 只能处理少于 32766 个字符的字符串 解决方式是 : 升级ojdbc的版本, 将原来的 ojdbc14_10.2.0.2.0.jar 升级到 ojdbc6_11.2.0.1.0.jar这边行方用的是 oracle版本是 Oracle Database 11g Enterprise Edition Release 11.2.0.4.0maven 安装到本地…

无需自己输入include这些的方法
使用项目模板为 windows 桌面向导 c 不用空白项 直接默认 不用勾选其他

第二次团队冲刺2
实现了查询的webservice服务端,做了查询时等待界面,对查询速度做了一点优化。 还写了一个入馆须知模块,介绍图书馆借阅规则。 还有借阅个人信息没做出来,还没进行界面优化。 转载于:https://www.cnblogs.com/318abc/p/4569576.htm…
Android StudioDay03-3(键盘导航)
Android Studio Day03-3(键盘导航) (1)打开Select In 快捷键:altF1 如下图: (2)打开Class CtrlN Class操作允许用后导航到特定的JAVA类),因此此操作也只能在Java文件中使用。 Android studio已…

虚幻中的风格化环境制作学习教程
Learn Squared-Tyler Smith-虚幻中的风格化环境 信息: 像AAA游戏开发者一样在虚幻引擎中创建风格化的环境。行业领先的游戏艺术家泰勒史密斯将教你在虚幻引擎中构建美丽的实时世界的规划、构建、集成和优化阶段使用多种巧妙的技术。 大小解压后:22G 时长6h 13m 19…

【转】oracle PLSQL基础学习
【转】oracle PLSQL基础学习 --oracle 练习;/**************************************************PL/SQL编程基础***************************************************************/--firstday--》》》数据类型-- Create tablecreate table T_CSCUSTOMER( CUST_NO…

python如何创建不同元素的矩阵_python – 如何在数据帧中创建矩阵元素的数...
我在.TXT文件中有3个参数’A’,’B’,’C’的数据集,在我用2420矩阵打印后,我需要收集’A’,’B’,’C’的第一个元素熊猫数据帧中的长数组,然后是每个第二个元素,然后是第3个,直到第480个元素为止. 所以我的数据在文本文件中是这样的: 我的数据是txt文件如下&#…

wps多窗口打开
在wps中打开wps文档不在一个窗口的方法如下: 1、启动wps文档,点击wps文字→选项,在弹出的选项对话框点击视图选项卡,勾选 在任务栏中显示所有窗口;

RHEL7.0系列 修改字符终端分辨率
由于是在VM里面安装的,完了之后终端界面的分辨率非常高,很难操作 因为RHEL7用了grub2,而不再是grub了,在grub2中要修改的文件是/boot/grub2/grub.cfg; 这里有一张分辨率的对照表(在grub.cfg中添加vgaask,系统重启后就会…
Java Day01-1
1.JAVA语言介绍 (1)特点:可移植性,平台无关性,面相对性,健壮性,分布式,多线程 (2)版本:JavaSE(标准版)、JavaME…

Autocad 3D 完全学习教程
Autocad 3D 完全学习教程 你会学到什么 如何使用AutoCAD三维基本特征 了解如何在AutoCAD中创建和开发三维模型 准备实体、网格和曲面几何图形 不同的命令2d和3D 要求 不需要事先了解 18章 63节讲座 全长5小时7分 语言:英语中英文字幕(根据原英文字幕机译…
[转]JAVA中Action层, Service层 ,modle层 和 Dao层的功能区分
首先这是现在最基本的分层方式,结合了SSH架构。modle层就是对应的数据库表的实体类。Dao层是使用了Hibernate连接数据库、操作数据库(增删改查)。Service层:引用对应的Dao数据库操作,在这里可以编写自己需要的代码&…

springmvc工作流程简单易懂_三极管的结构和工作特性,简单易懂
今天,我们来认识另一种十分重要的半导体器件:三极管。生活中,授课、集会、维持秩序等场合需要用到扩音器、音响等设备,这些设备之所以能够放大声音是因为它们都包含放大器,而放大器的核心部件就是三极管。那三极管究竟…

多个excel文件(内含多个工作表)查找
1.在父目录查找处输入关键词 2.将找到的文件进去查找-工作簿

git ssh key创建和github使用
github拉代码需要ssh验证 git是分布式的代码管理工具,远程的代码管理是基于ssh的,所以要使用远程的git则需要ssh的配置。一 、设置git:设置git的user name和email:$ git config --global user.name "xxx"$ git config -…

C语言常见面试题:什么是变量?变量有哪些作用?
变量是编程中的一个基本概念,其定义和用法因编程语言和上下文而异。但通常来说,变量是用于存储数据的容器,这些数据可以是数字、文本、布尔值等。总的来说,变量在编程中扮演着重要的角色,它们使得我们能够有效地存储、操作和使用数据。不同的编程语言和上下文可能会对变量的具体定义和使用方式有所不同,但上述作用是通用的。总的来说,变量和常量都是编程中重要的概念,它们各自有其特定的用途和特性。在编程中正确地使用它们可以帮助我们更好地组织和控制程序的行为。变量和常量在编程中都是重要的概念,但它们之间存在明显的区别。
Java Day01-2
一、字节码的解释 字节码:是一种在Java运行系统(JVM)中执行的更高度优化的指令集。 C/C 是一种编译型的语言; 文件经过编辑,编译,执行之后生成的是一种.exe的可执行文件。 Java:是一种解释型的语言&…

SparkSQL和Hadoop(面向数据科学家和大数据分析师)
了解HDFS命令、Hadoop、Spark SQL、SQL查询、ETL和数据分析| Spark Hadoop集群虚拟机|完全解决的问题 你会学到什么 作为本课程的一部分,学生将获得在Spark Hadoop环境中工作的实践经验,该环境是免费且可下载的。 学生将有机会在沙箱环境中使用Hadoop集…