Solución:
¿Es una forma de comprimir imágenes manteniendo la estructura de carpetas?
La respuesta corta es no, no con imagemin-cli
imagemin, (la API imagemin-cli se basa en), no proporciona un mecanismo para preservar la estructura de la carpeta. Ver abierto Issue / feature-request # 191 en el repositorio de github de proyectos.
Solución
Una forma multiplataforma de lograr sus requisitos es escribir un node.js script de utilidad que utiliza la API imagemin directamente. Tan eficazmente … cree su propia herramienta CLI que se puede ejecutar a través de npm-scripts
.
Las siguientes esencias muestran cómo se puede lograr esto …
imagemin.js
La utilidad nodo El guión es el siguiente:
#!/usr/bin/env node
'use strict';
var path = require('path');
var readline = require('readline');
var Imagemin = require('imagemin');
var outdir = process.env.PWD; // Default output folder.
var verbose = false; // Default no logging.
// The folder name specified MUST exist in the `glob` pattern of the npm-script.
var DEST_SUBROOT_FOLDER = 'images';
// Nice ticks for logging aren't supported via cmd.exe
var ticksymbol = process.env.npm_config_shell.indexOf('bash') !== -1 ? '✔' : '√';
var rl = readline.createInterface({
input: process.stdin,
output: null,
terminal: false
});
// Handle the optional `-o` argument for the destination folder.
if (process.argv.indexOf('-o') !== -1) {
outdir = process.argv[process.argv.indexOf('-o') + 1];
}
// Handle the optional `-v` argument for verbose logging.
if (process.argv.indexOf('-v') !== -1) {
verbose = true;
}
/**
* Utilizes the Imagemin API to create a new instance for optimizing each image.
* @param {String} srcpath - The filepath of the source image to optimize.
* @param {String} destpath - The destination path to save the resultant file.
* @param {Function} - The relevent `use` plugin (jpegtran|optipng|gifsicle).
*/
function imagemin(srcpath, destpath, plugin) {
var im = new Imagemin()
.src(srcpath)
.dest(destpath)
.use(plugin);
im.optimize(function (err, file) {
if (err) {
console.error('Error: ' + err);
process.exit(1);
}
if (file && verbose) {
console.log('x1b[32m%sx1b[0m', ticksymbol, destpath);
}
});
}
/**
* Obtains the destination path and file suffix from the original source path.
* @param {String} srcpath - The filepath for the image to optimize.
* @return {{dest: String, type: String}} dest path and ext (.jpg|.png|.gif).
*/
function getPathInfo(srcpath) {
var ext = path.extname(srcpath),
parts = srcpath.split(path.sep),
subpath = parts.slice(parts.indexOf(DEST_SUBROOT_FOLDER), parts.length);
subpath.unshift(outdir);
return {
dest: path.normalize(subpath.join(path.sep)),
ext: ext
};
}
/**
* Triggers the relevent imagemin process according to file suffix (jpg|png|gif).
* @param {String} srcpath - The filepath of the image to optimize.
*/
function optimizeImage(srcpath) {
var p = getPathInfo(srcpath);
switch (p.ext) {
case '.jpg':
imagemin(srcpath, p.dest, Imagemin.jpegtran({ progressive: true }));
break;
case '.png':
imagemin(srcpath, p.dest, Imagemin.optipng({ optimizationLevel: 5 }));
break;
case '.gif':
imagemin(srcpath, p.dest, Imagemin.gifsicle({ interlaced: true }));
break;
}
}
// Read each line from process.stdin (i.e. the filepath)
rl.on('line', function(srcpath) {
optimizeImage(srcpath);
});
Nota: El código anterior usa la versión 1.0.5
de El imagemin
API y no la última versión – ¿Por qué? Consulte el punto 1 en la sección Notas adicionales a continuación).
Desinstalar e instalar nuevos paquetes
- Primero desinstalar
imagemin-cli
ya que ya no es necesario:
$ npm un -D imagemin-cli
- Siguiente instalar la versión de imagemin
1.0.5
(Este es un paquete más antiguo, por lo que puede tardarnpm
más de instalar de lo habitual)
$ npm i -D [email protected]
- Luego instale cli-glob. Esto se utilizará para especificar el patrón global para que coincida con las imágenes para optimizar.
$ npm i -D cli-glob
npm-scripts
Actualiza tu npm-scripts
como sigue:
...
"scripts": {
"imagemin:prod": "glob "app/src/images/**/*.{png,jpg,gif}" | node bin/imagemin -v -o dist",
"imagemin:dev": "glob "app/src/images/**/*.{png,jpg,gif}" | node bin/imagemin -v -o .tmp",
...
},
...
Nota: Para optimizar las imágenes usando los gists que se muestran arriba, no es necesario usar los dos scripts llamados copy:prod
y copy:dev
mostrado en su publicación / pregunta original)
-
los
glob "app/src/...
parte del script anterior usa cli-glob para hacer coincidir los archivos fuente de imagen necesarios. -
Luego, los caminos se canalizan al
imagemin.js
secuencia de comandos del nodo de utilidad. -
Cuando el
-v
(detallado) argumento / bandera se incluye, luego cada imagen procesada se registra en la consola. Para omitir el registro, simplemente elimine el-v
bandera. -
los
-o
El argumento / bandera (de salida) se utiliza para especificar el nombre de la carpeta de destino. P.ejdist
o.tmp
. Cuando el valor de-o
Si se omite, las imágenes resultantes se envían al directorio raíz del proyecto.
Notas adicionales:
-
La razón para usar
imagemin
la versión 1.0.5 se debe a que esta API permitesrc
valor que se especificará como una única ruta de archivo. En versiones superiores a2.0.0
la API espera elsrc
value para ser un patrón glob como se muestra en la última versión 5.2.2. -
Las esencias anteriores asumen
imagemin.js
se guarda en una carpeta llamadabin
que existe en la misma carpeta quepackage.json
. Se puede cambiar a un nombre preferido, o una carpeta invisible prefijándolo con un punto [.] p.ej.scripts
o.bin
. Elija lo que elija, deberá actualizar la ruta al script ennpm-scripts
respectivamente.
Actualización 2020
Hay una solicitud de extracción no fusionada (a mediados de junio de 2020) de Gijs Rogé que permite preservar la estructura del directorio en el directorio de salida.
Puede instalar módulos npm que aún no figuran en el registro instalando directamente desde Github, haciendo referencia a un repositorio e incluso un compromiso específico:
npm install https://github.com/<username>/<repository>#<commit> --save-dev
Para instalar imagemin con la corrección de Gijs Rogé, ejecute …
npm install https://github.com/imagemin/imagemin#bfd7c547045f68ed92243c6a772f6265a08a687f --save-dev
… y habilite la nueva opción en su script configurando preserveDirectories: true
:
// Note: imports and plugin configs have been omitted for brevity
const imagemin = require('imagemin');
const imageminMozjpeg = require('imagemin-mozjpeg');
...
(async () => {
const files = await imagemin(['input_dir/**/*.{jpg,jpeg,png,svg}'], {
destination: 'output_dir/',
✨preserveDirectories: true,
plugins: [
imageminMozjpeg( ... ),
imageminPngquant( ... ),
imageminSvgo( ... )
]
});
A .jpg
encontrado en input_dir/some/sub/dir/image.jpg
ahora será procesado y escrito a output_dir/input_dir/some/sub/dir/image.jpg
.
Usar destination: '.'
para sobrescribir los archivos originales en su lugar.