Skip to content

Instantly share code, notes, and snippets.

@movahhedi
Last active July 22, 2023 16:54
Show Gist options
  • Save movahhedi/550b730c22bd342d3d5d8c32fed9ff25 to your computer and use it in GitHub Desktop.
Save movahhedi/550b730c22bd342d3d5d8c32fed9ff25 to your computer and use it in GitHub Desktop.
AdmoPro's old & new GulpFile - Transpile & Lint : Typescript, PHP, SCSS
/*
GulpFile Coded by Shahab Movahhedi
https://shmovahhedi.com
*/
import { src, dest } from "gulp";
import through from "through2";
import htmlmin from "gulp-html-minifier-terser";
import { execSync } from "child_process";
const paths = {
html: {
src: ["./src/**/*.html"],
build: "./build/",
},
php: {
src: ["./src/**/*.php", "!./src/**/vendor/**/*"],
build: "./build/",
},
};
const htmlmin_options = {
caseSensitive: true,
collapseWhitespace: true,
keepClosingSlash: true,
minifyCSS: true,
minifyJS: true,
removeAttributeQuotes: false,
removeComments: true,
ignoreCustomFragments: [/(<[%?])([\s\S]*?)(([%|?]>)|$(?![\r\n]))/],
// ignoreCustomFragments: [/(<(%|(\?(=|php|xml))))([\s\S]*?)(([%|\?]>)|$(?![\r\n]))/],
};
export const CopyHtml_Production = () =>
src(paths.html.src).pipe(htmlmin(htmlmin_options)).pipe(dest(paths.html.build));
export const CopyPhp_Production = () =>
src(paths.php.src).pipe(MinifyPhp()).pipe(htmlmin(htmlmin_options)).pipe(dest(paths.php.build));
export const MinifyPhp = () =>
through.obj((chunk, enc, cb) => {
console.log("PHP Minifying: " + chunk.path);
const ret = execSync("php php-minifier.php \"" + chunk.path + "\"");
chunk.contents = ret;
cb(null, chunk);
});
/*
GulpFile Coded by Shahab Movahhedi
https://shmovahhedi.com
*/
// cSpell:ignore nolint, nofix, lstyles, lscripts, ronilaukkarinen
// Bring in the ability to create the `require()` method
import { createRequire } from "module";
// construct the require method
const require = createRequire(import.meta.url);
// import Secrets from "./secret.json";
const Secrets = require("./secret.json");
// Fetch required plugins
import gulp from "gulp";
const { series, parallel, src, dest, watch, task } = gulp;
import through from "through2";
import chalk from "chalk";
import { execSync } from "child_process";
// import { deleteSync } from "del";
import sourcemaps from "gulp-sourcemaps";
// import concat from "gulp-concat";
// import replace from "gulp-replace";
// import rename from "gulp-rename";
// import imagemin from "gulp-imagemin";
import dartSass from "sass";
import gulpSass from "gulp-sass";
const sass = gulpSass(dartSass);
// import postcss from "gulp-postcss";
// import autoprefixer from "autoprefixer";
// import cssnano from "cssnano";
import gulpStylelint from "@ronilaukkarinen/gulp-stylelint";
import browserify from "browserify";
import tsify from "tsify";
import source from "vinyl-source-stream";
import buffer from "vinyl-buffer";
import watchify from "watchify";
import babelify from "babelify";
import gulpESLint from "gulp-eslint";
// import babel from "gulp-babel";
// import ts from "gulp-typescript";
import htmlmin from "gulp-html-minifier-terser";
import terser from "gulp-terser";
import php_connect from "gulp-connect-php";
const argv = require("yargs").options({
secret: {
alias: "s",
demandOption: true,
default: 0,
describe: "Choose a secret config",
type: "number",
},
}).argv;
// All paths
// const buildPath = "./build/**";
const paths = {
all: {
src: ["./src/**/*"],
build: "./build",
build_source: "./build/**/*",
},
html: {
src: ["./src/**/*.html"],
build: "./build/",
},
php: {
src: ["./src/**/*.php", "!./src/**/vendor/**/*.php"],
build: "./build/",
},
// images: {
// src: ["./src/assets/images/**/*"],
// build: "./build/assets/images/",
// },
styles: {
src: ["./src/assets/styles/**/*.scss"],
src_dest: ["./src/assets/styles/"],
build: "./build/assets/css/",
},
scripts: {
// src: ["./src/assets/js/**/*.js"],
src: ["./src/assets/scripts/**/*.tsx"],
src_dest: ["./src/assets/scripts/"],
build: "./build/assets/js/",
},
cachebust: {
src: ["./build/**/*.php"],
build: "./build/",
},
};
const myChalk = {
OperationCount: chalk.bgHex("#007fff").white,
All: chalk.bgHex("#18922f").white.bold,
Script: chalk.bgYellow.white.bold,
Style: chalk.bgBlue.white.bold,
Info: chalk.blueBright,
Success: chalk.green,
Error: chalk.red,
Team_Azure: chalk.bgHex("#007fff").white,
Team_Orange: chalk.bgHex("#ff8000").white,
Team_Turquoise: chalk.bgHex("#0ad5d5").white,
Team_Green: chalk.bgHex("#18922f").white,
Team_Red: chalk.bgHex("#f52a2a").white,
};
const PhpServerPort = 8000;
let OperationCount = 0;
const ClockNow = () =>
new Date().toLocaleTimeString("en-US", {
hour12: false,
hour: "2-digit",
minute: "numeric",
second: "numeric",
});
// const ParseHrtimeToSeconds = (hrtime) => (hrtime[0] + (hrtime[1] / 1e9)).toFixed(3);
function Intro(cb) {
console.log("\r\nGulpFile Coded by " + chalk.bold("Shahab Movahhedi") + "\r\nhttps://shmovahhedi.com\r\n");
cb();
}
function countOperations(cb = null, additional = "") {
console.log("[" + chalk.gray(ClockNow()) + "] " + chalk.bgBlue(" " + OperationCount + " ") + " " + additional);
OperationCount++;
if (cb) cb();
return true;
}
/**
* Copy all files
* @returns
*/
const CopyAll = () => src(paths.all.src).pipe(replaceSecrets()).pipe(dest(paths.all.build));
const htmlmin_options = {
caseSensitive: true,
collapseWhitespace: true,
keepClosingSlash: true,
minifyCSS: true,
minifyJS: true,
removeAttributeQuotes: false,
removeComments: true,
ignoreCustomFragments: [/(<[%?])([\s\S]*?)(([%|?]>)|$(?![\r\n]))/],
// ignoreCustomFragments: [/(<(%|(\?(=|php|xml))))([\s\S]*?)(([%|\?]>)|$(?![\r\n]))/],
};
const CopyHtml_Production = () =>
src(paths.html.src).pipe(htmlmin(htmlmin_options)).pipe(replaceSecrets()).pipe(dest(paths.html.build));
const CopyPhp_Production = () =>
src(paths.php.src).pipe(MinifyPhp()).pipe(htmlmin(htmlmin_options)).pipe(replaceSecrets()).pipe(dest(paths.php.build));
const MinifyPhp = () =>
through.obj((chunk, enc, cb) => {
let ret = execSync("php php-minifier.php \"" + chunk.path + "\"");
console.log(chalk.yellow("PHP Minifying: ") + chunk.path);
chunk.contents = ret;
cb(null, chunk);
});
/**
* Optimize images (.png, .jpeg, .gif, .svg)
* @returns
*/
/* const optimizeImages = () =>
src(paths.images.src)
.pipe(imagemin([
imagemin.gifsicle({ interlaced: true }),
imagemin.mozjpeg({ quality: 75, progressive: true }),
imagemin.optipng({ optimizationLevel: 5 }),
imagemin.svgo({
plugins: [{ removeViewBox: true }, { cleanupIDs: false }],
})
]).on("error", (error) => console.log(error)))
.pipe(dest(paths.images.build)); */
function TranspileStyles() {
countOperations(null, myChalk.Style(" Styles ") + " " + myChalk.Info("Started transpiling styles..."));
return (
src(paths.styles.src)
.on("end", () => countOperations(null, myChalk.Style(" Styles ") + " " + myChalk.Success("Transpiled styles")))
.on("error", (error) => {
countOperations(null, myChalk.Style(" Styles ") + " " + myChalk.Error("Transpile styles ERROR"));
console.log(error);
})
.pipe(replaceSecrets())
// .pipe(postcss([autoprefixer(), cssnano()]))
.pipe(sourcemaps.init({ loadMaps: true }))
.pipe(sass({ outputStyle: "compressed" }).on("error", sass.logError))
.pipe(sourcemaps.write(".", { includeContent: false }))
.pipe(dest(paths.styles.build))
);
}
const Stylelint_Reporters = (NowTs) => [
{
formatter: "string",
console: true,
},
{
formatter: "json",
save: "temp/stylelint-log/stylelint-log-" + NowTs + ".json",
},
{
formatter: "string",
save: "temp/stylelint-log/stylelint-log-last.txt",
},
{
formatter: "string",
save: "temp/stylelint-log/stylelint-log-" + NowTs + ".txt",
},
];
const LintStyles = (Fix = true) =>
src(paths.styles.src)
.pipe(
gulpStylelint({
fix: Fix,
reporters: Stylelint_Reporters(new Date().getTime()),
})
)
.pipe(dest(paths.styles.src_dest));
const LintStyles_NoFix = () =>
src(paths.styles.src)
.pipe(
gulpStylelint({
fix: false,
reporters: Stylelint_Reporters(new Date().getTime()),
})
)
.pipe(dest(paths.styles.src_dest));
const LintScripts = () =>
src(paths.scripts.src)
.pipe(gulpESLint({ fix: false })) // Lint files, create fixes.
.pipe(gulpESLint.format()) // Output lint results to the console.
// .pipe(gulpESLint.fix()) // Fix files if necessary.
// .pipe(gulpESLint.failAfterError()) // Exit with an error if problems are found.
.pipe(dest(paths.scripts.src_dest));
let watchedBrowserify = watchify(
browserify({
basedir: ".",
debug: true,
// entries: glob.sync(paths.scripts.src[0]),
entries: ["src/assets/scripts/app.tsx"],
cache: {},
packageCache: {},
})
.plugin(tsify)
.on("error", (error) => {
countOperations(null, myChalk.Script(" Script ") + " " + myChalk.Error("Transpiling scripts ERROR"));
console.log(error);
})
).transform(babelify, { extensions: [".ts", ".tsx"] });
function TranspileScripts() {
countOperations(null, myChalk.Script(" Script ") + " " + myChalk.Info("Started transpiling scripts..."));
return watchedBrowserify
.bundle()
.on("end", () => countOperations(null, myChalk.Script(" Script ") + " " + myChalk.Success("Transpiled scripts")))
.on("error", (error) => {
countOperations(null, myChalk.Script(" Script ") + " " + myChalk.Error("Transpiling scripts ERROR"));
console.log(error);
})
.pipe(source("script.js"))
.pipe(buffer())
.pipe(sourcemaps.init({ loadMaps: true }))
.pipe(replaceSecrets())
.pipe(terser().on("error", console.log))
.pipe(sourcemaps.write(".", { includeContent: false }))
.pipe(dest(paths.scripts.build));
}
/**
* Transpile scripts without watch
* @returns browserify.BrowserifyObject
*/
function TranspileScripts_Build() {
countOperations(null, myChalk.Script(" Script ") + " " + myChalk.Info("Started transpiling scripts..."));
return browserify({
basedir: ".",
debug: false,
entries: ["src/assets/scripts/app.tsx"],
cache: {},
packageCache: {},
})
.plugin(tsify)
.transform(babelify, { extensions: [".ts", ".tsx"] })
.bundle()
.on("end", () => countOperations(null, myChalk.Script(" Script ") + " " + myChalk.Success("Transpiled scripts")))
.on("error", (error) => {
countOperations(null, myChalk.Script(" Script ") + " " + myChalk.Error("Transpiling scripts ERROR"));
console.log(error);
})
.pipe(source("script.js"))
.pipe(buffer())
.pipe(sourcemaps.init({ loadMaps: true }))
.pipe(replaceSecrets())
.pipe(terser().on("error", console.log))
.pipe(sourcemaps.write(".", { includeContent: false }))
.pipe(dest(paths.scripts.build));
}
const replaceSecrets = () =>
through.obj((chunk, enc, cb) => {
let filetypes = ["php", "html", "css", "scss", "js", "ts", "jsx", "tsx"];
let extension = chunk.path.substring(chunk.path.lastIndexOf(".") + 1, chunk.path.length) || chunk.path;
if (filetypes.includes(extension) && chunk.contents) {
let ContentString = chunk.contents.toString();
ContentString = ContentString.replace(/cache_bust=\d+/g, "cache_bust=" + new Date().getTime());
Object.entries(Secrets[argv.secret].secrets).map(([k, v]) => {
ContentString = ContentString.replace(new RegExp("GULPREPLACE_" + k, "g"), v);
});
chunk.contents = Buffer.from(ContentString);
}
cb(null, chunk);
});
/**
* Watch for file modification at specific paths and run respective tasks accordingly
*/
function watcher() {
console.log(`[${chalk.gray(ClockNow())}] ======== ${chalk.green("Ready for development. Happy Coding :)")}`);
let watcher_all = watch(paths.all.src);
watcher_all.on("change", (fileName) => {
countOperations(null, myChalk.All(" File ") + " " + myChalk.Success("Copied") + " " + chalk.white(fileName));
return src(fileName, { base: "./src/" }).pipe(replaceSecrets()).pipe(dest(paths.all.build));
});
let watcher_styles = watch(paths.styles.src);
watcher_styles.on("change", TranspileStyles);
watchedBrowserify.on("update", TranspileScripts);
}
function RunPhpServer() {
php_connect.server({
base: "./build",
hostname: "0.0.0.0",
port: PhpServerPort,
keepalive: true,
// Suppress all the logging into console of the php server process.
stdio: "ignore",
// Custom PHP locations
// bin: "C:/php/php8.2.0/php.exe",
// ini: "C:/php/php8.2.0/php.ini",
});
console.log(
`[${chalk.gray(ClockNow())}] ======== ${chalk.green("PHP server started on ")} http://localhost:${PhpServerPort}`
);
}
/*function clearBuild(cb) {
countOperations(null, myChalk.Info("Started clearing previous build..."));
deleteSync([buildPath], { force: true });
countOperations(null, myChalk.Success("Cleared previous build"));
cb();
}*/
// Export tasks to make them public
export {
CopyAll as copy,
TranspileStyles as styles,
TranspileScripts as scripts,
LintStyles as lstyles,
LintStyles_NoFix as lstyles_nofix,
LintScripts as lscripts,
RunPhpServer as phpserver,
/*clearBuild as clear,*/
};
task(
"default",
series(Intro, LintStyles, LintScripts, CopyAll, TranspileStyles, TranspileScripts, parallel(RunPhpServer, watcher))
);
task("server", series(Intro, CopyAll, parallel(RunPhpServer, watcher)));
task("nolint", series(Intro, CopyAll, TranspileStyles, TranspileScripts, parallel(RunPhpServer, watcher)));
task("build", series(Intro, CopyAll, TranspileStyles, TranspileScripts_Build));
task(
"prod",
series(Intro, /*clearBuild,*/ CopyAll, CopyPhp_Production, CopyHtml_Production, TranspileStyles, TranspileScripts_Build)
);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment