分享我的 Gulpfile

Avatar of Chris Coyier
Chris Coyier

DigitalOcean 为您旅程的各个阶段提供云产品。立即开始使用 价值 200 美元的免费积分!

似乎是突然之间,我为这个网站设置的 Gulp 处理开始出现竞争条件。我运行我的 watch 命令,更改一些 CSS,处理有时会留下一些应该在处理过程中清理的额外文件。就像清理任务在文件进入文件系统之前就发生了(或者其他事情...我从来没有真正弄明白)。

不用管那个错误的细节。我认为我会通过升级到使用 Gulp 4.x 而不是 3.x 来解决它,并在内置的 gulp.series 命令中运行它们,我认为这会有所帮助(确实如此)。

让我使用 Gulp 4.x 真是个不小的挑战,我放弃了一整年,然后重新燃起斗争,最终修复了它。我的问题是 Gulp 4 需要 2.x 版本的 CLI,而 Gulp 3 由于某种原因使用了 3.x 版本。实际上,我需要将版本 *降级*,但是尝试了无数方法,却似乎什么也行不通,就好像我的机器上有一个 CLI 3.x 的幽灵版本。

我相信那些更熟悉命令行的人会比我更快地找到答案,但事实证明,运行 command -v gulp 会显示 Gulp 安装位置的文件路径,对我来说,它显示的是 /usr/local/share/npm/bin/gulp,手动删除它,然后重新安装最新版本,就可以让我降级到 2.x。

现在我可以用 Gulp 4.x 了,我将我的 gulpfile.js 重写为更小的函数,每个函数的职责都比较独立。其中很多 *非常适合我的设置*,所以它并不意味着要成为通用使用的样板代码。我只是发布它,因为在创建它的时候,如果我能参考它,肯定会很有帮助。

我的 Gulpfile 做了什么

  • 运行一个 Web 服务器(Browsersync)用于样式注入和自动刷新
  • 运行一个文件监视器(Gulp 的原生功能)用于对正确文件运行正确任务并执行上述操作
  • CSS 处理
    • Sass > Autoprefixer > 压缩
    • 从模板中中断样式表缓存(例如 <link href="style.css?BREAK_CACHE">
    • 将 style.css 放在 WordPress 主题的正确位置,并清理仅在处理期间需要的文件
  • JavaScript 处理
    • Babel > 合并 > 压缩
    • 中断 <script> 的浏览器缓存
    • 清理处理中创建的未使用的文件
  • SVG 处理
    • 创建一个 SVG 精灵(<symbol> 块)
    • 将其命名为 sprite.php 文件(以便它可以被 PHP 包含在模板中)并将其放在特定位置
  • PHP 处理
    • 更新 JavaScript 中的 Ajax 调用,以便在广告更改时清除缓存

代码转储!

const gulp = require("gulp"),
  browserSync = require("browser-sync").create(),
  sass = require("gulp-sass"),
  postcss = require("gulp-postcss"),
  autoprefixer = require("autoprefixer"),
  cssnano = require("cssnano"),
  del = require("del"),
  babel = require("gulp-babel"),
  minify = require("gulp-minify"),
  concat = require("gulp-concat"),
  rename = require("gulp-rename"),
  replace = require("gulp-replace"),
  svgSymbols = require("gulp-svg-symbols"),
  svgmin = require("gulp-svgmin");

const paths = {
  styles: {
    src: ["./scss/*.scss", "./art-direction/*.scss"],
    dest: "./css/"
  },
  scripts: {
    src: ["./js/*.js", "./js/libs/*.js", "!./js/min/*.js"],
    dest: "./js/min"
  },
  svg: {
    src: "./icons/*.svg"
  },
  php: {
    src: ["./*.php", "./ads/*.php", "./art-direction/*.php", "./parts/**/*.php"]
  },
  ads: {
    src: "./ads/*.php"
  }
};

/* STYLES */
function doStyles(done) {
  return gulp.series(style, moveMainStyle, deleteOldMainStyle, done => {
    cacheBust("./header.php", "./");
    done();
  })(done);
}

function style() {
  return gulp
    .src(paths.styles.src)
    .pipe(sass())
    .on("error", sass.logError)
    .pipe(postcss([autoprefixer(), cssnano()]))
    .pipe(gulp.dest(paths.styles.dest))
    .pipe(browserSync.stream());
}

function moveMainStyle() {
  return gulp.src("./css/style.css").pipe(gulp.dest("./"));
}

function deleteOldMainStyle() {
  return del("./css/style.css");
}
/* END STYLES */

/* SCRIPTS */
function doScripts(done) {
  return gulp.series(
    preprocessJs,
    concatJs,
    minifyJs,
    deleteArtifactJs,
    reload,
    done => {
      cacheBust("./parts/footer-scripts.php", "./parts/");
      done();
    }
  )(done);
}

function preprocessJs() {
  return gulp
    .src(paths.scripts.src)
    .pipe(
      babel({
        presets: ["@babel/env"],
        plugins: ["@babel/plugin-proposal-class-properties"]
      })
    )
    .pipe(gulp.dest("./js/babel/"));
}

function concatJs() {
  return gulp
    .src([
      "js/libs/jquery.lazy.js",
      "js/libs/jquery.fitvids.js",
      "js/libs/jquery.resizable.js",
      "js/libs/prism.js",
      "js/babel/highlighting-fixes.js",
      "js/babel/global.js"
    ])
    .pipe(concat("global-concat.js"))
    .pipe(gulp.dest("./js/concat/"));
}

function minifyJs() {
  return gulp
    .src(["./js/babel/*.js", "./js/concat/*.js"])
    .pipe(
      minify({
        ext: {
          src: ".js",
          min: ".min.js"
        }
      })
    )
    .pipe(gulp.dest(paths.scripts.dest));
}

function deleteArtifactJs() {
  return del([
    "./js/babel",
    "./js/concat",
    "./js/min/*.js",
    "!./js/min/*.min.js"
  ]);
}
/* END SCRIPTS */

/* SVG */
function doSvg() {
  return gulp
    .src(paths.svg.src)
    .pipe(svgmin())
    .pipe(
      svgSymbols({
        templates: ["default-svg"],
        svgAttrs: {
          width: 0,
          height: 0,
          display: "none"
        }
      })
    )
    .pipe(rename("icons/sprite/icons.php"))
    .pipe(gulp.dest("./"));
}
/* END SVG */

/* GENERIC THINGS */
function cacheBust(src, dest) {
  var cbString = new Date().getTime();
  return gulp
    .src(src)
    .pipe(
      replace(/cache_bust=\d+/g, function() {
        return "cache_bust=" + cbString;
      })
    )
    .pipe(gulp.dest(dest));
}

function reload(done) {
  browserSync.reload();
  done();
}

function watch() {
  browserSync.init({
    proxy: "csstricks.local"
  });
  gulp.watch(paths.styles.src, doStyles);
  gulp.watch(paths.scripts.src, doScripts);
  gulp.watch(paths.svg.src, doSvg);
  gulp.watch(paths.php.src, reload);
  gulp.watch(paths.ads.src, done => {
    cacheBust("./js/global.js", "./js/");
    done();
  });
}

gulp.task("default", watch);

问题 / 疑问

  • 最糟糕的是它没有非常智能地中断缓存。当 CSS 更改时,它会中断所有样式表的缓存,而不仅仅是相关的样式表。
  • 将来我可能会使用 PHP include() 将 SVG 图标内联,而不是处理精灵图。
  • 如果原始 SVG 具有 widthheight 属性,则 SVG 处理程序会中断,这似乎是错误的。
  • gulp-changed 会加快速度吗?也就是说,只查看已更改的文件而不是所有文件?还是现在不再需要了?
  • 我应该在 gulpfile.js 更改时 重新启动 gulp 吗?
  • 如果我使用所有库都与 ES6 兼容,这样我就可以 import 内容,而不是手动合并,那就太好了。

总是还有很多事情可以做。理想情况下,我会开源整个网站,但我还没有做到。