本文最后更新于:2023年3月19日 晚上
                
              
            
            
              本文转自:https://www.jianshu.com/p/1a255e740710、https://juejin.im/post/6844903870456414216、https://segmentfault.com/a/1190000019650765
1. Gulp
gulp 是基于 Nodejs 的自动任务运行器,能自动化的完成 javascript/coffee/sass/less/html/image/css 等文件的的测试、检查、合并、压缩、格式化、浏览器自动刷新、部署文件生成,并监听文件在改动后重复指定的这些步骤。
通俗来讲,gulp 就是一个处理项目文件的工具,通过 gulp 建立一些任务,当我们对相应文件进行修改之后,会自动触发这些任务,自动的对文件进行了处理。不用我们手动的、反复的去处理这些文件,大大提高了我们的工作效率。
举个栗子:
现在已经开始用 less 来写样式(less 的优点很多,写起来要比 css 快很多,在此不多说,盆友们可以上网了解 less),在 html 使用这些样式,需要用一些工具将.less 文件转换为.css 文件,如果用 Sublime 敲代码的盆友可能知道它有插件自动生成 css,但是.less 和生成的.css 文件在同一目录下。

目录.png
这只是文件比较少的情况,如果文件比较多呢?是不是也是一件很头疼的事情…
下面,上代码带你用 gulp 解决令人头疼的问题 ^ _ ^
前提我们已经创建好一个 nodejs 项目,这里我们安装两个插件: gulp 和 gulp-less(编译 less 文件)
npm install gulp --save-dev
npm install gulp-less --save-dev
新建 gulpfile.js 文件
1 2 3 4 5 6 7 8 9 10
   | // 说明:gulpfile.js是gulp项目的配置文件,放项目根目录即可。 // 导入工具包 var gulp = require('gulp'),     less = require('gulp-less'); // 定义一个testLess任务(自定义任务名称) gulp.task('testLess', function () {     gulp.src('public/stylesheets/style.less') //该任务针对的文件         .pipe(less()) //该任务调用的模块         .pipe(gulp.dest('public/css')); //将会在public/css下生成style.css });
 
  | 
 
接下来,我们只需要在命令行输入gulp testLess我们就可以在 public/css 下看到生成的 style.css 文件了
but 这显然是我们手动来生成的,我们需要的是让它自动生成,那好吧,现在我们需要一个东西能够来监听 less 文件的修改,然后自动去执行任务
1 2 3
   | gulp.task('testWatch', function () {     gulp.watch('public/stylesheets/*.less', ['testLess']);  });
 
  | 
 
好了,现在我们运行gulp testWatch当修改了 less 文件保存,会看到 css 文件也跟着变了^ _ ^
补充一点,我们在一个项目里使用 gulp 的时候,我们想启动项目,就自动启动了 testWatch,而不是启动项目之后,我们还要手动启动 testWatch,那么,加上下面代码:
1
   | gulp.task('default',['testWatch']); // 指定gulp默认启动任务
 
  | 
 
2. Grunt
Grunt 基于 Node.js ,用 JS 开发,这样就可以借助 Node.js 实现跨系统跨平台的桌面端的操作,例如文件操作等等。此外,Grunt 以及它的插件们,都作为一个 包 ,可以用 NPM 安装进行管理。
Grunt 依赖 Node.js 所以在安装之前确保你安装了 Node.js。然后开始安装 Grunt。
Grunt 可以帮助我们减少很多的工作量,比如:检查每个 JS 文件语法、合并两个 JS 文件、将合并后的 JS 文件压缩、将 SCSS 文件编译等,包括我们上面提到的试用 gulp 将.less 文件转换为.css 文件,grunt 也是可以实现的,下面我们用 grunt 实现 gulp 的转换 less 的功能:
和 gulp 一样,首先我们先安装 grunt 以及 grunt-contrib-less
npm install grunt --save-dev
npm install grunt-contrib-less --save-dev
新建 Gruntfile.js 文件
使用 grunt,主要有三块代码:任务配置代码、插件加载代码、任务注册代码。
任务配置代码就是调用插件配置一下要执行的任务和实现的功能,插件加载代码就是把需要用到的插件加载进来,任务注册代码就是注册一个 task,里面包含刚在前面编写的任务配置代码。
需要注意的是,grunt 的配置代码放到
1 2 3
   | module.exports = function(grunt) 
 
 
 
  | 
 
里面,没有为什么…
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
   | // 1. 任务配置代码 grunt.initConfig({     pkg: grunt.file.readJSON('package.json'),     //less插件配置     less: {         main: {         options: {             compress: false,             yuicompress: false         },         files: {             './public/css/global.css': './public/less/*.less'         }     }     } }); // pkg 功能是读取 package.json 文件,并把里面的信息获取出来,方便在后面任务中应用 // 2. 插件加载代码 grunt.loadNpmTasks('grunt-contrib-less'); // 3. 任务注册代码 grunt.registerTask('lessjs', ['less']);
 
  | 
 
到这一步,我们已经做好 grunt 配置文件了,控制台输入grunt lessjs即可实现同 gulp 一样的效果。
同样的,这一样使我们手动生成的,grunt 能像 gulp 一样自动为我们生成吗?答案是肯定的,grunt 同样也有 watch。
首先安装插件 grunt-contrib-watch
npm install grunt-contrib-watch --save-dev
在任务配置代码添加一个 watch 任务:
1 2 3 4 5 6
   | watch: {     lesses: {             files: ['./public/less/*.less'],         tasks: ['less']     } }
 
  | 
 
同样需要加载插件代码,任务注册代码:
1 2
   | grunt.loadNpmTasks('grunt-contrib-watch'); grunt.registerTask('default', ['less', 'watch']);
 
  | 
 
3. grunt 与 gulp 区别
上面的学习,我们知道 grunt 和 gulp 能实现同样的功能,那么它们有什么区别?分别在什么场景下使用呢?
在我看来,其实 grunt 和 gulp 两个东西的功能是一样的,只不过是任务配置 JS 的语法不同,Gulp 配置文件的写法更加通俗易懂,上手更快。但是 Gulp 的插件感觉不如 Grunt,只能满足基本的工作需要;而 Grunt 官方提供了一些常见的插件,满足大部分日常工作,而且可靠值得信赖,而 Gulp 好像没有太多官方出品,各种插件不太规范。
至于在什么场景下使用哪个?这个看个人需要吧,grunt 远远不止上面写的那么简单,如果 gulp 能满足平时工作需要,可以使用 gulp。
总之,用网友的话说,Grunt 和 Gulp 就像 iPhone 与 Android 一样,一个质量高学习难一点,一个学起来简单但是有点那个,你懂得。
什么是 gulp?
gulp 文档上面有这么一句话
 ,也就是说 gulp 是一个自动化构建工具; gulp 的一些功能如下(包括但不限于):

gulp 或 grunt 和 webpack 的区别
其实 Webpack 和另外两个并没有太多的可比性
Gulp/Grunt 是一种能够优化前端的开发流程的工具,而 WebPack 是一种模块化的解决方案,不过 Webpack 的优点使得 Webpack 在很多场景下可以替代 Gulp/Grunt 类的工具。
 
Grunt 和 Gulp 的工作方式是:在一个配置文件中,指明对某些文件进行类似编译,组合,压缩等任务的具体步骤,工具之后可以自动替你完成这些任务。

 
Webpack 的工作方式是:把你的项目当做一个整体,通过一个给定的主文件(如:index.js),Webpack 将从这个文件开始找到你的项目的所有依赖文件,使用 loaders 处理它们,最后打包为一个(或多个)浏览器可识别的 JavaScript 文件。
上述内容转自@zhangwang 的入门 Webpack,看这篇就够了
 
gulp 起步
傻瓜式起步照搬官网文档 1.安装
1 2 3 4 5 6 7
   |  $ npm install -g gulp 或者 $ npm install --global gulp
  $ npm install --save-dev gulp 复制代码
 
  | 
 
2.在项目根目录下创建一个名为 gulpfile.js 的文件:
1 2 3 4 5
   | var gulp = require('gulp'); gulp.task('default', function() {    }); 复制代码
 
  | 
 
