303 lines
9.4 KiB
JavaScript
303 lines
9.4 KiB
JavaScript
import gulp from 'gulp';
|
|
import twig from 'gulp-twig';
|
|
import * as dartSass from 'sass';
|
|
import gulpSass from 'gulp-sass';
|
|
import autoprefixer from 'gulp-autoprefixer';
|
|
import browserSync from 'browser-sync';
|
|
import babel from 'gulp-babel';
|
|
import concat from 'gulp-concat';
|
|
import uglify from 'gulp-uglify';
|
|
import imagemin from 'gulp-imagemin';
|
|
import cleanCss from 'gulp-clean-css';
|
|
import { deleteAsync } from 'del';
|
|
import sourcemaps from 'gulp-sourcemaps';
|
|
import fs from 'fs';
|
|
import plumber from 'gulp-plumber';
|
|
import svgstore from 'gulp-svgstore';
|
|
import cheerio from 'gulp-cheerio';
|
|
import through2 from 'through2';
|
|
import data from 'gulp-data';
|
|
import path from 'path';
|
|
import webp from 'gulp-webp';
|
|
import rev from 'gulp-rev';
|
|
import revReplace from 'gulp-rev-replace';
|
|
import cached from 'gulp-cached';
|
|
import remember from 'gulp-remember';
|
|
import { exec } from 'child_process';
|
|
import puppeteer from 'puppeteer';
|
|
import postcss from 'gulp-postcss';
|
|
|
|
import { fileURLToPath } from 'url';
|
|
import { dirname } from 'path';
|
|
|
|
const __filename = fileURLToPath(import.meta.url);
|
|
const __dirname = dirname(__filename);
|
|
|
|
const sass = gulpSass(dartSass);
|
|
browserSync.create();
|
|
|
|
const cleanTask = () => {
|
|
return deleteAsync(['dist']);
|
|
};
|
|
|
|
const lintJsTask = (cb) => {
|
|
exec('npx @biomejs/biome check src/js', (err, stdout, stderr) => {
|
|
console.log(stdout);
|
|
console.error(stderr);
|
|
if (err) {
|
|
console.error('Biome check failed!', err);
|
|
return cb(err);
|
|
}
|
|
cb();
|
|
});
|
|
};
|
|
|
|
const formatJsTask = (cb) => {
|
|
exec('npx @biomejs/biome format --write src/js', (err, stdout, stderr) => {
|
|
console.log(stdout);
|
|
console.error(stderr);
|
|
if (err) {
|
|
console.error('Biome format failed!', err);
|
|
return cb(err);
|
|
}
|
|
cb();
|
|
});
|
|
};
|
|
|
|
export const svgSpriteTask = (cb) => {
|
|
let svgContent = '';
|
|
return gulp.src('src/icons/**/*.svg')
|
|
.pipe(cached('svgIcons')) // Cache SVG icons
|
|
.pipe(plumber())
|
|
.pipe(cheerio({
|
|
run: function ($) {
|
|
$('[fill]').removeAttr('fill');
|
|
$('[stroke]').removeAttr('stroke');
|
|
$('[style]').removeAttr('style');
|
|
},
|
|
parserOptions: { xmlMode: true }
|
|
}))
|
|
.pipe(svgstore({
|
|
inlineSvg: true
|
|
}))
|
|
.pipe(remember('svgIcons')) // Remember all SVG icons
|
|
.pipe(through2.obj(function (file, enc, cb2) {
|
|
svgContent = file.contents.toString();
|
|
cb2(null, file);
|
|
}))
|
|
.pipe(gulp.dest('dist')) // Still write to dist for consistency
|
|
.on('end', () => {
|
|
// Ensure the file is written before calling the callback
|
|
fs.promises.writeFile('./dist/svg-sprite.svg', svgContent)
|
|
.then(cb)
|
|
.catch(cb);
|
|
});
|
|
};
|
|
|
|
const twigTask = () => {
|
|
const globalData = JSON.parse(fs.readFileSync('./src/data/global.json'));
|
|
const svgSprite = fs.readFileSync('./dist/svg-sprite.svg', 'utf8');
|
|
|
|
return gulp.src('src/templates/*.twig') // Process only top-level twig files
|
|
.pipe(cached('twigTemplates')) // Cache twig templates
|
|
.pipe(plumber())
|
|
.pipe(data(function(file) {
|
|
const fileName = path.basename(file.path, '.twig');
|
|
const dataFilePath = `./src/data/${fileName}.json`;
|
|
let pageData = {};
|
|
if (fs.existsSync(dataFilePath)) {
|
|
pageData = JSON.parse(fs.readFileSync(dataFilePath));
|
|
}
|
|
return { ...globalData, ...pageData, svgSprite: svgSprite };
|
|
}))
|
|
.pipe(twig())
|
|
.pipe(remember('twigTemplates')) // Remember all twig templates
|
|
.pipe(gulp.dest('dist'))
|
|
.pipe(browserSync.stream());
|
|
};
|
|
|
|
const scssTask = () => {
|
|
return gulp.src('src/scss/main.scss')
|
|
.pipe(cached('scss')) // Cache SCSS files
|
|
.pipe(plumber())
|
|
.pipe(sourcemaps.init())
|
|
.pipe(sass().on('error', sass.logError))
|
|
.pipe(autoprefixer())
|
|
.pipe(sourcemaps.write('.'))
|
|
.pipe(remember('scss')) // Remember all SCSS files
|
|
.pipe(gulp.dest('dist'))
|
|
.pipe(browserSync.stream());
|
|
};
|
|
|
|
const scssProdTask = () => {
|
|
return gulp.src('src/scss/main.scss')
|
|
.pipe(cached('scssProd')) // Cache SCSS files for prod
|
|
.pipe(plumber())
|
|
.pipe(sass().on('error', sass.logError))
|
|
.pipe(autoprefixer())
|
|
|
|
.pipe(cleanCss())
|
|
.pipe(remember('scssProd')) // Remember all SCSS files for prod
|
|
.pipe(gulp.dest('dist'));
|
|
};
|
|
|
|
const jsDevTask = () => {
|
|
return gulp.src('src/js/**/*.js')
|
|
.pipe(cached('jsDev')) // Cache JS files for dev
|
|
.pipe(plumber())
|
|
.pipe(babel({
|
|
presets: ['@babel/env']
|
|
}))
|
|
.pipe(concat('main.js'))
|
|
.pipe(sourcemaps.write('.'))
|
|
.pipe(remember('jsDev')) // Remember all JS files for dev
|
|
.pipe(gulp.dest('dist/js'))
|
|
.pipe(browserSync.stream());
|
|
};
|
|
|
|
const jsMinTask = () => {
|
|
return gulp.src(['src/js/**/*.js', '!src/js/**/*.test.js'])
|
|
.pipe(cached('jsProd')) // Cache JS files for prod
|
|
.pipe(plumber())
|
|
.pipe(sourcemaps.init())
|
|
.pipe(babel({
|
|
presets: ['@babel/env']
|
|
}))
|
|
.pipe(concat('main.min.js'))
|
|
.pipe(uglify())
|
|
.pipe(sourcemaps.write('.'))
|
|
.pipe(remember('jsProd')) // Remember all JS files for prod
|
|
.pipe(gulp.dest('dist/js'))
|
|
.pipe(browserSync.stream());
|
|
};
|
|
|
|
const jsTask = () => {
|
|
return gulp.src(['src/js/**/*.js', '!src/js/**/*.test.js'])
|
|
.pipe(cached('jsProd')) // Cache JS files for prod
|
|
.pipe(plumber())
|
|
.pipe(sourcemaps.init())
|
|
.pipe(babel({
|
|
presets: ['@babel/env']
|
|
}))
|
|
.pipe(concat('main.js'))
|
|
.pipe(sourcemaps.write('.'))
|
|
.pipe(remember('jsProd')) // Remember all JS files for prod
|
|
.pipe(gulp.dest('dist/js'))
|
|
.pipe(browserSync.stream());
|
|
};
|
|
|
|
const imagesTask = () => {
|
|
return gulp.src('src/images/*')
|
|
.pipe(cached('images')) // Cache images
|
|
.pipe(plumber())
|
|
.pipe(imagemin())
|
|
.pipe(remember('images')) // Remember all images
|
|
.pipe(gulp.dest('dist/images'))
|
|
.pipe(browserSync.stream());
|
|
};
|
|
|
|
const imagesProdTask = () => {
|
|
return gulp.src('src/images/*')
|
|
.pipe(cached('imagesProd')) // Cache images for prod
|
|
.pipe(plumber())
|
|
.pipe(imagemin())
|
|
.pipe(gulp.dest('dist/images'))
|
|
.pipe(webp())
|
|
.pipe(gulp.dest('dist/images'));
|
|
};
|
|
|
|
const copyAssetsTask = () => {
|
|
return gulp.src('src/assets/**/*')
|
|
.pipe(cached('assets')) // Cache assets
|
|
.pipe(plumber())
|
|
.pipe(remember('assets')) // Remember all assets
|
|
.pipe(gulp.dest('dist/assets'))
|
|
.pipe(browserSync.stream());
|
|
};
|
|
|
|
const copyFaviconTask = () => {
|
|
return gulp.src('src/favicon.ico')
|
|
.pipe(cached('favicon')) // Cache favicon
|
|
.pipe(plumber())
|
|
.pipe(remember('favicon')) // Remember favicon
|
|
.pipe(gulp.dest('dist'))
|
|
.pipe(browserSync.stream());
|
|
};
|
|
|
|
const copyFontsTask = () => {
|
|
return gulp.src('src/fonts/**/*')
|
|
.pipe(cached('fonts')) // Cache fonts
|
|
.pipe(plumber())
|
|
.pipe(remember('fonts')) // Remember all fonts
|
|
.pipe(gulp.dest('dist/fonts'))
|
|
.pipe(browserSync.stream());
|
|
};
|
|
|
|
const revTask = () => {
|
|
return gulp.src(['dist/**/*.css', 'dist/**/*.js'], { base: 'dist' })
|
|
.pipe(gulp.dest('dist')) // write original assets to dist
|
|
.pipe(rev())
|
|
.pipe(gulp.dest('dist')) // write rev'd assets to dist
|
|
.pipe(rev.manifest())
|
|
.pipe(gulp.dest('dist')); // write manifest to dist
|
|
};
|
|
|
|
const revReplaceTask = () => {
|
|
const manifest = gulp.src('dist/rev-manifest.json');
|
|
|
|
return gulp.src('dist/**/*.html')
|
|
.pipe(revReplace({ manifest: manifest }))
|
|
.pipe(gulp.dest('dist'));
|
|
};
|
|
|
|
const screenshotsTask = async () => {
|
|
const browser = await puppeteer.launch();
|
|
const page = await browser.newPage();
|
|
const resolutions = [
|
|
{ width: 1920, height: 1080, name: 'desktop' },
|
|
{ width: 1366, height: 768, name: 'laptop' },
|
|
{ width: 768, height: 1024, name: 'tablet' },
|
|
{ width: 375, height: 667, name: 'mobile' },
|
|
];
|
|
|
|
// Ensure the screenshots directory exists
|
|
if (!fs.existsSync('dist/screenshots')) {
|
|
fs.mkdirSync('dist/screenshots');
|
|
}
|
|
|
|
for (const res of resolutions) {
|
|
await page.setViewport({ width: res.width, height: res.height });
|
|
await page.goto('file://' + path.resolve(__dirname, 'dist/index.html'));
|
|
await page.screenshot({ path: `dist/screenshots/screenshot-${res.name}-${res.width}x${res.height}.png` });
|
|
console.log(`Screenshot captured for ${res.name} (${res.width}x${res.height})`);
|
|
}
|
|
|
|
await browser.close();
|
|
};
|
|
|
|
|
|
const watchTask = () => {
|
|
browserSync.init({
|
|
server: {
|
|
baseDir: './dist'
|
|
},
|
|
https: true // Enable HTTPS
|
|
});
|
|
gulp.watch('src/templates/**/*.twig', twigTask);
|
|
gulp.watch('src/scss/**/*.scss', scssTask);
|
|
gulp.watch('src/js/**/*.js', gulp.series(lintJsTask, jsDevTask));
|
|
gulp.watch('src/images/*', imagesTask);
|
|
gulp.watch('src/data/**/*.json', twigTask);
|
|
gulp.watch('src/assets/**/*', copyAssetsTask);
|
|
gulp.watch('src/favicon.ico', copyFaviconTask);
|
|
gulp.watch('src/icons/**/*.svg', gulp.series(svgSpriteTask, twigTask)); // Watch for changes in SVG icons
|
|
gulp.watch('src/fonts/**/*', copyFontsTask); // Watch for changes in fonts
|
|
};
|
|
|
|
const devBuild = gulp.series(cleanTask, svgSpriteTask, gulp.parallel(scssTask, jsDevTask, imagesTask, copyAssetsTask, copyFaviconTask, copyFontsTask), twigTask);
|
|
|
|
export const build = gulp.series(cleanTask, lintJsTask, svgSpriteTask, twigTask, gulp.parallel(scssTask, jsDevTask, imagesTask, copyAssetsTask, copyFaviconTask, copyFontsTask));
|
|
export const buildProd = gulp.series(cleanTask, lintJsTask, svgSpriteTask, twigTask, gulp.parallel(scssProdTask, jsTask, jsMinTask, imagesProdTask, copyAssetsTask, copyFaviconTask, copyFontsTask), revTask, revReplaceTask, screenshotsTask);
|
|
export const screenshots = screenshotsTask;
|
|
export default gulp.series(devBuild, watchTask);
|