gulp 基础入门

发布于 2024-07-05 12:50:41 字数 11042 浏览 14 评论 0

gulp 是基于 nodejs 的用自动化构建工具,可以通过 gulp 和各种插件实现前端的开发自动化工作流程。

gulp 4.0 已经发布,当前文章是 gulp@3.9.1 的版本的代码。

快速入门

第一步: 全局安装 gulp:

# 安装 gulp 的控制台辅助工具。
$ npm install --global gulp-cli
$ npm install --global gulp@3.9.1

第二步: 作为项目的开发依赖(devDependencies)安装

# 由于 gulp4.0.0 发布后不兼容之前的 api,所以本文以下所有的代码实例都是以 3.9.1 版本编写,请注意!
$ npm install --save-dev gulp@3.9.1

由于 gulp 4.0.0 发布后不兼容之前的 api,所以本文以下所有的代码实例都是以 3.9.1 版本编写,请注意!

第三步:

在项目根目录下创建一个名为 gulpfile.js 的文件:

var gulp = require('gulp');

gulp.task('default', function() {
  // 将你的默认的任务代码放在这
});

第四步: 运行 gulp:

$ gulp

默认的名为 default 的任务(task)将会被运行,在这里,这个任务并未做任何事情。 想要单独执行特定的任务(task),请输入 gulp 。

gulp API 文档

gulp 一共就 4 个 api, srcdesttaskwatch

具体细节请参考 官方文档

适合初学者的 gulp+requirejs 的项目模板

虽然, webpack 已经大行其道。作为初学者,gulp 依然是最快的入门学习前端工作流的工具。本项目本着为中小型团队打造一个基于:gulp+sass+requirejs+es6+eslint+arttemplate 的基本的项目模板。

项目模板 在线 github 地址

gulp 相关应用

  • js(用 requirejs 管理模块)
    • 压缩
    • 转码
    • 版本号
    • 自动修改注入 requirejs 的 paths
    • es6 转码
    • eslint 检测
    • 添加版本信息
  • style
    • sass
    • 合并
    • 压缩
    • 加前缀
    • 打版本
    • sourcemap(开发)
  • 图片压缩优化
  • html
    • 压缩
    • 修改 url 地址
  • 打包前清理
  • 打包后拷贝目录

编辑器的一致性

  • .editorconfig 文件控制编辑器的一致性
  • eslint 校验一致性,并配置 vscode 自动修改符合 eslint 校验,可以安装 eslint 插件。

本地测试和代理配置

  • 运行本地测试
$ npm run dev

本地启动服务器地址: http://localhost:8000

打包

$ npm run build

# 会把最终结果输出到 dist 目录

项目的目录结构

.
├── gulpfile.js
├── package.json
├── readme.md
├── src
│   ├── app.js
│   ├── asset
│   │   └── img
│   │       └── a.jpg
│   ├── controller
│   │   └── student
│   │       └── listController.js
│   ├── index.html
│   ├── js
│   │   ├── E.js
│   │   ├── index.js
│   │   ├── rev-manifest.json
│   │   └── tmpl
│   │       ├── header.js         // 自动生成
│   │       ├── student.js        // 自动生成
│   │       └── user.js
│   ├── lib
│   │   ├── arttemplate
│   │   │   ├── es5-sham.min.js
│   │   │   ├── es5-shim.min.js
│   │   │   ├── json3.min.js
│   │   │   └── template-web.js
│   │   └── require.js
│   ├── service
│   │   └── index.js              // 所有的服务
│   ├── style
│   │   ├── a.css
│   │   ├── main.css
│   │   ├── rev-manifest.json
│   │   └── scss
│   │       ├── b.scss
│   │       └── index.scss
│   ├── template                 //  art-template 模板
│   │   ├── header
│   │   │   └── header.html
│   │   ├── student
│   │   │   ├── stuList.html
│   │   │   ├── t.html
│   │   │   └── userList.html
│   │   └── user
│   │       └── footer.html
│   └── view
│       ├── about.html
│       └── student
│           └── list.html
└── yarn.lock

gulpfile 细节

'use strict';
const fs = require('fs');
const path = require('path');

// 引入 gulp 包, nodejs 代码
const gulp = require('gulp'),
  // 引入 gulp-sass 包
  sass = require('gulp-sass'),
  // gulp 版本定义
  rev = require('gulp-rev'),
  concat = require('gulp-concat'), // 合并文件 --合并只是放一起--压缩才会真正合并相同样式
  rename = require('gulp-rename'), // 设置压缩后的文件名
  // 替换版本 url
  revCollector = require('gulp-rev-collector'),
  // css 压缩
  cleanCss = require('gulp-clean-css'),
  // 兼容处理 css3
  autoprefixer = require('gulp-autoprefixer'),
  // css 代码 map
  sourcemaps = require('gulp-sourcemaps'),
  // js 压缩
  uglify = require('gulp-uglify'),
  // img 压缩
  imgagemin = require('gulp-imagemin'),
  // 清理文件夹
  clean = require('gulp-clean'),
  // 顺序执行
  runSequence = require('gulp-run-sequence'),
  // 给 js 文件替换文件路径
  configRevReplace = require('gulp-requirejs-rev-replace'),
  // 过滤
  filter = require('gulp-filter'),
  // js 校验
  eslint = require('gulp-eslint'),
  // babel 转换 es6
  babel = require('gulp-babel'),
  // 本地的测试服务器
  connect = require('gulp-connect'),
  // 本地测试服务器中间件
  proxy = require('http-proxy-middleware'),
  // 服务器的代理插件
  modRewrite = require('connect-modrewrite'),
  // 打开浏览器
  open = require('gulp-open'),
  // html 压缩
  htmlmin = require('gulp-htmlmin'),
  replace = require('gulp-replace'),
  // 自动编译 artTemplate 模板成 js 文件
  tmodjs = require('gulp-tmod');
// minifyHtml = require('gulp-minify-html'); 样式处理工作流:编译 sass → 添加 css3 前缀 → 合并 →
// 压缩 css →添加版本号
gulp.task('style', function(e) {
  // 过滤非 sass 文件
  var sassFilter = filter(['**/*.scss'], { restore: true });
  return gulp
    .src(['./src/style/**/*.{scss,css}', '!./src/style/main.css']) // 读取 sass 文件
    .pipe(sassFilter)
    .pipe(sass()) // 编译 sass
    .pipe(sassFilter.restore)
    .pipe(
      autoprefixer({
        // 兼容 css3
        browsers: ['last 2 versions'], // 浏览器版本
        cascade: true, // 美化属性,默认 true
        add: true, // 是否添加前缀,默认 true
        remove: true, // 删除过时前缀,默认 true
        flexbox: true // 为 flexbox 属性添加前缀,默认 true
      })
    )
    .pipe(concat('main.css')) // 合并 css
    .pipe(
      cleanCss({
        // 压缩 css
        compatibility: 'ie8',
        // 保留所有特殊前缀 当你用 autoprefixer 生成的浏览器前缀,如果不加这个参数,有可能将会删除你的部分前缀
        keepSpecialComments: '*'
      })
    )
    .pipe(rev()) // 文件名加 MD5 后缀
    .pipe(gulp.dest('./dist/style/')) // 输出目标文件到 dist 目录
    .pipe(rev.manifest()) // 生成一个 rev-manifest.json
    .pipe(gulp.dest('./src/style/')); // 将 rev-manifest.json 保存到 src 目录
});

// 替换目标 html 文件中的 css 版本文件名,js 版本的文件名,html 压缩
gulp.task('html', function(e) {
  return gulp
    .src(['./src/**/*.json', './src/**/*.html', '!./src/template/**']) // - 读取 rev-manifest.json 文件以及需要进行 css 名替换的文件
    .pipe(revCollector({ replaceReved: true })) // - 执行 html 文件内 css 文件名的替换和 js 文件名替换
    .pipe(
      htmlmin({
        removeComments: true, // 清除 HTML 注释
        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"
        minifyJS: true, // 压缩页面 JS
        minifyCSS: true // 压缩页面 CSS
      })
    )
    .pipe(gulp.dest('./dist/')); // - 替换后的文件输出的目录
});

// 图片压缩
gulp.task('imgmin', function(e) {
  return gulp
    .src('./src/asset/**/*.{png,jpg,gif,ico}')
    .pipe(
      imgagemin({
        optimizationLevel: 5, // 类型:Number  默认:3  取值范围:0-7(优化等级)
        progressive: true, // 类型:Boolean 默认:false 无损压缩 jpg 图片
        interlaced: true,
        // 类型:Boolean 默认:false 隔行扫描 gif 进行渲染
        multipass: true // 类型:Boolean
        // 默认:false 多次优化 svg 直到完全优化
      })
    )
    .pipe(gulp.dest('./dist/asset'));
});

// js 压缩添加版本
gulp.task('js', function(e) {
  return gulp
    .src(['./src/**/*.js', '!./src/lib/**'])
    .pipe(eslint())
    .pipe(
      eslint.results(results => {
        // Called once for all ESLint results.
        console.log(`JS 总校验文件: ${results.length}`);
        console.log(`JS 警告个数:: ${results.warningCount}`);
        console.log(`JS 错误个数: ${results.errorCount}`);
      })
    )
    .pipe(eslint.format())
    .pipe(eslint.failAfterError())
    .pipe(babel({ presets: ['env'] }))
    .pipe(uglify())
    .pipe(rev())
    .pipe(gulp.dest('./dist'))
    .pipe(rev.manifest())
    .pipe(gulp.dest('./src/js/'));
});

// 给 requirejs 引用的文件修改版本号的路径
gulp.task('revjs', function() {
  return gulp
    .src('./dist/*.js')
    .pipe(
      configRevReplace({
        manifest: gulp.src('./src/js/rev-manifest.json')
      })
    )
    .pipe(uglify())
    .pipe(gulp.dest('dist/'));
});

// 打包要复制的路径 2
var copyPathArr = ['./src/lib/**/*', './src/asset/**/*', './src/*.ico'];
// 拷贝 gulp 文件
gulp.task('copy', function(e) {
  return gulp.src(copyPathArr, { base: './src' }).pipe(gulp.dest('./dist/'));
});
// 清理 dist 目录下的历史文件
gulp.task('cleanDist', function() {
  gulp
    .src(['dist/style/**', 'dist/js/**', 'dist/*.js'], { read: false })
    .pipe(clean());
});
gulp.task('dist', [], function() {
  runSequence(
    'cleanDist',
    'tpl',
    'style',
    'js',
    'revjs',
    'html',
    'copy',
    'imgmin'
  );
});

gulp.task('tpl', function() {
  // 拿到所有的路径
  let basePath = path.join(__dirname, 'src/template');
  let files = fs.readdirSync(basePath);
  files.forEach((val, index) => {
    let dirPath = path.join(basePath, val);
    let stat = fs.statSync(dirPath);
    if (!stat.isDirectory()) {
      return;
    }
    var fileter = 'src/template/' + val + '/**/*.html';
    console.log(fileter);
    gulp
      .src('src/template/' + val + '/**/*.html')
      .pipe(
        tmodjs({
          templateBase: 'src/template/' + val,
          runtime: val + '.js',
          compress: false
        })
      )
      // 自动生成的模板文件,进行 babel 转换,会报错,此转换插件已经停更,所以间接改这个 bug
      // 参考 bug: https://github.com/aui/tmodjs/issues/112  主要是 this  →  window
      .pipe(replace('var String = this.String;', 'var String = window.String;'))
      .pipe(gulp.dest('src/js/tmpl/'));
  });
});

// ============= 开发样式处理
gulp.task('style:dev', function(e) {
  var sassFilter = filter(['**/*.scss'], { restore: true });
  return gulp
    .src(['./src/style/**/*.{scss,css}', '!./src/style/main.css']) // 读取 sass 文件
    .pipe(sourcemaps.init())
    .pipe(sassFilter)
    .pipe(sass()) // 编译 sass
    .pipe(sassFilter.restore)
    .pipe(concat('main.css'))
    .pipe(sourcemaps.write())
    .pipe(gulp.dest('./src/style/'));
});

// 开发监控 sass 文件变化编译 sass 到 css 文件 可以增加 es6 的编译,jslint
gulp.task('dev', ['open'], function() {
  gulp.watch('src/style/**', ['style:dev']);
  gulp.watch('src/template/**', ['tpl']);
});

// 配置测试服务器
gulp.task('devServer', function() {
  connect.server({
    root: ['./src'], // 网站根目录
    port: 38900, // 端口
    livereload: true,
    middleware: function(connect, opt) {
      return [
        modRewrite([
          // 设置代理
          '^/api/(.*)$  http://192.168.0.102:8080/mockjsdata/1/api/ $1 [P]'
        ])
      ];
    }
  });
});

// 启动浏览器打开地址
gulp.task('open', ['devServer'], function() {
  gulp.src(__filename).pipe(open({ uri: 'http://localhost:38900/index.html' }));
});

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

关于作者

心意如水

暂无简介

0 文章
0 评论
23 人气
更多

推荐作者

qq_BY4R7o

文章 0 评论 0

13696529860

文章 0 评论 0

qq_M1hW18

文章 0 评论 0

qq_4zWU6L

文章 0 评论 0

薄暮涼年

文章 0 评论 0

恬淡成诗

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文