3.运行 gulp:
默认的名为 default 的任务(task)将会被运行,在这里,这个任务并未做任何事情。 具体详情可以查看gulpjs.com 文档
项目搭建
新建一个项目 gulp-test 环境:
1 2 3
   | $ node -v // v9.1.0 $ npm -v // 6.5.0 复制代码
 
  | 
 
1.新建文件以下文件如下
1 2 3 4 5 6 7 8
   | gulp-test/           css/                index.scss            js/                helloworld.js            index.html            gulpfile.js 复制代码
 
  | 
 
其中 gulpfile.js 是我们 gulp 的配置文件,启动 gulp 默认会找个这个文件并执行; 2.接下来安装依赖
一直按回车 Enter 初始化 package.json 文件(小技巧: npm iniy -y 可以免去繁琐的 enter 步骤) 此时我们的目录结构是这样了
1 2 3 4 5 6 7 8 9
   | gulp-test/           css/                index.scss            js/                helloworld.js            index.html            gulpfile.js            package.json 复制代码
 
  | 
 
安装依赖
1 2 3 4 5 6 7 8 9 10 11 12 13
   | npm i --save-dev gulp         npm i --save-dev gulp-uglify  npm i --save-dev gulp-concat  npm i --save-dev gulp-jshint  npm i --save-dev gulp-rename  npm i --save-dev gulp-sass  npm i --save-dev gulp-minify-css  npm i --save-dev del       
  npm i --save-dev gulp-connect        npm i --save-dev  browser-sync        npm i --save-dev gulp-livereload        复制代码
 
  | 
 
这里页面实时刷新只讲这个gulp-connect ,其他详情可以参照Browsersync和文章gulp-livereload
安装完依赖后配置 gulpfile.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
   | // 定义依赖项和插件 const gulp=require('gulp'); const  uglify=require('gulp-uglify'); //js压缩 const  concat=require('gulp-concat'); //文件合并 const jshint = require('gulp-jshint'); //js语法检测 const rename = require('gulp-rename'); // 重命名 const sass = require('gulp-sass'); // 编译scss const  minifycss = require('gulp-minify-css'); // 压缩css // const livereload = require('gulp-livereload'); // 自动刷新页面 const  del = require('del'); //文件删除 const connect = require('gulp-connect'); // 自动刷新页面 gulp.task('server', function() {   connect.server({     port: 8080, //指定端口号,在浏览器中输入localhost:8080就可以直接访问生成的html页面     root: './', //指定html文件起始的根目录     livereload: true //启动实时刷新功能(配合上边的connect.reload()方法同步使用)   }); }); // 定义名为 "my-task" 的任务压缩js gulp.task('my-task-js', function(){   gulp.src('./js/*.js')     .pipe(jshint())     .pipe(uglify())     .pipe(concat('all.js'))     .pipe(rename({suffix: '.min'}))     .pipe(gulp.dest('./dist/js'))     .pipe(connect.reload()) }); // 定义名为 "my-task-css" 的任务编译scss压缩css gulp.task('my-task-css', function() {   gulp.src('./css/*.scss')     .pipe(sass().on('error', sass.logError))     .pipe(concat('all.css'))     .pipe(rename({suffix: '.min'}))     .pipe(minifycss())     .pipe(connect.reload())     .pipe(gulp.dest('./dist/css')) }); gulp.task('html', function(){   gulp.src('*.html')     .pipe(gulp.dest('dist/html'))     .pipe(connect.reload()) }) //执行压缩前,先删除以前压缩的文件 gulp.task('clean', function() {   return del(['./dist/css/all.css', './dist/css/all.min.css', './dist/all.js','./dist/all.min.js', './dist/html']) }); // 定义默认任务 gulp.task('default',['clean'],function() {   gulp.start('my-task-js', 'my-task-css', 'watch', 'server' ); }); // 任务监听 gulp.task('watch', function() {   // Watch.js files   gulp.watch('./js/*.js', ['my-task-js']);   // Watch .scss files   gulp.watch('./css/*.scss', ['my-task-css']);   // Watch .html files   gulp.watch('./*.html', ['html']);   // Watch any files in dist/, reload on change   // gulp.watch(['dist/!**']).on('change', livereload.changed); }); 复制代码
 
  | 
 
大概讲解一下 gulpfile.js:
1 2 3 4 5 6 7 8 9 10 11 12 13
   | // ... // 定义名为 "my-task" 的任务压缩js gulp.task('my-task-js', function(){   gulp.src('./js/*.js')     .pipe(jshint()) //js检测     .pipe(uglify()) //js压缩     .pipe(concat('all.js')) //合并为all.js     .pipe(rename({suffix: '.min'})) // 重命名为all.mim.js     .pipe(gulp.dest('./dist/js')) //输出到/dist/js目录     .pipe(connect.reload()) // 更新页面 }); // ... 复制代码
 
  | 
 
gulp.task是 gulp 的 api 定义一个使用 Orchestrator 实现的任务(task) 如上我们定义了my-task-js,my-task-css,html,clean,default,watch,server等任务,其中:
my-task-js 是将 符合所提供的匹配模式的 js 进行检测(gulp-jshint)、压缩(gulp-uglify)、合并(gulp-concat)、重命名(gulp-rename)、输出(gulp.dest)到/dist/js 目录下;
 
my-task-css 是将 符合所提供的匹配模式的 sass 进行编译(gulp-sass)、压缩(gulp-uglify)、合并(gulp-concat)、重命名(gulp-rename)、输出(gulp.dest)到/dist/css 目录下;
 
html 是将 符合所提供的匹配模式的 html 进行监听,如果有变化则 connect.reload()
 
clean 是如果任务重新启动时 删除旧文件;
 
default gulp 默认启动的任务
 
watch gulp 的 api 监视文件,并且可以在文件发生改动时候做一些事情。它总会返回一个 EventEmitter 来发射(emit) change 事件。
 
server 依赖 gulp-connect 启动一个服务器
 
