搁浅被注册了

图样 图森破 、

@搁浅被注册了8 年前

02/29
23:42
Gulp

Gulp 自动化你的前端

“1. 我为什么使用grunt; 2. 我为何放弃grunt转投gulp; 3. 我为何放弃gulp与grunt,转投npm scripts; 4. 我为何放弃前端” —— 司徒正美

前端(段子)界的发展突飞猛进,总感觉随时会跟不上技术潮流(其实我已经被甩开了一条街,so sad

选择在这样一个时机发布一篇 gulp 教程并不是我的初衷,第一次用 gulp 是在一年前,而这篇帖子在草稿箱里躺了一个多月,再不发出来说不定就过时了。

当我在用 gulp 时我用它做什么?

  1. 编译 sass
  2. 合并优化压缩 css
  3. 校验压缩 js
  4. 优化图片
  5. 添加文件指纹(md5)
  6. 组件化头部底部(include html)
  7. 实时自动刷新…

总之,gulp是前端开发过程中对代码进行自动化构建的利器。它不仅能对资源进行优化,而且在开发过程中能够通过配置自动完成很多重复的任务,让我们可以专注于代码,提高工作效率。

然而由于众所周知的原因,国内到 npm 服务器的连接很不稳定,如果你有V了个PN大可不必担心,也可通过设置 npm 代理服务器的方式访问:

// 设置代理
npm config set proxy="http://127.0.0.1:1080"
// 删除代理
npm config delete proxy

推荐一个简单的方案:使用淘宝 npm 镜像 

“这是一个完整 npmjs.org 镜像,你可以用此代替官方版本(只读),同步频率目前为 10分钟 一次以保证尽量与官方服务同步。” —— 淘宝团队点赞

npm config set registry="https://registry.npm.taobao.org"
npm config set disturl https://npm.taobao.org/dist

接下来开始 gulp 教程:

准备工作: 安装 node.js (推荐 TLS 版),并重启系统。

1. 全局安装 gulp

npm install gulp -g

2. 目录结构:

└── src / 源码目录
  ├── build /   .html 组件
  ├── sass /     .scss.sass 文件
  ├── css /       .css 文件
  ├── js /         .js 文件
  └── img / 图片
└── dist / 输出目录
└── package.json
└── gulpfile.js

3. 关于 package.json

可以在项目上使用 npm init 配置,推荐直接新建 package.json 并写入初始内容:

{
  "name": "gulp-build",
  "version": "1.0.0",
  "description": "Gulp.js",
  "private": true
}

对于完整的 package.json (比如别人的开源项目), 只需对整个项目执行 npm install 即可安装 package.json 文件中声明的所有插件模块。

4. 给项目目录安装 gulp

npm install gulp --save-dev

—save-dev 这个参数会将插件信息自动更新到 package.json 里,其中的 devDependencies 属性会随插件依赖的安装卸载而改变。

PS. Windows 7及以上,按住 Shift 再右键,选择在此处打开命令窗口。免去 cd 命令定位目录的烦恼。

5. 给项目目录安装常用的插件

PS.可与上一步同时进行

npm install gulp del gulp-cached gulp-uglify gulp-rename gulp-concat gulp-notify gulp-filter gulp-jshint gulp-ruby-sass gulp-rev-append gulp-cssnano gulp-replace gulp-imagemin browser-sync gulp-font-spider gulp-file-include gulp-autoprefixer --save-dev

插件将在配置文件里介绍,更多用法请参见相应的 GitHub 主页,或者直接戳这里: https://www.npmjs.com/package/

以上两个安装操作将会在项目目录下生成 node_modules 文件夹,相应的插件都在这里。

Windows 用户请注意,此文件夹可能 无法删除 无法复制 无法移动,会出现诸如“包含名称过长且无法放入回收站”,“源文件名长度大于文件系统支持的长度。请尝试将其移动到具有较短路径名称的位置” 等等问题。使用一个简单的方式即可删除,使用 WinRAR “添加到压缩文件”,勾选压缩选项里的 “压缩后删除源文件” ,确定之后即可删除。

6. API

别看我,看它:http://www.gulpjs.com.cn/docs/api/

7. 代码示例

src/build/header.html

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>嘿嘿嘿</title>
<link href="css/m.base.css?rev=@@hash" rel="stylesheet" type="text/css" />
<link href="css/jquery.fullPage.css?rev=@@hash" rel="stylesheet" type="text/css" />
<link href="css/mobile.css?rev=@@hash" rel="stylesheet" type="text/css" />
</head>
<body>

src/build/footer.html

<!– common js –>
<script type="text/javascript" src="js/jquery-2.1.4.min.js"></script>
<script type="text/javascript" src="js/main.js?rev=@@hash"></script>
</body>
</html>

src/index.html

@@include(‘build/header.html’)

<div class="wrap">内容</div>

@@include(‘build/footer.html’)

代码中, ?rev=@@hash  是 gulp-rev-append 插件的指纹标识
@@include('build/header.html') 可以插入 html 文件,还可以配合参数生成独立的头部。

8. 我的 gulpfile.js,配置及说明

/*!
* gulp
* $ npm install gulp gulp-ruby-sass gulp-cached gulp-uglify gulp-rename gulp-concat gulp-notify gulp-filter gulp-jshint gulp-rev-append gulp-cssnano gulp-imagemin browser-sync gulp-file-include gulp-autoprefixer del –save-dev
*/

// Load plugins
var gulp = require(‘gulp’), // 必须先引入gulp插件
  del = require(‘del’), // 文件删除
  sass = require(‘gulp - ruby - sass’), // sass 编译
  cached = require(‘gulp - cached’), // 缓存当前任务中的文件,只让已修改的文件通过管道
  uglify = require(‘gulp - uglify’), // js 压缩
  rename = require(‘gulp - rename’), // 重命名
  concat = require(‘gulp - concat’), // 合并文件
  notify = require(‘gulp - notify’), // 相当于 console.log()
  filter = require(‘gulp - filter’), // 过滤筛选指定文件
  jshint = require(‘gulp - jshint’), // js 语法校验
  rev = require(‘gulp - rev - append’), // 插入文件指纹(MD5)
  cssnano = require(‘gulp - cssnano’), // CSS 压缩
  imagemin = require(‘gulp - imagemin’), // 图片优化
  browserSync = require(‘browser - sync’), // 保存自动刷新
  fileinclude = require(‘gulp - file - include’), // 可以 include html 文件
  autoprefixer = require(‘gulp - autoprefixer’); // 添加 CSS 浏览器前缀

// sass
gulp.task(‘sass’, function () {
  return sass(‘src / sass/**/ *.scss’, { style: ‘expanded’ }) // 传入 sass 目录及子目录下的所有 .scss 文件生成文件流通过管道并设置输出格式
    .pipe(cached(‘sass’)) // 缓存传入文件,只让已修改的文件通过管道(第一次执行是全部通过,因为还没有记录缓存)
    .pipe(autoprefixer(‘last 6 version’)) // 添加 CSS 浏览器前缀,兼容最新的5个版本
    .pipe(gulp.dest(‘dist / css’)) // 输出到 dist/css 目录下(不影响此时管道里的文件流)
    .pipe(rename({ suffix: ‘.min’ })) // 对管道里的文件流添加 .min 的重命名
    .pipe(cssnano()) // 压缩 CSS
    .pipe(gulp.dest(‘dist / css’)) // 输出到 dist/css 目录下,此时每个文件都有压缩(*.min.css)和未压缩(*.css)两个版本
});

// css (拷贝 *.min.css,常规 CSS 则输出压缩与未压缩两个版本)
gulp.task(‘css’, function () {
  return gulp.src(‘src / css/**/ *.css’)
    .pipe(cached(‘css’))
    .pipe(gulp.dest(‘dist / css’)) // 把管道里的所有文件输出到 dist/css 目录
    .pipe(filter([‘**/*’, ‘!**/*.min.css’])) // 筛选出管道中的非 *.min.css 文件
    .pipe(autoprefixer(‘last 6 version’))
    .pipe(gulp.dest(‘dist / css’)) // 把处理过的 css 输出到 dist/css 目录
    .pipe(rename({ suffix: ‘.min’ }))
    .pipe(cssnano())
    .pipe(gulp.dest(‘dist / css’))
});

// styleReload (结合 watch 任务,无刷新CSS注入)
gulp.task(‘styleReload’, [‘sass’, ‘css’], function () {
  return gulp.src([‘dist / css/**/ *.css’])
    .pipe(cached(‘style’))
    .pipe(browserSync.reload({ stream: true })); // 使用无刷新 browserSync 注入 CSS
});

// script (拷贝 *.min.js,常规 js 则输出压缩与未压缩两个版本)
gulp.task(‘script’, function () {
  return gulp.src([‘src / js/**/ *.js’])
    .pipe(cached(‘script’))
    .pipe(gulp.dest(‘dist / js’))
    .pipe(filter([‘**/*’, ‘!**/*.min.js’])) // 筛选出管道中的非 *.min.js 文件
    // .pipe(jshint(‘.jshintrc’)) // js的校验与合并,根据需要开启
    // .pipe(jshint.reporter(‘default’))
    // .pipe(concat(‘main.js’))
    // .pipe(gulp.dest(‘dist/js’))
    .pipe(rename({ suffix: ‘.min’ }))
    .pipe(uglify())
    .pipe(gulp.dest(‘dist / js’))
});

// image
gulp.task(‘image’, function () {
  return gulp.src(‘src / img/**/ *.{ jpg, jpeg, png, gif }’)
    .pipe(cached(‘image’))
    .pipe(imagemin({ optimizationLevel: 3, progressive: true, interlaced: true, multipass: true }))
    // 取值范围:0-7(优化等级),是否无损压缩jpg图片,是否隔行扫描gif进行渲染,是否多次优化svg直到完全优化
    .pipe(gulp.dest(‘dist / img’))
});

// html 编译 html 文件并复制字体
gulp.task(‘html’, function () {
  return gulp.src(‘src/*.html’)
.pipe(fileinclude()) // include html
.pipe(rev()) // 生成并插入 MD5
.pipe(gulp.dest(‘dist/’))
});

// clean 清空 dist 目录
gulp.task(‘clean’, function() {
return del(‘dist/**/*’);
});

// build,关连执行全部编译任务
gulp.task(‘build’, [‘sass’, ‘css’, ‘script’, ‘image’], function () {
  gulp.start(‘html’);
});

// default 默认任务,依赖清空任务
gulp.task(‘default ’, [‘clean’], function () {
  gulp.start(‘build’);
});

// watch 开启本地服务器并监听
gulp.task(‘watch’, function () {
  browserSync.init({
    server: {
      baseDir: ‘dist’ // 在 dist 目录下启动本地服务器环境,自动启动默认浏览器
    }
  });

  // 监控 SASS 文件,有变动则执行CSS注入
  gulp.watch(‘src / sass/**/ *.scss’, [‘styleReload’]);
  // 监控 CSS 文件,有变动则执行CSS注入
  gulp.watch(‘src / css/**/ *.css’, [‘styleReload’]);
  // 监控 js 文件,有变动则执行 script 任务
  gulp.watch(‘src / js/**/ *.js’, [‘script’]);
  // 监控图片文件,有变动则执行 image 任务
  gulp.watch(‘src / img/**/ *’, [‘image’]);
  // 监控 html 文件,有变动则执行 html 任务
  gulp.watch(‘src/**/ *.html’, [‘html’]);
  // 监控 dist 目录下除 css 目录以外的变动(如js,图片等),则自动刷新页面
  gulp.watch([‘dist/**/ *’, ‘!dist / css/**/ *’]).on(‘change’, browserSync.reload);

});

9. 使用 gulp 的方法

执行gulp任务

gulp taskname // 如 gulp sass,不指定 taskname 则默认执行 default 任务

赶在四年一遇的2月29号,匆忙发表。

PS. 感谢 @合金大圣 订正错误。 16.07.04

更新 Gulp 系列教程,请戳下面

Gulp 自动化你的前端

      1. zou
        Google Chrome 60Google Chrome 60Windows 8.1Windows 8.1

        有一个问题还想问下你,我想写一个自动初始化创建目录的task,不知道从哪儿下手,gulp.dest可以新建文件夹,当但是我不太会使用他,想请教下,需要用其他东西吗

        回复
  1. 合金大圣
    UnknownUnknownUnknownUnknown

    关于filter的用法问题:目录结构和插件严格按照按博主的文章搭建,以下两行测试无效,这样筛选出的是空集合,无法实现注释的功能。经查阅filter官方API,猜测与src返回的路径含有上级目录有关,于是在所有的*前添加了**/,功能实现。41行.pipe(filter([‘*’, ‘!*.min.css’])) // 筛选出管道中的非 *.min.css 文件61行.pipe(filter([‘*’, ‘!*.min.js’])) // 筛选出管道中的非 *.min.js 文件改为:41行.pipe(filter([‘**/*’, ‘!**/*.min.css’])) // 筛选出管道中的非 *.min.css 文件61行.pipe(filter([‘**/*’, ‘!**/*.min.js’])) // 筛选出管道中的非 *.min.js 文件至今无人反馈这个问题,不知道我这是不是个例。

    回复
  2. UnknownUnknownUnknownUnknown

    你这才是有亮点的干货,要么代码整体弄上来放注释,要让多点干货,不像我看到另外几篇完全是写给他自己看的。。给赞一个。话说,你这blog用的是什么搭的。

    回复