0.参考说明 本文参考自以下文章 1.gulp简介 gulp将开发流程中让人痛苦或耗时的任务自动化,从而减少你所浪费的时间、创造更大价值。
简单来说,gulp就是一个自动化工具,在本文中将体现以下功能:
压缩静态资源(js/css/html/font
) 监控自定义js/css
的改变,合并成一个(这么做有一定的弊端!) 扩展:引入Stylus
,编译并合并 2.gulp安装 安装gulp命令行工具 1 npm install --global gulp-cli
创建项目目录并进入 1 2 3 mkdir jinyu_hexo_gulp cd jinyu_hexo_gulp
提示:
可以在Hexo根目录
下创建,或完全新建一个项目 之后将使用[gulp_root]
代指本项目的根目录 此处设定gulp
项目(jinyu_hexo_gulp
)和Hexo
项目(jinyu_hexo_blog
)是并列关系:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 Project ├── jinyu_hexo_blog │ ├── ... │ ├── public │ ├── scaffolds │ ├── source │ │ ├── ... │ │ ├── js //用于放置自定义js整合文件 │ │ ├── css //用于放置自定义css整合文件 │ │ └── custom //未处理的自定义静态资源 │ │ ├── fonts │ │ ├── js │ │ ├── css │ │ └── styl │ └── themes │ └── butterfly │ └── ... └── jinyu_hexo_gulp └── ...
在项目目录下创建package.json文件 提示:(一直按回车)
安装gulp,作为开发时依赖项 1 npm install --save-dev gulp
检查gulp版本 确保输出与下面的屏幕截图匹配,否则你可能需要执行本指南中的上述步骤。
创建gulpfile文件 在[gulp_root]
创建文件gulpfile.js
或Gulpfile.js
(请确保名称正确),然后在里面先写一个HelloWorld
试试:
1 2 3 4 5 6 7 function defaultTask (cb ) { console .log ('HelloWorld!' ); cb (); } exports .default = defaultTask
说明:cb:CallBack的缩写,具体请看异步执行
测试 在[gulp_root]
路径下,打开终端输入:
输出结果
3.gulpfile.js解析 创建任务 在gulpfile.js
中,创建函数即可创建一个任务,如上面的HelloWorld
例子:
1 2 3 4 5 6 7 8 function defaultTask (cb ) { console .log ('HelloWorld!' ); cb (); } exports .default = defaultTask
然后下面的exports.default = defaultTask
指的是导出了defaultTask
任务,并命名为default
。
被exports.<task_name>
的任务称为public
任务,可以在命令行中使用gulp <task_name>
执行,未导出的任务则是private
任务,不可在命令行中使用gulp <task_name>
来执行。
default
是默认任务名称,所以在命令行中使用gulp <task_name>
时可以省略任务名,只需要输入gulp
,等效于gulp default
。
多个任务 再创建两个测试任务a
、b
,且都导出:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 function defaultTask (cb ) { console .log ('HelloWorld!' ); cb (); } function a (cb ) { console .log ('a' ); cb (); } function b (cb ) { console .log ('b' ); cb (); } exports .default = defaultTaskexports .a = aexports .b = b
此时可以在命令行中使用gulp a b
来执行多个任务,即:可以输入gulp <task_name0> <task_name1> ...
来执行多个任务,若还要执行default
任务,则必须写上,不可省略。
组合任务 gulp
提供了两个强大的组合方法:series()
和parallel()
,允许将多个独立的任务组合为一个更大的操作。这两个方法都可以接受任意数目的任务(task)函数或已经组合的操作。series()
和parallel()
可以互相嵌套至任意深度。
串行series() 如果需要让任务(task)按顺序执行,请使用series()
方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 const { series } = require ('gulp' );function defaultTask (cb ) { console .log ('HelloWorld!' ); cb (); } function a (cb ) { console .log ('a' ); cb (); } function b (cb ) { console .log ('b' ); cb (); } exports .default = defaultTaskexports .c = series (a, b)
此时执行在命令行中执行gulp c
将会顺序执行a
和b
两个任务。
并行parallel() 对于希望以最大并发来运行的任务(tasks),可以使用parallel()
方法将它们组合起来:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 const { parallel } = require ('gulp' );function defaultTask (cb ) { console .log ('HelloWorld!' ); cb (); } function a (cb ) { console .log ('a' ); cb (); } function b (cb ) { console .log ('b' ); cb (); } exports .default = defaultTaskexports .c = parallel (a, b)
此时执行在命令行中执行gulp c
将会并发执行a
和b
两个任务。
结论 使用series()
还是parallel()
要看任务之间是否有依赖关系,比如:
编译stylus为css
的任务和压缩css
任务就有先后关系,需要使用series()
来执行。压缩css
任务和压缩js
任务之间就没有依赖关系,可以使用parallel()
来执行。4.Gulpfile分割 大部分用户起初是将所有业务逻辑都写到一个gulpfile.js
文件中。随着文件的变大,可以将此文件重构为数个独立的文件。 每个任务(task)可以被分割为独立的文件,然后导入(import)到gulpfile.js
文件中并组合。这不仅使事情变得井然有序,而且可以对每个任务(task)进行单独测试,或者根据条件改变组合。
例:在[gulp_root]
下新建文件夹tasks
,新建任务say_hello.js
和say_world.js
,此时的目录格式如下:
1 2 3 4 5 6 7 jinyu_hexo_gulp ├── gulpfile.js ├── package-lock.json ├── package.json └── tasks ├── say_hello.js └── say_world.js
say_hello.js
:
1 2 3 4 5 6 const sayHello = (cb ) => { console .log ("hello" ); cb (); } exports .sayHello = sayHello;
say_world.js
:
1 2 3 4 5 6 const sayWorld = (cb ) => { console .log ("world" ); cb (); } exports .sayWorld = sayWorld;
gulpfile.js
:
1 2 3 4 5 const {series} = require ('gulp' );const {sayHello} = require ('./tasks/say_hello.js' );const {sayWorld} = require ('./tasks/say_world.js' );exports .default = series (sayHello, sayWorld);
这样按文件区分不同的任务,然后在gulpfile.js
中引入的方式,便于任务的管理和分类以及日后的维护。
命令行中执行gulp
的结果:
5.插件 gulp
有很多插件来达成各式各样的功能,如压缩静态资源(js/css/html/font
)、监控文件的变化等。
下文用到的插件列表 插件名 作用 版本 gulp-terser 压缩js ^2.1.0 gulp-clean-css 压缩css ^4.3.0 gulp-htmlclean 压缩html ^2.7.22 gulp-html-minifier-terser 压缩html,可以压缩html中的ES6语法 ^7.1.0 gulp-fontmin 压缩字体 ^0.7.4 gulp-concat 合并静态资源 ^2.6.1 gulp-stylus 编译Stylus文件 ^3.0.0
引入path.js 在[gulp_root]
下新建path.js
,用于定义后面任务需要用到的路径,比如自定义js文件的源路径、压缩合并后的目的路径等:
1 2 3 4 5 6 7 8 9 10 11 12 module .exports = { custom_js : { src : '../jinyu_hexo_blog/source/custom/js/*.js' , concat_name : 'jinyu.js' , dest : '../jinyu_hexo_blog/source/js' }, custom_css : { src : '../jinyu_hexo_blog/source/custom/css/*.css' , concat_name : 'jinyu.css' , dest : '../jinyu_hexo_blog/source/css' } };
合并自定义静态资源并监测 安装插件:
1 npm install --save-dev gulp-concat
在tasks
文件夹新建任务custom_js.js
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 const {src, dest, watch} = require ('gulp' );const {custom_js} = require ('../paths.js' );const concat = require ('gulp-concat' ); const concatJs = ( ) => src ([custom_js.src ]) .pipe (concat (custom_js.concat_name )) .pipe (dest (custom_js.dest )); const watchJs = ( ) => watch (custom_js.src , {ignoreInitial : false }, concatJs); exports .concatJs = concatJs;exports .watchJs = watchJs;
在tasks
文件夹新建任务custom_css.js
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 const {src, dest, watch} = require ('gulp' );const {custom_css} = require ('../paths.js' );const concat = require ('gulp-concat' ); const concatCss = ( ) => src ([custom_css.src ]) .pipe (concat (custom_css.concat_name )) .pipe (dest (custom_css.dest )); const watchCss = ( ) => watch (custom_css.src , {ignoreInitial : false }, concatCss); exports .concatCss = concatCss;exports .watchCss = watchCss;
修改gulpfile.js
:
1 2 3 4 5 6 7 const {parallel, series} = require ('gulp' );const {concatJs, watchJs} = require ('./tasks/custom_js.js' );const {concatCss, watchCss} = require ('./tasks/custom_css.js' );exports .concat = parallel (concatJs, concatCss);exports .watch = parallel (watchJs, watchCss);
gulp concat 在命令行输入gulp concat
,执行效果:
jinyu_hexo_blog/source/custom/js/
下的所有js
文件合并成jinyu.js
,并放到jinyu_hexo_blog/source/js/
下。jinyu_hexo_blog/source/custom/css/
下的所有css
文件合并成jinyu.css
,并放到jinyu_hexo_blog/source/css/
下。修改Hexo的_config.yml jinyu_hexo_blog/source/custom
下存放的是未处理的自定义静态资源文件,在执行hexo g
时,public
里是不需要这些文件的,所以在_config.yml
(不是主题的_config.yml
)中把此文件夹忽略。
1 2 3 4 5 6 include: exclude: ignore: - '**/source/custom'
注意:在部署Hexo
时,命令gulp concat
需要放在hexo cl
和hexo g
之间。
gulp watch 在命令行输入gulp watch
,执行效果:
jinyu_hexo_blog/source/custom/js/
下的任意js
文件在编辑后,会被gulp
监测到,然后执行custom_js.js
中的concatJs
任务:jinyu_hexo_blog/source/custom/js/
下的所有js
文件合并成jinyu.js
,并放到jinyu_hexo_blog/source/js/
下。jinyu_hexo_blog/source/custom/css/
下的任意css
文件在编辑后,会被gulp
监测到,然后执行custom_css.js
中的concatCss
任务:jinyu_hexo_blog/source/custom/css/
下的所有css
文件合并成jinyu.css
,并放到jinyu_hexo_blog/source/css/
下。修改主题的_config.yml 在_config.butterfyl.yml
或_config.yml
(主题的_config.yml
)中找到inject
,然后把合并后的自定义文件引入即可:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 inject: head: - <link rel="stylesheet" media="defer" onload="this.media='all'" href="/css/jinyu.css?v=202301151121"> bottom: - <script async data-pjax src="/js/jinyu.js?v=202301151121"></script>
注意:命令gulp watch
的作用通常是在本地开发时使用,本地hexo s
后,另开一个终端执行gulp watch
。在修改自定义js/css
后,会更新合并后的文件jinyu.js/jinyu.css
。
编译、合并自定义Stylus并监测 若对于自定义css
依旧想使用原生的css
来实现,可跳过这一节。或想要使用其他css预处理器
,可以参考此节。
关于Stylus的介绍,请查看
安装插件:
1 npm install --save-dev gulp-stylus
在paths.js
中添加关于stylus
的数据:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 module .exports = { custom_js : { src : '../jinyu_hexo_blog/source/custom/js/*.js' , concat_name : 'jinyu.js' , dest : '../jinyu_hexo_blog/source/js' }, custom_stylus : { src : '../jinyu_hexo_blog/source/custom/styl/*.styl' , concat_name : 'jinyu.css' , dest : '../jinyu_hexo_blog/source/css' }, };
在tasks
文件夹新建任务custom_stylus.js
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 const {src, dest, watch} = require ('gulp' );const {custom_stylus} = require ('../paths.js' );const concat = require ('gulp-concat' ); const stylus = require ("gulp-stylus" ); const concatStylus = ( ) => src ([custom_stylus.src ]) .pipe (stylus ()) .pipe (concat (custom_stylus.concat_name )) .pipe (dest (custom_stylus.dest )); const watchStylus = ( ) => watch (custom_stylus.src , {ignoreInitial : false }, concatStylus); exports .concatStylus = concatStylus;exports .watchStylus = watchStylus;
修改gulpfile.js
:
1 2 3 4 5 6 7 8 9 const {parallel, series} = require ('gulp' );const {concatJs, watchJs} = require ('./tasks/custom_js.js' );const {concatStylus, watchStylus} = require ('./tasks/custom_stylus.js' );exports .concat = parallel (concatJs, concatStylus);exports .watch = parallel (watchJs, watchStylus);
gulp concat
和gulp watch
的效果没变,监视css
变成了监视styl
文件的修改;已修改的Hexo
的_config.yml
和主题的_config.butterfly.yml
也不需要改动。
压缩静态资源 安装以下插件:
1 npm install --save-dev gulp-terser gulp-clean-css gulp-htmlclean gulp-html-minifier-terser gulp-fontmin
在paths.js
中添加关于minify
的数据:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 module .exports = { custom_js : { src : '../jinyu_hexo_blog/source/custom/js/*.js' , concat_name : 'jinyu.js' , dest : '../jinyu_hexo_blog/source/js' }, custom_stylus : { src : '../jinyu_hexo_blog/source/custom/styl/*.styl' , concat_name : 'jinyu.css' , dest : '../jinyu_hexo_blog/source/css' }, minify : { js : { src : [ '../jinyu_hexo_blog/public/**/*.js' , '!../jinyu_hexo_blog/public/**/*.min.js' ], dest : '../jinyu_hexo_blog/public' }, css : { src : '../jinyu_hexo_blog/public/**/*.css' , dest : '../jinyu_hexo_blog/public' }, html : { src : '../jinyu_hexo_blog/public/**/*.html' , dest : '../jinyu_hexo_blog/public' }, font : { src : '../jinyu_hexo_blog/public/fonts/*.ttf' , html : '../jinyu_hexo_blog/public/**/*.html' , dest : '../jinyu_hexo_blog/public/fonts_dest/' }, } };
在tasks
文件夹新建任务minify.js
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 const {src, dest, parallel} = require ('gulp' );const {minify} = require ('../paths.js' );const terser = require ('gulp-terser' ); const cleanCSS = require ('gulp-clean-css' ); const htmlClean = require ('gulp-htmlclean' ); const htmlMinifierTerser = require ('gulp-html-minifier-terser' ); const fontMin = require ('gulp-fontmin' ); const minifyJS = ( ) => src (minify.js .src ) .pipe (terser ({keep_fnames : true , mangle : false })) .pipe (dest (minify.js .dest )); const minifyCSS = ( ) => src ([minify.css .src ]) .pipe (cleanCSS ({compatibility : 'ie11' })) .pipe (dest (minify.css .dest )); const minifyHTML = ( ) => src (minify.html .src ) .pipe (htmlClean ()) .pipe (htmlMinifierTerser ({ removeComments : true , collapseWhitespace : true , collapseBooleanAttributes : true , removeEmptyAttributes : true , removeScriptTypeAttributes : true , removeStyleLinkTypeAttributes : true , minifyJS : true , minifyCSS : true , minifyURLs : true })) .pipe (dest (minify.html .dest )); function minifyFontInner (text, cb ) { src (minify.font .src ) .pipe (fontMin ({ text : text })) .pipe (dest (minify.font .dest )) .on ('end' , cb); } const minifyFont = (cb ) => { let buffers = []; src ([minify.font .html ]) .on ('data' , function (file ) { buffers.push (file.contents ); }) .on ('end' , function ( ) { let text = Buffer .concat (buffers).toString ('utf-8' ); minifyFontInner (text, cb); }); } exports .minify = parallel (minifyJS, minifyCSS, minifyHTML, minifyFont);
修改gulpfile.js
:
1 2 3 4 5 6 7 8 9 10 11 const {parallel, series} = require ('gulp' );const {concatJs, watchJs} = require ('./tasks/custom_js.js' );const {concatStylus, watchStylus} = require ('./tasks/custom_stylus.js' );const {minify} = require ('./tasks/minify.js' );exports .concat = parallel (concatJs, concatStylus);exports .watch = parallel (watchJs, watchStylus);exports .minify = minify;
gulp minify 在命令行输入gulp minify
,执行效果: 并行执行minifyJS
, minifyCSS
, minifyHTML
, minifyFont
四个任务,压缩public
下的所有js/css/html
文件;压缩后的字体文件会在public/fonts_dest
生成,在css
中引用时需要注意路径。 例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 @font-face { font-family : 'ResourceHanRoundedCN' ; font-display : swap; font-style : normal; font-weight : normal; src : url ('/fonts_dest/ResourceHanRoundedCN-Bold.eot' ); src : url ('/fonts_dest/ResourceHanRoundedCN-Bold.eot' ) format ('embedded-opentype' ), url ('/fonts_dest/ResourceHanRoundedCN-Bold.woff' ) format ('woff' ), url ('/fonts_dest/ResourceHanRoundedCN-Bold.ttf' ) format ('truetype' ), url ('/fonts_dest/ResourceHanRoundedCN-Bold.svg' ) format ('svg' ); } body { font-family : "ResourceHanRoundedCN" , sans-serif !important ; }
注意:gulp minify
压缩的是public
目录下的文件,所以在执行完hexo g
执行gulp minify
。
6.使用 此处分享一下平常用的管理脚本,来自张洪Heo 《通过alias自定义终端命令实现Hexo博客的高效使用,简化你的终端命令》 的Peach 的评论,并做了一些修改:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 @echo off set blog_home=E:\Project\jinyu_hexo_blog set gulp_home=E:\Project\jinyu_hexo_gulp :begin cd %blog_home% echo 项目路径:%blog_home% echo gulp路径:%gulp_home% echo ==================================== echo 欢迎使用 Hexo 命令助手 请选择命令 echo 本地测试或上传网站时,将自动清理缓存 echo ==================================== echo 1. 本地启动 echo 2. 通过VsCode打开项目 echo 3. 清理缓存 echo 4. 更新追番页数据 echo 5. 新建文章 echo 6. 新建页面 echo 7. 上传网站 echo 8. 访问服务器博客 echo 0. 退出 set /p input="请选择命令并按下回车:" if %input%==1 goto A if %input%==2 goto B if %input%==3 goto C if %input%==4 goto D if %input%==5 goto E if %input%==6 goto F if %input%==7 goto G if %input%==8 goto H if %input%==0 goto Z @REM order: 1. 本地启动 :A cls start cmd.exe /k "@echo off && hexo cl && hexo g && hexo s" start cmd.exe /k "@echo off && cd %gulp_home% && gulp watch" goto begin @REM order: 2. 通过VsCode打开项目 :B cls start cmd.exe /c "@echo off && code %blog_home% && exit" start cmd.exe /c "@echo off && code %gulp_home% && exit" goto begin @REM order: 3. 清理缓存 :C cls start cmd.exe /k "@echo off && hexo cl && echo 已清理缓存 && pause && exit" goto begin @REM order: 4. 更新追番页数据 :D cls start cmd.exe /k "@echo off && hexo bangumi -u && pause && exit" goto begin @REM order: 5. 新建文章 :E set /p newFileName="请输入文章文件名:" cls start cmd.exe /k "hexo n %newFileName% && echo. && echo 已在 source/_posts 目录下生成文件:%newFileName%.md && pause && exit" cls goto begin @REM order: 6. 新建页面 :F set /p newPageName="请输入独立页面文件名:" cls start cmd.exe /k "hexo n page %newPageName% && echo. && echo 已在 source 目录下生成文件夹: %newPageName%,并在文件夹内创建文件: index.md && pause && exit" goto begin @REM order: 7. 上传网站 :G cls start cmd.exe /k "@echo off && hexo cl && cd %gulp_home% && gulp concat && cd %blog_home% && hexo bangumi -u && hexo g && cd %gulp_home% && gulp minify && cd %blog_home% && hexo d && pause && exit" goto begin @REM order: 8. 访问服务器博客 :H cls start https://jinyu.host goto begin @REM order: 0. 退出 :Z exit pause
开发 可以看到,在平常开发时,会启动两个命令窗口,一个执行hexo cl && hexo g && hexo s
,另一个则是使用gulp
进行监测:gulp watch
部署 在部署的时候,顺序如下:hexo cl -> gulp concat -> hexo bangumi -u -> hexo g -> gulp minify -> hexo d
说明:hexo bangumi -u
是更新番剧页面的数据,若没有引入,可以去掉