1 2 3 4 5 6 7 8
   | gulp.task('server', function() {   connect.server({     port: 8080, //指定端口号,在浏览器中输入localhost:8080就可以直接访问生成的html页面     root: './', //指定html文件起始的根目录     livereload: true //启动实时刷新功能(配合上边的connect.reload()方法同步使用)   }); }); 复制代码
 
  | 
 
配置完 gulpfile.js 之后,我们给 js 和 css 及 html 加点东西:
首先 js/helloworld.js
1 2 3
   |  console.log('hello world') 复制代码
 
  | 
 
css/index.scss
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
   | 
  $fontColor:  #red; $backColor: aqua;
  div {   p {     font-weight: bold;     font-size: 20px;     color: $fontColor;   } } div{   background: $backColor; } 复制代码
 
  | 
 
index.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
   | <!DOCTYPE html> <html lang="en"> <head> 	<meta charset="UTF-8"> 	<title>gulp-study</title> 	<link href=/dist/css/all.min.css rel=stylesheet> </head> <body> 	<div id="firstDiv"> 		<p>我是gulp</p> 		<p>hello world</p> 	</div> <p>我是p标签</p> <p>我是p标签</p> </body> <script src="/dist/js/all.min.js"></script> </html> 复制代码
 
  | 
 
运行 gulp

浏览器效果:

接下来我们修改 helloworld.js 来看看是否能实时刷新 修改如下:
1 2 3 4 5
   |  console.log('hello world'); let firstDiv =  document.getElementById('firstDiv') console.log(firstDiv) 复制代码
 
  | 
 
按保存之后,终端给我们报了一个错:

查看 js 发现我们用了 es6 语法的声明语句
 但当前 gulp 无法处理 es6 语法,有问题解决问题,es6=>es5
解决方案: 安装 gulp-babel babel-core babel-preset-es2015
1 2
   | npm i  --save-dev  gulp-babel babel-core babel-preset-es2015 复制代码
 
  | 
 
gulpfile.js 修改如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
   | // ... const babel = require('gulp-babel'); // ... // 定义名为 "my-task" 的任务压缩js gulp.task('my-task-js', function(){   gulp.src('./js/*.js')     .pipe(babel())     .pipe(jshint())     .pipe(uglify())     .pipe(concat('all.js'))     .pipe(rename({suffix: '.min'}))     .pipe(gulp.dest('./dist/js'))     .pipe(connect.reload()) }); // ... 复制代码
 
  | 
 
运行
依然报上面的错;找了一些原因发现,虽然安装了相关依赖,却没有配置.babelrc 文件,即 babel 还没转化 es6
根目录添加.babelrc 文件
1 2 3 4
   | { 	"presets": ["es2015"] } 复制代码
 
  | 
 
重新运行:

查看 dist 下的 js 文件

改变 helloworld.js 检查页面是否刷新
1 2 3 4 5 6
   |  console.log('hello world'); let firstDiv =  document.getElementById('firstDiv') console.log(firstDiv) firstDiv.style.backgroundColor = 'yellow'; 复制代码
 
  | 
 
保存,页面的天空蓝换成你们喜欢的 yellow 颜色

修改 index.scss 查看是否会刷新页面
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
   | 
  $fontColor:  #red; $backColor: aqua;
  div {   p {     font-weight: bold;     font-size: 20px;     color: $fontColor;   } } div{   background: $backColor;   width: 400px;   height: 400px;   margin: 0 auto; } 复制代码
 
  | 
 

最后修改 index.html 查看是否会刷新页面
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
   | <!DOCTYPE html> <html lang="en"> <head> 	<meta charset="UTF-8"> 	<title>gulp-study</title> 	<link href=/dist/css/all.min.css rel=stylesheet> </head> <body> 	<div id="firstDiv"> 		<p>我是gulp</p> 		<p>hello world</p> 	</div> <div> 	<p>我是真的皮</p> </div> </body> <script src="/dist/js/all.min.js"></script> </html> 复制代码
 
  | 
 

随着前端发展如日冲天,前端项目也越来越复杂,得益于 Nodejs 的发展,前端模块化、组件化、工程化也大势所趋。这些年 Grunt、Gulp 到 Webpack 随着工程化的发展都大行其道。
前端工程化的早期,主要是解决重复任务的问题。Grunt、Gulp 就是其中代表。比如: 压缩、编译 less、sass、地址添加 hash、替换等。
Grunt 官网中就说:
对于需要反复重复的任务,例如压缩(minification)、编译、单元测试、linting 等,完成大部分无聊的工作。
而如今的 Webpack 更像一套前端工程化解决方案。利用强大插件机制,解决前端静态资源依赖管理的问题。
Webpack 作者 Tobias 回复与 Grunt Gulp NPM 脚本的比较
Tobias: NPM 脚本对我而言足矣。实际上,说 webpack 是 Grunt/Gulp 的替代器并不完全准确。Grunt 和 Gulp 以及 NPM 脚本都是任务执行程序。
Webpack 是**模块打包程序**。这两类程序的目标不一样。但 webpack 简化了必须“过度使用”Grunt 和 Gulp 和 NPM 脚本才能实现的 Web 开发任务也是事实。NPM 脚本才是 Grunt 和 Gulp 的替代品。
不过,除了纯粹的构建之外,任务运行程序也有存在的理由,比如部署、代码检查、版本管理,等等。
Webpack 与 Grunt、Gulp 运行机制
1 2 3 4 5 6
   | # grunt gulp 思路 【遍历源文件】->【匹配规则】->【打包】 做不到按需加载,对打包的资源,是否用到,打包过程不关心。 # webpack 【入口】->【模块依赖加载】->【依赖分析】->【打包】 在加载、分析、打包的过程中,可以针对性的做一些解决方案。比如:code split(拆分公共代码)
 
  | 
 
Grunt 与 Gulp 性能比较
Grunt: 每个任务处理完成后存放在本地磁盘.tmp 目录中,有本地磁盘的 I/O 操作,会导致打包速度比较慢。
**Gulp: **gulp 与 grunt 都是按任务执行,gulp 有一个文件流的概念。每一步构建的结果并不会存在本地磁盘,而是保存在内存中,下一个步骤是可以使用上一个步骤的内存,大大增加了打包的速度。