博客部署调整记录
This commit is contained in:
parent
1618668b14
commit
10ca6c1d4c
@ -4,7 +4,7 @@ date: 2019-04-23 19:13:17
|
|||||||
tags:
|
tags:
|
||||||
- nodejs
|
- nodejs
|
||||||
categories:
|
categories:
|
||||||
- linux
|
- 前端杂烩
|
||||||
---
|
---
|
||||||
|
|
||||||
本着不折腾不舒服的原则, 之前的图片迁移与构建时的自动同步虽然已经实现
|
本着不折腾不舒服的原则, 之前的图片迁移与构建时的自动同步虽然已经实现
|
||||||
@ -5,7 +5,7 @@ tags:
|
|||||||
- jenkins
|
- jenkins
|
||||||
- nodejs
|
- nodejs
|
||||||
categories:
|
categories:
|
||||||
- linux
|
- 前端杂烩
|
||||||
---
|
---
|
||||||
|
|
||||||
之前博客的图片都是直接访问自己的服务器的, 无奈我的服务器带宽太小
|
之前博客的图片都是直接访问自己的服务器的, 无奈我的服务器带宽太小
|
||||||
300
source/_posts/前端杂烩/博客部署调整记录.md
Normal file
300
source/_posts/前端杂烩/博客部署调整记录.md
Normal file
@ -0,0 +1,300 @@
|
|||||||
|
---
|
||||||
|
title: 博客部署调整记录
|
||||||
|
date: 2019-05-11 19:01:11
|
||||||
|
tags:
|
||||||
|
- gulp
|
||||||
|
- nodejs
|
||||||
|
categories:
|
||||||
|
- 前端杂烩
|
||||||
|
---
|
||||||
|
|
||||||
|
让你永远都有事情可忙正是前端的魅力所在
|
||||||
|
<!-- more -->
|
||||||
|
按照目前的策略, 博客构建部署大概是以下几个步骤
|
||||||
|
1. 主题内容的webpack打包
|
||||||
|
2. hexo clean && hexo generate
|
||||||
|
3. 图片与对象存储仓库同步
|
||||||
|
4. 生成的html文件的压缩
|
||||||
|
5. public目录中所有内容的拷贝发布
|
||||||
|
|
||||||
|
因为不想把主题和内容过多整合, 这样会导致将来更换主题困难
|
||||||
|
所以计划是把2 3 4 5步骤在构建过程中一键完成
|
||||||
|
( 虽然有jenkins可以写多步的执行脚本, 但是仍然感觉不够优雅 )
|
||||||
|
最好是能有个js脚本, 用nodejs一次执行完成这些步骤
|
||||||
|
|
||||||
|
第2步之前用的是hexo的命令行工具, 现在可以换成hexo的api, 在js当中调用之
|
||||||
|
|
||||||
|
第3步之前已经完成了, 就是用js写的脚本, 简单封装一下拿过来就可以用
|
||||||
|
|
||||||
|
第4步目前还没有做到, 准备实现一下, 因为webpack完成了对css和js的压缩输出, 所以静态化后就无需再次处理了
|
||||||
|
但是html文件是由hexo生成, 所以对主题内容的webpack打包, 是无法完成这件事的
|
||||||
|
查了一些资料发现gulp可以很简单做到, 于是就计划用它了
|
||||||
|
|
||||||
|
第5步, 就在js里面写递归删除与递归拷贝吧
|
||||||
|
|
||||||
|
### hexo的api
|
||||||
|
根据官网的介绍, 可以按照下面的方式使用hexo的api
|
||||||
|
```javascript
|
||||||
|
const Hexo = require('hexo')
|
||||||
|
const hexo = new Hexo(process.cwd(), {})
|
||||||
|
hexo.init().then(()=>{ // 链式的Promise调用, 每一步都要返回Promise对象
|
||||||
|
return hexo.call('clean')
|
||||||
|
}).then(()=>{
|
||||||
|
return hexo.call('generate', {watch: false})
|
||||||
|
}).then(()=>{
|
||||||
|
return hexo.exit()
|
||||||
|
}).catch(err => {
|
||||||
|
return hexo.exit(err)
|
||||||
|
})
|
||||||
|
/* 当然也可以采用更加简洁的await
|
||||||
|
try {
|
||||||
|
await hexo.init()
|
||||||
|
await hexo.call('clean')
|
||||||
|
await hexo.call('generate', { watch: false })
|
||||||
|
return hexo.exit()
|
||||||
|
} catch (err) {
|
||||||
|
return hexo.exit(err)
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
```
|
||||||
|
上面的写法就如同是在命令行执行`hexo clean && hexo generate`
|
||||||
|
正好gulp配置任务的时候也需要返回Promise对象( 下面会提到 ), 正好能结合, 不需要二次封装了, 不错
|
||||||
|
|
||||||
|
### gulp
|
||||||
|
之前没用过这个前端构建工具, 因为跟webpack的作用有不少的重合, 前端实在学不完
|
||||||
|
这里使用一下它的任务自动管理的功能, 整体的体验挺好
|
||||||
|
|
||||||
|
#### 安装
|
||||||
|
除了gulp本身, 还有其他几个用的到的插件 ( 当然也可以用npm安装 )
|
||||||
|
```bash
|
||||||
|
# 这几个是gulp相关的
|
||||||
|
yarn add gulp gulp-htmlclean gulp-htmlmin gulp-plumber -D
|
||||||
|
# 这是图片同步到对象仓库相关的
|
||||||
|
yarn add @xgheaven/nos-node-sdk optimist -D
|
||||||
|
```
|
||||||
|
gulp在**4.0**这个大版本做了很大的改变, 这里我使用的是4.0.2
|
||||||
|
|
||||||
|
#### gulpfile.js
|
||||||
|
在根目录下创建`gulpfile.js`文件, 这个文件是gulp的配置文件
|
||||||
|
先简单规划一下结构
|
||||||
|
```javascript
|
||||||
|
const gulp = require('gulp')
|
||||||
|
|
||||||
|
// 创建静态页面 (等同 hexo generate)
|
||||||
|
gulp.task('generate', () => {
|
||||||
|
// TODO 执行hexo的api
|
||||||
|
})
|
||||||
|
|
||||||
|
// 压缩public目录下的html文件
|
||||||
|
gulp.task('compressHtml', () => {
|
||||||
|
// TODO 使用gulp-htmlmin插件压缩html
|
||||||
|
})
|
||||||
|
|
||||||
|
// 同步图片到对象存储仓库
|
||||||
|
gulp.task('syncImages', () => {
|
||||||
|
//TODO 直接调用之前写的同步文件的代码
|
||||||
|
})
|
||||||
|
|
||||||
|
gulp.task('deploy', () => {
|
||||||
|
//TODO 递归拷贝public目录中的所有文件到站点根目录
|
||||||
|
})
|
||||||
|
|
||||||
|
// 默认任务
|
||||||
|
gulp.task('default',
|
||||||
|
gulp.series('generate', 'compressHtml', 'syncImages', 'deploy') // 串行执行任务
|
||||||
|
)
|
||||||
|
```
|
||||||
|
1. **gulp.task** 用于定义一个任务, 第一个参数是任务的名称, 第二个参数是任务要执行的函数
|
||||||
|
从4.0版本开始, 这个函数必须返回Promise对象, 让gulp来监测该任务是否执行完毕
|
||||||
|
应该是有利于更优化串行任务的执行过程
|
||||||
|
2. `default`就是在直接执行`gulp`的时候会执行的任务
|
||||||
|
当然也可以执行`gulp 任务名称`用来指定执行某个任务
|
||||||
|
3. **gulp.series**用来定义串行的任务, 也就是把参数里面这几个任务作为子任务, 并按照串行的方式执行
|
||||||
|
如果不使用它, 而是直接写
|
||||||
|
```javascript
|
||||||
|
gulp.task('default', ['generate', 'compressHtml', 'syncImages', 'deploy'])
|
||||||
|
```
|
||||||
|
任务这几个子任务就会以并行的方式执行, 但是在这里因为有执行的顺序要求
|
||||||
|
比如必须在generate完成之后再执行html的压缩, 所以选择串行方式
|
||||||
|
这个api也是gulp4.0新增的
|
||||||
|
以往只能定义任务的完成依赖, 比如在定义B任务必须在A任务完成后执行
|
||||||
|
```javascript
|
||||||
|
gulp.task('B', ['A'], ()=>{/* do something */})
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 添加一些细节
|
||||||
|
```javascript
|
||||||
|
// gulpfile.js
|
||||||
|
|
||||||
|
const gulp = require('gulp'),
|
||||||
|
htmlmin = require('gulp-htmlmin'), //html压缩组件
|
||||||
|
htmlclean = require('gulp-htmlclean'), //html清理组件
|
||||||
|
plumber = require('gulp-plumber'), //容错组件(发生错误不跳出任务,并报出错误内容)
|
||||||
|
Hexo = require('hexo')
|
||||||
|
|
||||||
|
// 程序执行的传参
|
||||||
|
const argv = require('optimist')
|
||||||
|
.demand(['accessKey', 'accessSecret', 'deployPath'])
|
||||||
|
.describe('accessKey', '网易云对象存储key')
|
||||||
|
.describe('accessSecret', '网易云对象存储secret')
|
||||||
|
.describe('deployPath', '静态化后发布的目录')
|
||||||
|
.argv
|
||||||
|
|
||||||
|
const hexo = new Hexo(process.cwd(), {})
|
||||||
|
|
||||||
|
// 创建静态页面 (等同 hexo generate)
|
||||||
|
gulp.task('generate', async function() {
|
||||||
|
try {
|
||||||
|
await hexo.init()
|
||||||
|
await hexo.call('clean')
|
||||||
|
await hexo.call('generate', { watch: false })
|
||||||
|
return hexo.exit()
|
||||||
|
} catch (err) {
|
||||||
|
return hexo.exit(err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// 压缩public目录下的html文件
|
||||||
|
gulp.task('compressHtml', () => {
|
||||||
|
const cleanOptions = {
|
||||||
|
protect: /<\!--%fooTemplate\b.*?%-->/g, //忽略处理
|
||||||
|
unprotect: /<script [^>]*\btype="text\/x-handlebars-template"[\s\S]+?<\/script>/ig //特殊处理
|
||||||
|
}
|
||||||
|
const minOption = {
|
||||||
|
collapseWhitespace: true, //压缩HTML
|
||||||
|
collapseBooleanAttributes: true, //省略布尔属性的值 <input checked="true"/> ==> <input />
|
||||||
|
removeEmptyAttributes: true, //删除所有空属性 <input id="" /> ==> <input />
|
||||||
|
removeScriptTypeAttributes: true, //删除<script>的type="text/javascript"
|
||||||
|
removeStyleLinkTypeAttributes: true,//删除<style>和<link>的type="text/css"
|
||||||
|
removeComments: true, //清除HTML注释
|
||||||
|
minifyJS: true, //压缩页面JS
|
||||||
|
minifyCSS: true, //压缩页面CSS
|
||||||
|
minifyURLs: true //替换页面URL
|
||||||
|
}
|
||||||
|
return gulp.src('./public/**/*.html')
|
||||||
|
.pipe(plumber())
|
||||||
|
.pipe(htmlclean(cleanOptions))
|
||||||
|
.pipe(htmlmin(minOption))
|
||||||
|
.pipe(gulp.dest('./public'))
|
||||||
|
})
|
||||||
|
|
||||||
|
// 同步图片到对象存储仓库
|
||||||
|
gulp.task('syncImages', () => {
|
||||||
|
const listImages = require('./deploy_utils/list_images')
|
||||||
|
// 当前本地存在的所有图片
|
||||||
|
const imagesList = listImages(`${process.cwd()}/source/`, 'images/')
|
||||||
|
const ImageSynchronizer = require('./deploy_utils/image_synchronize')
|
||||||
|
const nosSetting = {
|
||||||
|
defaultBucket: 'blog-cdn',
|
||||||
|
endpoint: 'http://nos-eastchina1.126.net',
|
||||||
|
accessKey: argv.accessKey,
|
||||||
|
accessSecret: argv.accessSecret
|
||||||
|
}
|
||||||
|
const imageSynchronizer = new ImageSynchronizer(nosSetting, imagesList, `${process.cwd()}/source/`)
|
||||||
|
return imageSynchronizer.synchronize('images/')
|
||||||
|
})
|
||||||
|
|
||||||
|
gulp.task('deploy', () => {
|
||||||
|
const deploy = require('./deploy_utils/deploy')
|
||||||
|
return deploy.exec('./public', argv.deployPath, false)
|
||||||
|
})
|
||||||
|
|
||||||
|
// 默认任务
|
||||||
|
gulp.task('default',
|
||||||
|
gulp.series('generate', 'compressHtml', 'syncImages', 'deploy') // 串行执行任务
|
||||||
|
)
|
||||||
|
```
|
||||||
|
1. `syncImages`里面相关的东西可以看这篇 [博客图片迁移记](https://www.colorfulsweet.site/linux/%E5%8D%9A%E5%AE%A2%E5%9B%BE%E7%89%87%E8%BF%81%E7%A7%BB%E8%AE%B0/)
|
||||||
|
大体上都一致, 之后又简单封装了一下, 这都不重要
|
||||||
|
2. `accessKey, accessSecret, deployPath`这三个参数分别在运行时传入
|
||||||
|
前两个是网易云对象存储的访问token, deployPath用来指定页面发布的目录, 在`deploy`当中拷贝到该位置
|
||||||
|
3. `deploy`里面写了递归删除目录与递归拷贝目录的函数
|
||||||
|
```javascript
|
||||||
|
// deploy.js
|
||||||
|
|
||||||
|
const fs = require('fs')
|
||||||
|
const path = require('path')
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
/**
|
||||||
|
* 发布静态化的站点
|
||||||
|
* @param {String} source 源位置
|
||||||
|
* @param {String} target 目标位置
|
||||||
|
* @param {Boolean} copyRoot 是否拷贝根目录
|
||||||
|
*/
|
||||||
|
async exec(source, target, copyRoot) {
|
||||||
|
await new Promise((resolve, reject) => {
|
||||||
|
console.log(`删除${target}目录中的文件`)
|
||||||
|
this._deleteFolderRecursive(target, true)
|
||||||
|
resolve()
|
||||||
|
})
|
||||||
|
console.log(`拷贝${source}所有文件 -> ${target}`)
|
||||||
|
this._copyFolderRecursive(source, target, copyRoot)
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 递归删除目录以及子目录中的所有文件
|
||||||
|
* @param {String} curPath 要递归删除的目录
|
||||||
|
* @param {Boolean} retainRoot 是否保留根目录不删除
|
||||||
|
*/
|
||||||
|
_deleteFolderRecursive(curPath, retainRoot) {
|
||||||
|
fs.readdirSync(curPath).forEach(file => {
|
||||||
|
var nextPath = path.resolve(curPath, file)
|
||||||
|
if(fs.statSync(nextPath).isDirectory()) { // recurse
|
||||||
|
this._deleteFolderRecursive(nextPath)
|
||||||
|
} else {
|
||||||
|
fs.unlinkSync(nextPath)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if(!retainRoot) { // 根目录保留
|
||||||
|
fs.rmdirSync(curPath)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 递归拷贝目录
|
||||||
|
* @param {String} source 源位置
|
||||||
|
* @param {String} target 目标位置
|
||||||
|
*/
|
||||||
|
_copyFolderRecursive(source, target) {
|
||||||
|
let files = fs.readdirSync(source); //同步读取当前目录
|
||||||
|
files.forEach(file => {
|
||||||
|
var _src = path.resolve(source, file)
|
||||||
|
var _target = path.resolve(target, file)
|
||||||
|
fs.stat(_src,(err,stats) => { //stats 该对象 包含文件属性
|
||||||
|
if (err) throw err
|
||||||
|
if (stats.isFile()) { //如果是个文件则拷贝
|
||||||
|
let readable = fs.createReadStream(_src) //创建读取流
|
||||||
|
let writable = fs.createWriteStream(_target) //创建写入流
|
||||||
|
readable.pipe(writable);
|
||||||
|
} else if (stats.isDirectory()) { //是目录则 递归
|
||||||
|
this._checkDirectory(_src, _target, this._copyFolderRecursive)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 校验目标目录是否存在
|
||||||
|
* @param {String} src 源目录
|
||||||
|
* @param {String} target 目标目录
|
||||||
|
* @param {Function} callback 回调函数
|
||||||
|
*/
|
||||||
|
_checkDirectory (src,target,callback) {
|
||||||
|
fs.access(target, fs.constants.F_OK, err => {
|
||||||
|
if (err) {
|
||||||
|
fs.mkdirSync(target)
|
||||||
|
}
|
||||||
|
callback.call(this, src, target)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 持续集成
|
||||||
|
在**package.json**的scripts里面添加 `"build": "gulp"` 之后, 就可以配置持续集成的脚本了
|
||||||
|
现在只需要一行了
|
||||||
|
```bash
|
||||||
|
npm run build -- --accessKey xxx --accessSecret xxx --deployPath /path/to/deploy
|
||||||
|
```
|
||||||
|
jenkins输出日志
|
||||||
|

|
||||||
BIN
source/images/前端杂烩/jenkins输出日志.png
Normal file
BIN
source/images/前端杂烩/jenkins输出日志.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 195 KiB |
@ -19,7 +19,7 @@ $fontEn: "Helvetica Neue", Helvetica, Roboto, "Droid San
|
|||||||
// 背景色,文本色,边框色,链接色
|
// 背景色,文本色,边框色,链接色
|
||||||
//-----------------------------------------------------
|
//-----------------------------------------------------
|
||||||
$colorText: #333 !default;
|
$colorText: #333 !default;
|
||||||
$colorBg: #fff !default;
|
$colorBg: #f0eae3 !default;
|
||||||
$colorBorder: #dbdbdb !default;
|
$colorBorder: #dbdbdb !default;
|
||||||
$colorLink: #08c !default;
|
$colorLink: #08c !default;
|
||||||
$colorPlaceholder: #999 !default; // input placeholder color
|
$colorPlaceholder: #999 !default; // input placeholder color
|
||||||
|
|||||||
@ -38,7 +38,7 @@ html, body, #container {
|
|||||||
position:absolute;
|
position:absolute;
|
||||||
right:0;
|
right:0;
|
||||||
min-height:100%;
|
min-height:100%;
|
||||||
background:#eaeaea;
|
background:#f5dfc6;
|
||||||
left: 300px;
|
left: 300px;
|
||||||
width: auto;
|
width: auto;
|
||||||
@extend %trans;
|
@extend %trans;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user