Mein Gulpfile zum Teilen

Avatar of Chris Coyier
Chris Coyier am

DigitalOcean bietet Cloud-Produkte für jede Phase Ihrer Reise. Starten Sie mit 200 $ kostenlosem Guthaben!

Scheinbar aus heiterem Himmel begann die Gulp-Verarbeitung, die ich für diese Website eingerichtet hatte, mit einem Wettlauf-Problem. Ich führte meinen watch-Befehl aus, änderte etwas CSS, und die Verarbeitung hinterließ manchmal einige zusätzliche Dateien, die während der Verarbeitung aufgeräumt werden sollten. Als ob die Bereinigungsaufgaben vor der Landung der Dateien im Dateisystem stattgefunden hätten (oder so ähnlich… ich bin der Sache nie wirklich auf den Grund gegangen).

Vergessen wir die Details dieses Fehlers. Ich dachte, ich würde es lösen, indem ich die Dinge auf Gulp 4.x anstelle von 3.x aktualisiere und die Dinge im integrierten Befehl gulp.series ausführe, was meiner Meinung nach helfen würde (und das tat es auch).

Gulp 4.x zum Laufen zu bringen, war eine ziemliche Reise für mich, die darin bestand, dass ich ein Jahr lang aufgab, dann den Kampf neu entfachte und ihn schließlich behob. Mein Problem war, dass Gulp 4 eine CLI-Version von 2.x benötigt, während Gulp 3 aus irgendeinem Grund eine Version 3.x verwendete. Im Wesentlichen musste ich die Versionen herabstufen, aber nachdem ich unzählige Dinge versucht hatte, schien nichts zu funktionieren, als ob eine Geisterversion von CLI 3.x auf meiner Maschine wäre.

Ich bin sicher, dass versiertere Kommandozeilen-Experten dies schneller als ich herausgefunden hätten, aber es stellt sich heraus, dass die Ausführung von command -v gulp den Dateipfad enthüllt, an dem Gulp installiert ist, was bei mir /usr/local/share/npm/bin/gulp ergab, und das manuelle Löschen von dort vor der Neuinstallation der neuesten Version hat mich wieder auf 2.x zurückgebracht.

Jetzt, wo ich Gulp 4.x verwenden konnte, habe ich meine gulpfile.js in kleinere Funktionen umgeschrieben, die jeweils ziemlich isoliert in ihrer Verantwortung sind. Vieles davon ist **ganz spezifisch für mein Setup** auf dieser Website, daher ist es nicht als generische Vorlage gedacht. Ich veröffentliche es nur, weil es mir bei der Erstellung sicherlich geholfen hätte.

Was mein spezielles Gulpfile tut

  • Führt einen Webserver ( Browsersync ) für Stil-Injektion und automatische Aktualisierung aus
  • Führt einen Dateibeobachter (native Gulp-Funktion) aus, um die richtigen Aufgaben für die richtigen Dateien auszuführen und die obigen Dinge zu tun
  • CSS-Verarbeitung
    • Sass > Autoprefixer > Minifizieren
    • Bricht den Stylesheet-Cache aus den Vorlagen (z. B. <link href="style.css?BREAK_CACHE">
    • Legt style.css an den richtigen Ort für ein WordPress-Theme und bereinigt Dateien, die nur während der Verarbeitung benötigt werden
  • JavaScript-Verarbeitung
    • Babel > Verketten > Minifizieren
    • Bricht den Browser-Cache für die <script>s
    • Bereinigt ungenutzte Dateien, die bei der Verarbeitung erstellt wurden
  • SVG-Verarbeitung
    • Erstellt einen SVG-Sprite (einen Block von <symbol>s
    • Benennt ihn als sprite.php-Datei (damit er in einer Vorlage per PHP-Include eingebunden werden kann) und platziert ihn an einem bestimmten Ort
  • PHP-Verarbeitung
    • Aktualisiert den Ajax-Aufruf im JavaScript, um den Cache zu leeren, wenn die Anzeigen geändert werden

Code-Dump!

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);

Probleme / Fragen

  • Das Schlimmste ist, dass der Cache nicht sehr intelligent geleert wird. Wenn sich CSS ändert, wird der Cache aller Stylesheets geleert, nicht nur der relevanten.
  • Ich würde SVG-Icons in Zukunft wahrscheinlich einfach mit PHP include()s direkt einbetten, anstatt mich mit Sprites zu befassen.
  • Der SVG-Prozessor bricht ab, wenn die ursprünglichen SVGs width und height Attribute haben, was falsch erscheint.
  • Würde gulp-changed eine Geschwindigkeitssteigerung bringen? Also nur Dateien betrachten, die sich geändert haben, anstatt alle Dateien? Oder ist es nicht mehr nötig?
  • Sollte ich Gulp neu starten bei Änderungen an der gulpfile.js?
  • Es wäre schön, wenn alle von mir verwendeten Bibliotheken ES6-kompatibel wären, damit ich Dinge importieren könnte, anstatt sie manuell verketten zu müssen.

Es gibt immer so viel mehr, das getan werden kann. Idealerweise würde ich diese gesamte Website einfach Open-Source machen, aber dazu bin ich noch nicht gekommen.