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 preserveDirectories option #353

Closed
wants to merge 3 commits into from

Conversation

gijsroge
Copy link

@gijsroge gijsroge commented Apr 29, 2020

Fixes #191

If the preserveDirectories is set the output will match the directory structure from the input files.

Another possibility would be to introduce a breaking change and make this the default behaviour as that's what I would expect, but maybe i'm biased as I need this feature in a current project 😄

Given: assets/images/1.jpg, assets/images/nested/2.svg, assets/images/nested/nested/3.webp

It will detect that assets/images is the basePath and will not copy over these directories to the destination.

imagemin(['assets/images/**/*.{jpg,svg,webp}'], {
	plugins: [imageminJpegtran(), imageminWebp(), imageminSvgo()],
	destination: 'dest',
	preserveDirectories: true
});

Our output would be dest/1.jpg, dest/nested/assets/2.svg, dest/nested/nested/3.webp

cc/ #293 #262 #225 #213 #196 #192

@gijsroge
Copy link
Author

gijsroge commented Apr 29, 2020

removed

@gijsroge gijsroge force-pushed the feature/preserve-directories branch from 86ae9a1 to 8c9e24f Compare April 30, 2020 01:07
@gijsroge gijsroge marked this pull request as ready for review April 30, 2020 01:16
@gijsroge gijsroge force-pushed the feature/preserve-directories branch from 8c9e24f to bfd7c54 Compare April 30, 2020 10:19
@1000ch 1000ch requested a review from sindresorhus June 9, 2020 05:54
@rolbr
Copy link

rolbr commented Jun 17, 2020

@gijsroge
Sweet, exactly what I was looking for! 🥳

However, I encountered a bug that would not preserve directory structure for the first subdirectory.

Script:

