Skip to content

Instantly share code, notes, and snippets.

@dancingmonkey
Forked from hildissent/gulpfile.js
Created April 13, 2022 08:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dancingmonkey/840e22bf00cc028b1271bf2697d4996c to your computer and use it in GitHub Desktop.
Save dancingmonkey/840e22bf00cc028b1271bf2697d4996c to your computer and use it in GitHub Desktop.
gulpfile - gulp 4, jekyll, tailwindcss, purged (css), minified (css, js, and html), and cache-busting.
"use strict";
//
// PLUGINS
//
const autoprefixer = require("autoprefixer");
const browsersync = require("browser-sync").create();
const clean = require("gulp-clean");
const concat = require("gulp-concat");
const cp = require("child_process");
const critical = require("critical");
const cssimport = require("gulp-cssimport");
const cssnano = require("cssnano");
const gulp = require("gulp");
const htmlmin = require("gulp-htmlmin");
const inject = require("gulp-inject");
const postcss = require("gulp-postcss");
const purgecss = require("gulp-purgecss");
const rename = require("gulp-rename");
const responsive = require("gulp-responsive");
const rev = require("gulp-rev");
const tailwindcss = require("tailwindcss");
const uglify = require("gulp-uglify");
//
// CSS BUILDS
//
// build critical css inline. must run after css + html builds. [production]
function build_nstyle() {
return gulp.src("dist/**/*.html")
.pipe(critical.stream(
{
base: "dist/",
css: ["dist/assets/temp/master.css"],
inline: true,
dimensions:
[
{ height: 896, width: 414 },
{ height: 1024, width: 768 },
{ height: 1336, width: 1024 },
{ height: 1440, width: 2560 }
],
ignore: { atrule: ["@font-face"] }
}
))
.pipe(gulp.dest("dist"))
}
// build a temporary style file with all styles. [production]
// this is only necessary as critical will not accept globs for css input.
function build_master() {
return gulp.src(
[
"src/css/normal.css",
"src/css/styles.css",
"src/css/work.css"
]
)
.pipe(concat("master.css"))
.pipe(cssimport())
.pipe(postcss(
[
tailwindcss("tailwind.js"),
autoprefixer({ browsers: ["last 1 version"] }),
cssnano({ discardComments: { removeAll: true } })
]
))
.pipe(gulp.dest("dist/assets/temp"))
}
// build a css normalize-reset. [development + production]
function build_normal() {
return gulp.src("src/css/normal.css")
.pipe(postcss(
[
tailwindcss("tailwind.js"),
autoprefixer({ browsers: ["last 1 version"] }),
cssnano({ discardComments: { removeAll: true } })
]
))
.pipe(rev())
.pipe(gulp.dest("dist/assets/css"))
.pipe(browsersync.stream());
}
// build full css framework. [development]
function build_styles() {
return gulp.src("src/css/styles.css")
.pipe(postcss(
[
tailwindcss("tailwind.js"),
autoprefixer({ browsers: ["last 1 version"] }),
cssnano({ discardComments: { removeAll: true } })
]
))
.pipe(rev())
.pipe(gulp.dest("dist/assets/css"))
.pipe(browsersync.stream());
}
// build css with only the used elements. [production]
function build_purged() {
// define the tailwind extractor.
class TailwindExtractor {
static extract(content) {
return content.match(/[A-z0-9-:\/]+/g) || [];
}
}
return gulp.src("src/css/styles.css")
.pipe(postcss(
[
tailwindcss("tailwind.js"),
autoprefixer({ browsers: ["last 1 version"] }),
cssnano({ discardComments: { removeAll: true } })
]
))
.pipe(rename({ basename: "purged" }))
.pipe(purgecss(
{
content: ["dist/**/*.html"],
extractors: [
{
extractor: TailwindExtractor,
extensions: ["html", "js"]
}
]
}
))
.pipe(rev())
.pipe(gulp.dest("dist/assets/css"))
.pipe(browsersync.stream());
}
// build css with custom elements. [development + production]
function build_custom() {
return gulp.src("src/css/work.css")
.pipe(cssimport())
.pipe(postcss(
[
tailwindcss("tailwind.js"),
autoprefixer({ browsers: ["last 1 version"] }),
cssnano({ discardComments: { removeAll: true } })
]
))
.pipe(rev())
.pipe(gulp.dest("dist/assets/css"))
.pipe(browsersync.stream());
}
//
// JS BUILDS
//
// build js to be injected inline. [development + production]
function build_ncode() {
return gulp.src(["src/js/vendor/loadCSS.js", "src/js/vendor/loadJS.js"])
.pipe(uglify())
.pipe(gulp.dest("dist/assets/inline"))
.pipe(browsersync.stream());
}
// build js bundle - current strategy is to combine most js. [development + production]
function build_bundle() {
return gulp.src(["src/js/vendor/jquery.js", "src/js/vendor/pushy.js", "src/js/custom.js"])
.pipe(concat("bundle.js"))
.pipe(uglify())
.pipe(rev())
.pipe(gulp.dest("dist/assets/js"))
.pipe(browsersync.stream());
}
//
// IMAGE BUILDS
//
// generate optmized, correctly sized, images. [development + production]
function build_images() {
return gulp.src("src/img/**/*.{jpg,png}")
.pipe(responsive(
{
"21x09/**/*.jpg":
[
{ width: 640, rename: { suffix: "-640", extname: ".jpeg" } },
{ width: 768, rename: { suffix: "-768", extname: ".jpeg" } },
{ width: 1024, rename: { suffix: "-1024", extname: ".jpeg" } },
{ width: 1280, rename: { suffix: "-1280", extname: ".jpeg" } },
{ width: 1536, rename: { suffix: "-1536", extname: ".jpeg" } },
{ width: 1920, rename: { suffix: "-1920", extname: ".jpeg" } }
],
"01x01/**/*.jpg":
[
{ width: 1024, rename: { suffix: "-1024", extname: ".jpeg" } }
],
"avatar.jpg":
[
{ width: 320, rename: { extname: ".jpeg" } }
],
"mythicdomains.png":
[
{ width: 320, rename: { extname: ".png" } }
]
},
{
// global configuration for all images
quality: 70,
progressive: true,
withMetadata: false,
errorOnUnusedImage: false,
passThroughUnused: true
}
))
.pipe(gulp.dest("dist/assets/img"))
.pipe(browsersync.stream());
}
//
// JEKYLL BUILDS
//
// build jekyll with development environment variable. exclude analytics, comments, etc. [development]
function build_static() {
return cp.spawn(
"bundle",
["exec", "jekyll", "build"],
{ stdio: "inherit" }
);
}
// build jekyll with production environment variable. [production]
function build_jekyll() {
var productionEnv = process.env;
productionEnv.JEKYLL_ENV = "production";
return cp.spawn(
"bundle",
["exec", "jekyll", "build"],
{
stdio: "inherit",
env: productionEnv
}
);
}
//
// HTML BUILDS
//
// process the html content in dist. [development + production]
function build_forged() {
return gulp.src("dist/**/*.html")
// inject inline js - each injection is to a specific file.
.pipe(inject(
gulp.src(["dist/assets/inline/*.js"]),
{
transform: function (filePath, file)
{ return '<script type=\"text/javascript\">' + file.contents.toString('utf8') + '</script>'; }
}
))
// include cache-busting css via loadCSS.js.
.pipe(inject(
gulp.src(["dist/assets/css/*.css"],{ read: false }),
{
relative: true,
transform: function (filepath, file, i, length)
{ return '<link rel=\"preload\" href=\"' + filepath + '\" as=\"style\" onload=\"this.onload=null\;this.rel=\'stylesheet\'\" /><noscript><link rel=\"stylesheet\" href=\"' + filepath + '\" /></noscript>'; }
}
))
//include cache-busting js via loadJS.js.
.pipe(inject(
gulp.src(["dist/assets/js/*.js"],{ read: false }),
{
starttag: "<!-- codefile:{{ext}} -->",
endtag: "<!-- endcodefile -->",
relative: true,
transform: function (filepath, file, i, length)
{ return '<script type=\"text/javascript\">loadJS( \"' + filepath + '\" )\;</script>'; }
}
))
// minify the html files.
.pipe(htmlmin(
{
collapseWhitespace: true,
removeComments: true,
minifyCSS: true,
processScripts: ["application/ld+json"],
sortAttributes: true,
sortClassName: true
}
))
.pipe(gulp.dest("dist"))
.pipe(browsersync.stream());
}
//
// CLEAN FOLDERS
//
// remove all css files from dist.
function clean_styles() {
return gulp.src(
"dist/assets/css/",
{
read: false,
allowEmpty: true
}
)
.pipe(clean());
}
// remove all js files from dist.
function clean_script() {
return gulp.src(
[
"dist/assets/js/",
"dist/assets/inline/*.js"
],
{
read: false,
allowEmpty: true
}
)
.pipe(clean());
}
// remove all image files from dist.
function clean_images() {
return gulp.src(
"dist/assets/img/",
{
read: false,
allowEmpty: true
}
)
.pipe(clean());
}
// remove all of dist.
function clean_folder() {
return gulp.src(
"dist/",
{
read: false,
allowEmpty: true
}
)
.pipe(clean());
}
//
// SERVICES
//
// websync initiation.
function local_browse(done) {
browsersync.init(
{
server: { baseDir: "./dist/" },
port: 4000
}
);
done();
}
// websync cycler.
function local_cycler(done) {
browsersync.reload();
done();
}
// project watcher & automated rebuilding.
function watch_mywork() {
gulp.watch("./src/css/normal.css", gulp.series(build_normal, build_static, build_forged, local_cycler));
gulp.watch("./src/css/styles.css", gulp.series(build_styles, build_static, build_forged, local_cycler));
gulp.watch("./src/js/**/*", gulp.series(build_ncode, build_bundle, build_static, build_forged, local_cycler));
gulp.watch("./src/img/**/*", build_images);
gulp.watch(
[
"app/_includes/**/*",
"app/_layouts/**/*",
"app/_data/**/*",
"app/_posts/**/*",
"app/_drafts/**/*",
"app/pages/**/*",
"app/_category/**/*",
"app/_grain-of-destiny/**/*"
],
gulp.series(build_static, build_forged, local_cycler)
);
}
//
// COMPLEX TASKS
//
// these tasks manage assets, and are called by the other tasks.
const pack_styles = gulp.series(clean_styles, gulp.parallel(build_normal, build_styles, build_custom));
const pack_script = gulp.series(clean_script, gulp.parallel(build_ncode, build_bundle));
const pack_images = gulp.series(clean_images, build_images);
// this task starts watching the project and running tasks on file changes.
const watch = gulp.parallel(local_browse, watch_mywork);
// this task forces a complete build in the development environment.
const pack_tester =
gulp.series(
clean_folder, // clear workspace
gulp.parallel(pack_styles, pack_script, pack_images), // build css, jss, & images
build_static, // generate html via jekyll
build_forged, // minify html, include js and external css
local_cycler // websync update
);
// use this to force a complete build in the production environment.
const pack_server =
gulp.series(
clean_folder, // clear workspace
gulp.parallel(pack_script, pack_images), // build js & images
gulp.parallel(build_normal, build_custom, build_master), // build base css
build_jekyll, // generate html via jekyll
build_purged, // build css w/ only used styles
build_forged, // minify html, include js and external css
build_nstyle // inline critical styles
);
//
// EXPORTS
//
exports.watch = watch;
exports.clean = clean_folder;
exports.styles = pack_styles;
exports.script = pack_script;
exports.images = pack_images;
exports.tester = pack_tester;
exports.server = pack_server;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment