如何利用webpack进行项目的发布记录管理
需求分析
我们在做一个项目过程中会遇到很多版本的迭代;这就会有很多的上线记录等着我们去做管理,在一些线上事故到来之际第一时间能够找到对应的版本回滚;
我们之前的做法是在全局window下面挂载一个Gdata对象,把每次发版的版本号记录上去;然后利用confluence去记录每次发版信息,比如作者、发布时间、对应的发布包名称;我个人觉得不失为一种很好的方案,但是借助第三方工具跟项目本身有了脱离。比如:打包完了项目,又要在confluence上记录下;动作一旦切换过多,其实很是比较反感的;所以我在看到webpack内置BannerPlugin插件的时候自己产生了一些想法。
BannerPlugin插件的作用就是在打包后的代码头部插入一些说明文字,那能不能动态的将本地的.md
插入到代码中呢;这样我们根据本地的文件与线上说明做一个对应起来;
要解决的几个问题
- 如何能够很好的将本地的md文件与插入的说明进行对应
- 如何进行
.md
文件的获取 - 如何解析
.md
文件的内容
- 如何能够很好的将本地的md文件与插入的说明进行对应
从我们要记录的内容出发,我们要记录的主要是时间、发布者、内容;从时间上看就是每天的时间;于是我们可以在项目生成一个notes
文件夹;里面的结构如下:
└── notes
├── 202003
│ ├── 0330.md
│ └── 0331.md
├── 202004
│ ├── 0401.md
│ └── 0402.md
- 如何进行
.md
文件的获取
原本想着直接用require()
去载入这个文件,但是node不支持直接这么引入;于是想用fs模块readFile
去读取这个文件内容;但是读取是异步操作;还是不能解决这个问题;好在还有个同步读取文件的方法fs.readFileSync
;于是读取的问题得到了解决;根据计算得出要读取的md文件fs.readFileSync(
./notes/${format(new Date(),'yyyyMM')}/${format(new Date(),'MMdd')}.md,'utf8')
- 如何解析
.md
文件
解析.md
文件,原本想找一个现成的插件;但发现大多数是解析成html或者vue的;于是我就自己把这个.md
文件内容进行了字符串解析;不过我这里的md文件内容是有规范要求的;
#### 需求发布记录
- 完成banner的构建
1. author:devin
2. daytime:20200331
3. content:具体的需求描述
- 改动了公共配置
1. author:devin
2. daytime:20200331
3. content:具体的需求描述
测试
222
解析代码如下:
const fs = require('fs');
const getMdText = () => {
let returnValue = {};
fs.access(`./notes/${format(new Date(),'yyyyMM')}/${format(new Date(),'MMdd')}.md`, (err) => {
if(err) return;
const mdText = fs.readFileSync(`./notes/${format(new Date(),'yyyyMM')}/${format(new Date(),'MMdd')}.md`, 'utf8')
let result = mdText.split('\n'); // 解析出md文档返回每一行可字符串
// 每次取最后一条记录,一般最后一条记录是最新的
const last_index = findLastIndex(result, item => {
return item.includes('-')
});
const splice_target = result.splice(last_index);
for (let i = 0; i < splice_target.length; i++) {
let curStr = splice_target[i].trim(),
nextStr = i + 1 < splice_target.length ? splice_target[i + 1].trim() : '.';
let cur_isDot = curStr.includes('.'),
isTitle = curStr.includes('-'),
next_isDot = nextStr.includes('.');
// 找到 -
if (curStr.includes('-')) {
returnValue['title'] = curStr.replace('-', '').trim();
}
// 找到 .
if (cur_isDot && next_isDot) {
let keyValue = curStr.split('.')[1].split(':');
returnValue[keyValue[0].trim()] = keyValue[1].trim();
}
// 空行情况, 处理如果一个. 下面有多个空行情况,进行拼接
if (cur_isDot && !next_isDot) {
let currentIndex = i + 1,
isnextDot = splice_target[currentIndex].includes('.');
while (!isnextDot && currentIndex < splice_target.length) {
curStr += splice_target[currentIndex].trim();
currentIndex++;
}
let keyValue = curStr.split('.')[1].split(':');
returnValue[keyValue[0].trim()] = keyValue[1].trim();
}
}
});
// 返回一个对象 {title: '改动了公共配置',author: 'devin',daytime: '20200331',content: '具体的需求描述测试222'}
return returnValue;
}
最后就是打包生成banner
- 我们可以忽略一些具体的修改记录打包到banner中;
new webpack.BannerPlugin({
banner: () => {
let str = ' ';
Object.keys(md).map(key => {
if (key !== 'content') {
return str += md[key]+' '
}
})
return str;
}
- 效果代码
/*! 改动了公共配置 devin 20200331 */ ! function (e) {...}(...)
- 最终的目的就是根据线上的代码的banner信息,在项目里找到对应的文档;
项目地址