(async () => {
	const files = await imagemin(['input_dir/**/*.{jpg,jpeg,png,svg}'], {
		destination: 'output_dir',
		preserveDirectories: true,
		...

Files/ directories:

⨽ input_dir
   ⊢ sub_dir_1
   ∣  ⨽ files 1…N
   ⨽ sub_dir_2
      ⨽ files 1…N

All files in input_dir/sub_dir_1 would be written to output_dir/ whereas
files in input_dir/sub_dir_2 would be written to output_dir/sub_dir_2.

Is this something you can reproduce?

@glassdimlygr
Copy link

glassdimlygr commented Jul 20, 2020

I can't reproduce the skipping of the first directory as reported by @rolbr. For me it works great.

I can say that when I was on the master branch of gijsroge/imagemin, it did not function. It was necessary to check out the feature/preserve-directories branch for this to work.

@yuceltoluyag
Copy link

ty save my life <3 @gijsroge

index.js Outdated
@@ -33,6 +33,10 @@ const handleFile = async (sourcePath, {destination, plugins = []}) => {
return returnValue;
}

if (preserveDirectories) {
returnValue.destinationPath = path.join(path.dirname(destinationPath), sourcePath.replace(baseDirectory, ''));
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't think using .replace will work cross-platform. Use the path related methods for path manipulation.

Copy link
Author

Choose a reason for hiding this comment

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

Sourcepath is just a string generated from "globby" where I need to remove the baseDirectory from. I can't find anything path related to do this. So I assume this is just fine, if not, could you point me in the right direction?

index.js Outdated
@@ -45,13 +49,14 @@ module.exports = async (input, {glob = true, ...options} = {}) => {
}

const filePaths = glob ? await globby(input, {onlyFiles: true}) : input;
const baseDirectory = path.dirname(filePaths[0]);
Copy link
Contributor

Choose a reason for hiding this comment

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

Why does the first file path decide the base directory? This should be documented.

Copy link
Author

Choose a reason for hiding this comment

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

readme.md Outdated Show resolved Hide resolved
test.js Outdated Show resolved Hide resolved
@sindresorhus sindresorhus changed the title Add ability to preserve your directory structure in the output. Add preserveDirectories option Aug 10, 2020
@yellow1912
Copy link

What is the status with this PR? Can we have it merged soon?

@gijsroge
Copy link
Author

@yellow1912 i'm picking this back up in the next few days.

Base automatically changed from master to main January 25, 2021 21:10
xaviervalarino added a commit to xaviervalarino/portfolio that referenced this pull request Feb 18, 2021
Getting the build script to handle this was more trouble than it should
have been. `imagemin` has a 4 year old merge request[1] to handle
recursing into subdirectories...
As a work around when images are batched, the script loops over all the
files in the image dir, running them in parallel groups of 4 (to speed
things up, but not lock up the CPU).

1: imagemin/imagemin#353
@misaka00251
Copy link

Hey, just asking..What's the status of this PR?

@illycz
Copy link

illycz commented Mar 7, 2021

Any news about PR?

@kosssi
Copy link

kosssi commented Apr 29, 2021

This feature is essential 🎉

I use this command while waiting:

find ./static -type f | xargs -I % sh -c 'imagemin % -o $(dirname %)'

Thanks for imagemin 👍

@leesei
Copy link

leesei commented Jun 3, 2021

I've implemented something similar locally.

Concerning @sindresorhus's question on "Why does the first file path decide the base directory? This should be documented.", how about we only enable preserveDirectories for glob inputs?
Then we rather than passing baseDirectory, we just need to:

let destinationPath = destination ? path.join(destination, preserveDirectories? sourcePath: path.basename(sourcePath)) : undefined;

@price84
Copy link

price84 commented Oct 27, 2021

Any movement?

* rebase with upstream
* add clarification what basePath does
* make basePath configurable
@gijsroge
Copy link
Author

gijsroge commented Oct 27, 2021

So yeah, days turned into weeks, weeks turned into months, months turned into years. Sorry about the delay :(

I addressed most of the issues + rebased with main, care to re-review? cc/ @1000ch @sindresorhus

@gijsroge
Copy link
Author

gijsroge commented Oct 27, 2021

I've implemented something similar locally.

Concerning @sindresorhus's question on "Why does the first file path decide the base directory? This should be documented.", how about we only enable preserveDirectories for glob inputs? Then we rather than passing baseDirectory, we just need to:

let destinationPath = destination ? path.join(destination, preserveDirectories? sourcePath: path.basename(sourcePath)) : undefined;

There is no solid way to detect if someone is using a glob or not even if glob:true they can still use ['image.jpg', 'assets/images/image.jpg']. So the most obvious thing to do was make it configurable imo.

@@ -35,6 +35,10 @@ const handleFile = async (sourcePath, {destination, plugins = []}) => {
return returnValue;
}

if (preserveDirectories) {
returnValue.destinationPath = path.join(destination, path.parse(sourcePath).dir.replace(basePath, ''), path.basename(destinationPath));
Copy link
Contributor

Choose a reason for hiding this comment

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

Use path.dirname

preserveDirectories: true,
});
```
- `assets/images/1.jpg` -> `dist/1.jpg`
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
- `assets/images/1.jpg` -> `dist/1.jpg`
- `assets/images/1.jpg` `dist/1.jpg`

@sindresorhus
Copy link
Contributor

Tests are failing on Windows.

@pumano
Copy link

pumano commented Nov 23, 2021

@gijsroge thank you for that very important feature! Hope it will be merged soon!

@eBaeza
Copy link

eBaeza commented Mar 25, 2022

Very important feature! Hope it will be merged soon!

@rtatarinov
Copy link

Any updates about it?

@okinawaa
Copy link

Very important feature! Hope it will be merged soon!!!

@1ewiswarren
Copy link

is this not being worked on anymore?

@Shayan-To
Copy link

Any progress? This is really necessary.

@tofran
Copy link

tofran commented Mar 7, 2023

@Shayan-To @eBaeza, @rtatarinov, etc

Please refrain from making such comments. There are plenty of people subscribed to threads and this kind of comment just spams their inbox. Please only comment if you have something to add to the discussion.

If this is so "necessary" feel free to contribute with valuable help. This might even include making a PR to the fork, helping the original author.

Thank you.

@saeidzebardast
Copy link

Any progress on this?

Kristinita added a commit to Kristinita/imagemin-cli that referenced this pull request Feb 11, 2024
@sindresorhus
Copy link
Contributor

Closing for lack of activity from OP.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Output ignores input folder structure