-
Notifications
You must be signed in to change notification settings - Fork 18
fix (webpack-image-sizes-plugin): optimizes image generation and proc… #464
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
base: master
Are you sure you want to change the base?
Conversation
…essing Improves the image generation process by adding change detection based on timestamps to avoid unnecessary rebuilds. Refactors TPL parsing to extract comprehensive size and crop information, ensuring accurate image configuration. Enhances default image generation by skipping existing images and updating only outdated ones. Cleans up image locations data for output by removing internal properties.
Reviewer's GuideOptimizes the image generation process by adding timestamp-based change detection, refactoring TPL parsing for accurate size and crop extraction, enhancing default image generation to skip or update files based on timestamps, cleaning up output image location data, and unifying directory existence checks with improved error handling. Sequence Diagram for Image Generation Skip LogicsequenceDiagram
participant C as Compiler
participant P as WebpackImageSizesPlugin
participant FS as FileSystem
C->>P: emit hook (triggers runGeneration)
P->>P: shouldSkipGeneration(confImgPath, sizesPath, tplPath)
alt lastGenerationTime is 0
P-->>P: false (don't skip)
else
P->>FS: statSync(sizesPath / tplPath / files in dirs)
FS-->>P: file/dir stats (mtime)
P->>P: Compare mtime with lastGenerationTime
alt any file/dir modified since lastGenerationTime
P-->>P: false (don't skip)
else no changes
P-->>P: true (skip)
end
end
P-->>P: result from shouldSkipGeneration()
alt result is true (skip generation)
P->>P: log("No changes detected, skipping generation")
P->>C: callback() (generation skipped)
else result is false (proceed with generation)
P->>P: log("Starting WebpackImageSizesPlugin generation...")
P->>P: Perform image locations and sizes generation
P->>P: lastGenerationTime = Date.now()
P->>P: cleanImageLocationsForOutput()
P->>FS: writeFileSync(imageLocationsPath, cleanedImageLocations)
P->>FS: writeFileSync(imageSizesPath, imageSizes)
opt generateDefaultImages is true
P->>P: generateDefaultImages(compiler.context, imageSizes)
end
P->>C: callback() (generation done)
end
Sequence Diagram for Optimized Default Image Generation ProcesssequenceDiagram
participant P as WebpackImageSizesPlugin
participant FS as FileSystem
participant Sharp as SharpLibrary
P->>P: generateDefaultImages(context, imageSizes)
loop for each sizeKey in imageSizes
P->>P: Determine outputPath for image
P->>FS: existsSync(outputPath)
alt outputPath exists
FS-->>P: true
P->>FS: statSync(sourceImagePath)
FS-->>P: sourceStats (mtime)
P->>FS: statSync(outputPath)
FS-->>P: outputStats (mtime)
alt sourceStats.mtime <= outputStats.mtime (image is up-to-date)
P->>P: log("Skipped existing image")
else source is newer or timestamp check failed (image outdated)
P->>P: log("Updating/Regenerating outdated image")
P->>Sharp: sharp(sourceImagePath).resize().toFile(outputPath)
Sharp-->>P: Image processed
P->>P: log("Generated/Updated image")
end
else outputPath does not exist (new image)
FS-->>P: false
P->>P: log("Generating new image")
P->>Sharp: sharp(sourceImagePath).resize().toFile(outputPath)
Sharp-->>P: Image processed
P->>P: log("Generated new image")
end
end
P->>P: log("Default image generation completed!")
Updated Class Diagram for WebpackImageSizesPluginclassDiagram
class WebpackImageSizesPlugin {
+options: Object
+lastGenerationTime: number
+constructor(options)
+apply(compiler): void
+shouldSkipGeneration(confImgPath, sizesPath, tplPath): boolean
+generateImageSizes(sizesPath, tplPath, imageLocations): Array
+extractSizesFromTPLFiles(tplPath, imageLocations, imageSizesObj, allSizes): void
+parseTPLContent(tplContent): Object
+generateImageLocations(sizesPath, tplPath): Array
+cleanImageLocationsForOutput(imageLocations): Array
+generateDefaultImages(context, imageSizes): Promise~void~
+log(level, message, ...args): void
+deleteRemovedImages(outputDir, currentFiles): void
+getSharpFormatOptions(format): Object
+checkForRemovedFiles(confImgPath, imageLocationsPath, imageSizesPath): void
}
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey @firestar300 - I've reviewed your changes and they look great!
Here's what I looked at during the review
- 🟡 General issues: 1 issue found
- 🟢 Security: all looks good
- 🟢 Testing: all looks good
- 🟢 Documentation: all looks good
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
compiler.hooks.watchRun.tapAsync('WebpackImageSizesPlugin', (compiler, callback) => { | ||
this.log('log', '👀 Watch mode: checking for conf-img changes...') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
issue (bug_risk): Removal of watchRun hook may break incremental builds in watch mode.
If removal is intentional, verify that the emit hook reliably triggers on every rebuild in watch mode, or consider restoring watchRun to ensure updates are not missed.
const result = { | ||
srcsets: srcsets, | ||
default_img: `default-${largestSize.size.replace('img-', '')}.${this.options.defaultImageFormat}`, | ||
img_base: largestSize.size, | ||
sizeCropMap: sizeCropMap, // Include crop mapping | ||
} | ||
|
||
return result |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
suggestion (code-quality): Inline variable that is immediately returned (inline-immediately-returned-variable
)
const result = { | |
srcsets: srcsets, | |
default_img: `default-${largestSize.size.replace('img-', '')}.${this.options.defaultImageFormat}`, | |
img_base: largestSize.size, | |
sizeCropMap: sizeCropMap, // Include crop mapping | |
} | |
return result | |
return { | |
srcsets: srcsets, | |
default_img: `default-${largestSize.size.replace('img-', '')}.${this.options.defaultImageFormat}`, | |
img_base: largestSize.size, | |
sizeCropMap: sizeCropMap, // Include crop mapping | |
}; | |
Explanation
Something that we often see in people's code is assigning to a result variableand then immediately returning it.
Returning the result directly shortens the code and removes an unnecessary
variable, reducing the mental load of reading the function.
Where intermediate variables can be useful is if they then get used as a
parameter or a condition, and the name can act like a comment on what the
variable represents. In the case where you're returning it from a function, the
function name is there to tell you what the result is, so the variable name
is unnecessary.
const cleanedLocation = { | ||
srcsets: location.srcsets.map((srcset) => ({ | ||
srcset: srcset.srcset, | ||
size: srcset.size, | ||
// Remove crop property from srcsets | ||
})), | ||
default_img: location.default_img, | ||
img_base: location.img_base, | ||
// Remove sizeCropMap property | ||
} | ||
|
||
return cleanedLocation |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
suggestion (code-quality): Inline variable that is immediately returned (inline-immediately-returned-variable
)
const cleanedLocation = { | |
srcsets: location.srcsets.map((srcset) => ({ | |
srcset: srcset.srcset, | |
size: srcset.size, | |
// Remove crop property from srcsets | |
})), | |
default_img: location.default_img, | |
img_base: location.img_base, | |
// Remove sizeCropMap property | |
} | |
return cleanedLocation | |
return { | |
srcsets: location.srcsets.map((srcset) => ({ | |
srcset: srcset.srcset, | |
size: srcset.size, | |
// Remove crop property from srcsets | |
})), | |
default_img: location.default_img, | |
img_base: location.img_base, | |
// Remove sizeCropMap property | |
}; | |
Explanation
Something that we often see in people's code is assigning to a result variableand then immediately returning it.
Returning the result directly shortens the code and removes an unnecessary
variable, reducing the mental load of reading the function.
Where intermediate variables can be useful is if they then get used as a
parameter or a condition, and the name can act like a comment on what the
variable represents. In the case where you're returning it from a function, the
function name is there to tell you what the result is, so the variable name
is unnecessary.
…essing
Improves the image generation process by adding change detection based on timestamps to avoid unnecessary rebuilds.
Refactors TPL parsing to extract comprehensive size and crop information, ensuring accurate image configuration.
Enhances default image generation by skipping existing images and updating only outdated ones.
Cleans up image locations data for output by removing internal properties.
Summary by Sourcery
Optimize WebpackImageSizesPlugin by adding timestamp-based rebuild skipping, enhancing TPL parsing with crop mapping, cleaning output data, and streamlining default image generation and build hooks
Enhancements: