Skip to content

Instantly share code, notes, and snippets.

@JCervantesB
Last active January 26, 2026 16:34
Show Gist options
  • Select an option

  • Save JCervantesB/460c5e865548dd209da3e95cf56bbf6e to your computer and use it in GitHub Desktop.

Select an option

Save JCervantesB/460c5e865548dd209da3e95cf56bbf6e to your computer and use it in GitHub Desktop.
Gulpfile bienesraices con sharp

Estas son las extensiones necesarias a instalar para poder utilizar esta version con sharp.

Por lo que te proporciono los comandos para instalarlas:

npm install -D cssnano [email protected] gulp-autoprefixer gulp-avif gulp-cache gulp-clean gulp-concat gulp-notify gulp-postcss gulp-rename gulp-sass gulp-sourcemaps gulp-terser-js gulp-webp gulp-plumber through2 sass terser

En cuanto a Sharp aunque es una herramienta de desarrollo, Gulp lo necesita en tiempo de ejecución, por lo que necesitamos instalarlo globalmente.

npm install sharp
const { src, dest, watch, series, parallel } = require('gulp');
const sass = require('gulp-sass')(require('sass'));
const autoprefixer = require('autoprefixer');
const postcss = require('gulp-postcss');
const sourcemaps = require('gulp-sourcemaps');
const cssnano = require('cssnano');
const concat = require('gulp-concat');
const terser = require('gulp-terser-js');
const rename = require('gulp-rename');
const cache = require('gulp-cache');
const notify = require('gulp-notify');
const sharp = require('sharp');
const path = require('path');
const plumber = require('gulp-plumber');
const through2 = require('through2');
// Rutas
const paths = {
scss: 'src/scss/**/*.scss',
js: 'src/js/**/*.js',
imagenes: 'src/img/**/*.{jpg,jpeg,png,webp}'
};
// Compilar Sass
function css() {
return src(paths.scss)
.pipe(sourcemaps.init())
.pipe(
sass({
quietDeps: true,
silenceDeprecations: ['import']
}).on('error', sass.logError)
)
.pipe(postcss([autoprefixer(), cssnano()]))
.pipe(sourcemaps.write('.'))
.pipe(dest('build/css'));
}
// Procesar JavaScript
function javascript() {
return src(paths.js)
.pipe(sourcemaps.init())
.pipe(concat('bundle.js'))
.pipe(terser())
.pipe(rename({ basename: 'bundle.min' }))
.pipe(dest('build/js'))
.pipe(rename({ extname: '.map' }))
.pipe(dest('build/js'));
}
// Transform para usar Sharp dentro de Gulp
function sharpTransform() {
return through2.obj(async (file, _, cb) => {
if (file.isNull()) return cb(null, file);
if (file.isStream()) return cb(new Error('Streams no soportados'));
const ext = path.extname(file.path).toLowerCase();
try {
// Si ya es WebP, solo reoptimiza
if (ext === '.webp') {
const buffer = await sharp(file.contents)
.webp({ quality: 80, effort: 4 })
.toBuffer();
file.contents = buffer;
return cb(null, file);
}
// Para JPG/PNG/JPEG optimiza sin cambiar formato
let pipeline = sharp(file.contents, { failOnError: false });
if (ext === '.jpg' || ext === '.jpeg') {
pipeline = pipeline.jpeg({
quality: 80,
progressive: true,
mozjpeg: true
});
} else if (ext === '.png') {
pipeline = pipeline.png({
quality: 80,
compressionLevel: 9,
effort: 7,
palette: true
});
}
const buffer = await pipeline.toBuffer();
file.contents = buffer;
cb(null, file);
} catch (err) {
cb(err);
}
});
}
// Optimizar imágenes originales con Sharp
function imagenes() {
return src('src/img/**/*.{jpg,jpeg,png,webp}', { allowEmpty: true })
.pipe(plumber())
.pipe(cache(sharpTransform()))
.pipe(dest('build/img'))
.pipe(notify({ message: 'Imagen optimizada: <%= file.relative %>' }));
}
// Función auxiliar: convertir a WebP
async function convertirWebp(ruta) {
const outputPath = ruta
.replace('src/img', 'build/img')
.replace(/\.(jpe?g|png)$/i, '.webp');
await sharp(ruta)
.webp({ quality: 50, effort: 4 })
.toFile(outputPath);
}
// Función auxiliar: convertir a AVIF
async function convertirAvif(ruta) {
const outputPath = ruta
.replace('src/img', 'build/img')
.replace(/\.(jpe?g|png)$/i, '.avif');
await sharp(ruta)
.avif({ quality: 50, effort: 4 })
.toFile(outputPath);
}
// Tarea: procesar imágenes y generar formatos modernos
async function procesarImagenes(done) {
await imagenes();
done();
}
// Watch: vigila cambios y ejecuta tareas
function watchArchivos() {
watch(paths.scss, css);
watch(paths.js, javascript);
watch(paths.imagenes, procesarImagenes);
// Vigila cambios en JPG/PNG para generar WebP y AVIF
watch('src/img/**/*.{jpg,jpeg,png}', async (event) => {
const ruta = event.path || event;
await convertirWebp(ruta);
await convertirAvif(ruta);
console.log(`Formatos generados para: ${path.basename(ruta)}`);
});
}
// Exportar tareas
exports.css = css;
exports.javascript = javascript;
exports.imagenes = imagenes;
exports.procesarImagenes = procesarImagenes;
exports.watchArchivos = watchArchivos;
// Tarea por defecto
exports.default = parallel(css, javascript, procesarImagenes, watchArchivos);
{
"name": "bienesraices",
"version": "1.0.0",
"description": "Curso Desarrollo Web Completo",
"main": "gulpfile.js",
"scripts": {
"sass": "sass --watch src/scss:build/css",
"dev": "gulp"
},
"author": "Juan De La Torre",
"license": "ISC",
"devDependencies": {
"cssnano": "^5.1.0",
"gulp": "^4.0.2",
"gulp-autoprefixer": "^8.0.0",
"gulp-avif": "^1.1.0",
"gulp-cache": "^1.1.3",
"gulp-clean": "^0.4.0",
"gulp-concat": "^2.6.1",
"gulp-notify": "^4.0.0",
"gulp-plumber": "^1.2.1",
"gulp-postcss": "^9.0.1",
"gulp-rename": "^2.0.0",
"gulp-sass": "^5.1.0",
"gulp-sourcemaps": "^3.0.0",
"gulp-terser-js": "^5.2.2",
"gulp-webp": "^4.0.1",
"node-sass": "^7.0.1",
"sass": "^1.49.9",
"terser": "^4.8.0",
"through2": "^4.0.2"
},
"dependencies": {
"sharp": "^0.34.3"
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment