Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add gulp option #22

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,6 @@ dist/
dist/**/*
node_modules
.idea/

.DS_Store
.DS_Store?
.vscode
7 changes: 5 additions & 2 deletions config.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
{
"defaultUrl": "https://classic.shoptet.cz/",
"sourceFolder": "./src",
"outputFolder": "./dist"
}
"outputFolder": "./dist",
"addonPrefix": "sample-addon",
"addonInfo": "This is description of sample addon",
"env": "development"
}
120 changes: 120 additions & 0 deletions gulpfile.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
/* Shoptet Gulpstack, by Klubus Creative */

// Variables
import { config } from './config.js';
import path from 'path';
import gulp from "gulp";
import pkg from 'gulp-inject-string';
import less from "gulp-less";
import autoPrefixer from "gulp-autoprefixer";
import concat from "gulp-concat";
import cleanCss from "gulp-clean-css";
import uglify from "gulp-uglify";
import javascriptObfuscator from "gulp-javascript-obfuscator";
import rename from "gulp-rename";

const { wrap } = pkg;

const rootDir = process.cwd();

const sourceFolder = path.join(rootDir, config.sourceFolder ?? 'src');
const outputFolder = path.join(rootDir, config.outputFolder);

const addonPrefix = config.addonPrefix;
const addonInfo = config.addonInfo;

const env = config.env;
const isProduction = (env == "production") ? true : false;
Comment on lines +26 to +27
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tady se nám trochu rozchází nastavení webpacku a gulpu. Webpack očekává env.production = true|false. Vy tu pracujete s env = "production". Nejspíš to dělá stejnou věc, ale přijde mi to trochu matoucí.
Ještě jsem se chtěl zeptat, jestli počítáte s env, který může uživatel zadat v CLI?

const minExtension = isProduction ? '.min' : '';

// Tasks
gulp.task("styles-header", function () {
let stream = gulp.src([sourceFolder + "/header/css/styles.less"], {allowEmpty: true})
.pipe(less())
.on('error', function (error) {
console.error('Error in styles-header task:', error.message);
this.emit('end');
})
.pipe(autoPrefixer())
.pipe(wrap("/* " + addonInfo + " */\n\n", ""));
if (isProduction) {
stream = stream.pipe(cleanCss())
}
return stream
.pipe(rename("styles.header"+minExtension+".css"))
.pipe(gulp.dest(outputFolder))
.on('end', () => {
console.log('Task style-header has been completed');
});
});


gulp.task("styles-footer", function () {
let stream = gulp.src([sourceFolder + "/footer/css/styles.less"], {allowEmpty: true})
.pipe(less())
.on('error', function (error) {
console.error('Error in styles-footer task:', error.message);
this.emit('end');
})
.pipe(autoPrefixer())
.pipe(wrap("/* " + addonInfo + " */\n\n", ""));
if (isProduction) {
stream = stream.pipe(cleanCss())
}
return stream
.pipe(rename("styles.footer"+minExtension+".css"))
.pipe(gulp.dest(outputFolder))
.on('end', () => {
console.log('Task style-footer has been completed');
});
});

gulp.task("scripts-header", function () {
let stream = gulp.src([sourceFolder + "/header/js/**/*.js"], { allowEmpty: true })
.pipe(concat("scripts.header" + minExtension + ".js"))
.pipe(wrap("var " + addonPrefix + " = {};(function (" + addonPrefix + ") {\n\n", "\n\n})(" + addonPrefix + ");"))
.pipe(wrap("/* " + addonInfo + " */ \n\n", ""));
if (isProduction) {
stream = stream.pipe(uglify())
.on('error', function (error) {
console.error('Error in scripts-header task:', error.message);
this.emit('end');
})
.pipe(javascriptObfuscator());
}
return stream
.pipe(gulp.dest(outputFolder))
.on('end', () => {
console.log('Task scripts-header has been completed');
});
});

gulp.task("scripts-footer", function () {
let stream = gulp.src([sourceFolder + "/footer/js/**/*.js"], { allowEmpty: true })
.pipe(concat("scripts.footer" + minExtension + ".js"))
.pipe(wrap("var " + addonPrefix + " = {};(function (" + addonPrefix + ") {\n\n", "\n\n})(" + addonPrefix + ");"))
.pipe(wrap("/* " + addonInfo + " */ \n\n", ""));
if (isProduction) {
stream = stream.pipe(uglify())
.on('error', function (error) {
console.error('Error in scripts-footer task:', error.message);
this.emit('end');
})
.pipe(javascriptObfuscator());
}
return stream
.pipe(gulp.dest(outputFolder))
.on('end', () => {
console.log('Task scripts-footer has been completed');
});
});

export const build = gulp.series("styles-header", "styles-footer", "scripts-header", "scripts-footer");
export function watch () {
console.log("Starting watcher...");
gulp.watch(sourceFolder + "/header/css/**/*.less", gulp.series("styles-header"));
gulp.watch(sourceFolder + "/footer/css/**/*.less", gulp.series("styles-footer"));
gulp.watch(sourceFolder + "/header/js/**/*.js", gulp.series("scripts-header"));
gulp.watch(sourceFolder + "/footer/js/**/*.js", gulp.series("scripts-footer"));
}
export default build;
198 changes: 114 additions & 84 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,109 +1,139 @@
#!/usr/bin/env node
/** @format */

import command from './cli.js';
import { config } from './config.js';
import fs from 'fs';
import path from 'path';
import BrowserSyncPlugin from 'browser-sync-webpack-plugin';
import webpack from 'webpack';
import getWebpackConfig from './webpack.config.js';
import command from "./cli.js";
import { config } from "./config.js";
import fs from "fs";
import path from "path";
import BrowserSync from "browser-sync";
import BrowserSyncPlugin from "browser-sync-webpack-plugin";
import webpack from "webpack";
import getWebpackConfig from "./webpack.config.js";
import { build, watch } from "./gulpfile.js";

command.parse(process.argv);

const options = command.opts();

const rootDir = process.cwd();

const sourceFolder = path.join(rootDir, config.sourceFolder ?? 'src');
const outputFolder = path.join(rootDir, options.folder ?? config.outputFolder);
const sourceFolder = path.join(rootDir, config.sourceFolder ?? "src");
const outputFolder = path.join(rootDir, config.outputFolder);

const includesRegex = /<!-- (?:service\s\d+\(\d+\)|api\s\d+\(\d+\)|project)\shtml\s+code\s+(?:header|footer) -->/gi;
const includesCodeRegex = new RegExp(includesRegex.source + '[\\s\\S]*?(?=' + includesRegex.source + '|$)', 'g');
const includesCodeRegex = new RegExp(includesRegex.source + "[\\s\\S]*?(?=" + includesRegex.source + "|$)", "g");

const blankModeStyle = {
match: /<link\s+href="https:\/\/cdn\.myshoptet\.com\/prj\/[^"]+"[^>]*>/gi,
fn: function () {
return '';
},
match: /<link\s+href="https:\/\/cdn\.myshoptet\.com\/prj\/[^"]+"[^>]*>/gi,
fn: function () {
return "";
},
};

const blankModeScript = {
match: /<script\s+src="https:\/\/cdn\.myshoptet\.com\/prj\/[^"]+"[^>]*>/gi,
fn: function () {
return '';
},
match: /<script\s+src="https:\/\/cdn\.myshoptet\.com\/prj\/[^"]+"[^>]*>/gi,
fn: function () {
return "";
},
};

const headerIncludes = {
match: /(?<=<head[\s\S]*?<!--\sUser include\s-->)[\s\S]*?(?=<!--\s\/User include\s-->)/i,
fn: function (req, res, match) {
// Remove includes from the header
const includes = options.removeHeaderIncludes || config.removeHeaderIncludes || [];
const matchedServices = match.match(includesCodeRegex);
if (matchedServices) {
match = matchedServices.filter(service => {
return !includes.some(removedService => service.includes(removedService));
}).join('')
}

// Add custom includes to the footer
const headerMarkup =
(fs.existsSync(outputFolder + '/scripts.header.js') ? '<script src="/scripts.header.js"></script>' : '') +
(fs.existsSync(outputFolder + '/styles.header.css') ? '<link rel="stylesheet" href="/styles.header.css">' : '');
return match + headerMarkup;
},
match: /(?<=<head[\s\S]*?<!--\sUser include\s-->)[\s\S]*?(?=<!--\s\/User include\s-->)/i,
fn: function (req, res, match) {
// Remove includes from the header
const includes = options.removeHeaderIncludes || config.removeHeaderIncludes || [];
const matchedServices = match.match(includesCodeRegex);
if (matchedServices) {
match = matchedServices
.filter((service) => {
return !includes.some((removedService) => service.includes(removedService));
})
.join("");
}

// Add custom includes to the footer
const headerMarkup =
(fs.existsSync(outputFolder + "/scripts.header.js") ? '<script src="/scripts.header.js"></script>' : "") + (fs.existsSync(outputFolder + "/styles.header.css") ? '<link rel="stylesheet" href="/styles.header.css">' : "");
return match + headerMarkup;
},
};

const footerIncludes = {
match: /(?<=<body[\s\S]*?<!--\sUser include\s-->\s*<div class="container">)[\s\S]*?(?=<\/div>\s*<!--\s\/User include\s-->)/i,
fn: function (req, res, match) {
// Remove includes from the footer
const includes = options.removeFooterIncludes || config.removeFooterIncludes || [];
const matchedServices = match.match(includesCodeRegex);
if (matchedServices) {
match = matchedServices.filter(service => {
return !includes.some(removedService => service.includes(removedService));
}).join('')
}

// Add custom includes to the footer
const footerMarkup =
(fs.existsSync(outputFolder + '/scripts.footer.js') ? '<script src="/scripts.footer.js"></script>' : '') +
(fs.existsSync(outputFolder + '/styles.footer.css') ? '<link rel="stylesheet" href="/styles.footer.css">' : '');
return footerMarkup + match;
},
match: /(?<=<body[\s\S]*?<!--\sUser include\s-->\s*<div class="container">)[\s\S]*?(?=<\/div>\s*<!--\s\/User include\s-->)/i,
fn: function (req, res, match) {
// Remove includes from the footer
const includes = options.removeFooterIncludes || config.removeFooterIncludes || [];
const matchedServices = match.match(includesCodeRegex);
if (matchedServices) {
match = matchedServices
.filter((service) => {
return !includes.some((removedService) => service.includes(removedService));
})
.join("");
}

// Add custom includes to the footer
const footerMarkup =
(fs.existsSync(outputFolder + "/scripts.footer.js") ? '<script src="/scripts.footer.js"></script>' : "") + (fs.existsSync(outputFolder + "/styles.footer.css") ? '<link rel="stylesheet" href="/styles.footer.css">' : "");
return footerMarkup + match;
},
};

const rewriteRules = [
{ ...headerIncludes },
{ ...footerIncludes },
{ ...(options.blankMode && blankModeStyle) },
{ ...(options.blankMode && blankModeScript) },
];

const bsPlugin = [
new BrowserSyncPlugin({
proxy: { target: options.remote ?? config.defaultUrl },
serveStatic: [outputFolder],
rewriteRules: rewriteRules.filter(value => Object.keys(value).length !== 0),
port: 3010,
notify: options.notify,
open: false,
}),
];

const baseWebpackConfig = getWebpackConfig('development');

const webpackConfig = {
watch: options.watch,
...baseWebpackConfig,
plugins: [...bsPlugin, ...baseWebpackConfig.plugins],
};

webpack(webpackConfig, (err, stats) => {
if (err || stats.hasErrors()) {
console.log('Webpack errors', err);
}
console.log(stats.toString({ colors: true }));
});
const rewriteRules = [{ ...headerIncludes }, { ...footerIncludes }, { ...(options.blankMode && blankModeStyle) }, { ...(options.blankMode && blankModeScript) }];

function runWebpack() {
const bsPlugin = [
new BrowserSyncPlugin({
proxy: { target: options.remote ?? config.defaultUrl },
serveStatic: [outputFolder],
rewriteRules: rewriteRules.filter((value) => Object.keys(value).length !== 0),
port: 3010,
notify: options.notify || config.notify || true,
open: options.open || config.open || false,
}),
];

const baseWebpackConfig = getWebpackConfig(options.env ?? config.env);
const webpackConfig = {
watch: options.watch,
...baseWebpackConfig,
plugins: [...bsPlugin, ...baseWebpackConfig.plugins],
};
webpack(webpackConfig, (err, stats) => {
if (err || stats.hasErrors()) {
console.log("Webpack errors", err);
}
console.log(stats.toString({ colors: true }));
});
}

async function runGulpTask() {
try {
await build();
} catch (err) {
console.error("Gulp task error:", err);
}
}

function runGulp() {
watch();
runGulpTask();
const bs = BrowserSync({
proxy: { target: options.remote ?? config.defaultUrl },
watch: options.watch,
files: [outputFolder],
serveStatic: [outputFolder],
rewriteRules: rewriteRules.filter((value) => Object.keys(value).length !== 0),
port: 3010,
notify: options.notify || config.notify || true,
open: options.open || config.open || false,
});
}

if (config.builder === "webpack" || options.builder === "webpack") {
runWebpack();
} else if (config.builder === "gulp" || options.builder === "gulp") {
runGulp();
} else {
console.error("Please specify a valid builder: webpack or gulp");
}
Comment on lines +133 to +139
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Prosím, myslím, že by bylo potřeba zachovat status quo, než zavedeme pořádně verzování a publikování jako balíčku. Mohl byste přidat fallback na webpack?
Ještě je přidat options.builder do cli.js.

Loading