@ecopages/image-processor 0.2.1-beta.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +27 -10
- package/package.json +25 -15
- package/src/component/html.js +12 -6
- package/src/component/jsx.d.ts +12 -0
- package/src/component/jsx.js +18 -0
- package/src/component/react.js +17 -10
- package/src/constants.js +5 -4
- package/src/image-plugins.d.ts +3 -11
- package/src/image-plugins.js +40 -29
- package/src/image-processor.d.ts +7 -1
- package/src/image-processor.js +148 -135
- package/src/image-renderer.d.ts +1 -1
- package/src/image-renderer.js +222 -220
- package/src/image-runtime-state.d.ts +20 -0
- package/src/image-runtime-state.js +59 -0
- package/src/image-types.d.ts +3 -0
- package/src/image-utils.js +109 -98
- package/src/index.js +3 -3
- package/src/plugin.d.ts +17 -19
- package/src/plugin.js +275 -261
- package/src/types.js +1 -0
- package/src/utils.js +24 -25
- package/src/bun-plugins.d.ts +0 -22
- package/src/bun-plugins.js +0 -33
package/src/image-utils.js
CHANGED
|
@@ -1,103 +1,114 @@
|
|
|
1
|
-
import { DEFAULT_LAYOUT } from
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
* This approach ensures that the browser will select the correct image variant based on the viewport width.
|
|
30
|
-
* @see https://developer.mozilla.org/en-US/docs/Learn/HTML/Multimedia_and_embedding/Responsive_images#resolution_switching_different_sizes
|
|
31
|
-
* @param {ImageVariant[]} variants - Array of processed image variants
|
|
32
|
-
* @returns {string} sizes attribute string
|
|
33
|
-
* @private
|
|
34
|
-
*/
|
|
35
|
-
static generateSizes(variants) {
|
|
36
|
-
if (!variants?.length) return "";
|
|
37
|
-
const sortedVariants = [...variants].sort((a, b) => b.width - a.width);
|
|
38
|
-
const [largest, ...rest] = sortedVariants;
|
|
39
|
-
const conditions = [
|
|
40
|
-
`(min-width: ${largest.width}px) ${largest.width}px`,
|
|
41
|
-
...rest.map((variant) => {
|
|
42
|
-
if (variant.width >= ImageUtils.BREAKPOINTS.desktop) {
|
|
43
|
-
return `(min-width: ${variant.width}px) ${ImageUtils.VIEWPORT_SIZES.desktop}`;
|
|
44
|
-
}
|
|
45
|
-
if (variant.width >= ImageUtils.BREAKPOINTS.tablet) {
|
|
46
|
-
return `(min-width: ${variant.width}px) ${ImageUtils.VIEWPORT_SIZES.tablet}`;
|
|
47
|
-
}
|
|
48
|
-
return null;
|
|
49
|
-
}).filter(Boolean),
|
|
50
|
-
ImageUtils.VIEWPORT_SIZES.mobile
|
|
51
|
-
];
|
|
52
|
-
return conditions.join(", ");
|
|
53
|
-
}
|
|
54
|
-
/**
|
|
55
|
-
* Generates a styles string based on image layout and config
|
|
56
|
-
* @param {ImageLayout} layout - Image layout type
|
|
57
|
-
* @param {LayoutAttributes} config - Image layout configuration
|
|
58
|
-
* @returns {string} styles string
|
|
59
|
-
* @private
|
|
60
|
-
*/
|
|
61
|
-
static generateLayoutStyles(config) {
|
|
62
|
-
const layout = config.layout || ImageUtils.DEFAULT_LAYOUT;
|
|
63
|
-
const styles = [["object-fit", "cover"]];
|
|
64
|
-
if (config.aspectRatio) {
|
|
65
|
-
styles.push(["aspect-ratio", config.aspectRatio]);
|
|
1
|
+
import { DEFAULT_LAYOUT } from './constants.js';
|
|
2
|
+
/**
|
|
3
|
+
* ImageUtils
|
|
4
|
+
* This class contains utility methods for working with images
|
|
5
|
+
* It contains methods for generating srcset, sizes and styles attributes for the image element
|
|
6
|
+
*/
|
|
7
|
+
export class ImageUtils {
|
|
8
|
+
static BREAKPOINTS = {
|
|
9
|
+
desktop: 1024,
|
|
10
|
+
tablet: 768,
|
|
11
|
+
};
|
|
12
|
+
static VIEWPORT_SIZES = {
|
|
13
|
+
desktop: '70vw',
|
|
14
|
+
tablet: '80vw',
|
|
15
|
+
mobile: '100vw',
|
|
16
|
+
};
|
|
17
|
+
static DEFAULT_LAYOUT = DEFAULT_LAYOUT;
|
|
18
|
+
/**
|
|
19
|
+
* Generates a srcset string from processed image variants using relative paths
|
|
20
|
+
* @param {ImageVariant[]} variants - Array of processed image variants
|
|
21
|
+
* @returns {string} srcset attribute string
|
|
22
|
+
* @private
|
|
23
|
+
*/
|
|
24
|
+
static generateSrcset(variants) {
|
|
25
|
+
return variants
|
|
26
|
+
.sort((a, b) => b.width - a.width)
|
|
27
|
+
.map(({ src, width }) => `${src} ${width}w`)
|
|
28
|
+
.join(', ');
|
|
66
29
|
}
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
30
|
+
/**
|
|
31
|
+
* Generates sizes attribute based on image variants.
|
|
32
|
+
* Sizes are generated based on the variant widths and breakpoints.
|
|
33
|
+
* Here we use a smart approach to generate sizes based on the variant widths.
|
|
34
|
+
* We start with the largest variant and set a min-width condition for its width.
|
|
35
|
+
* Then we add conditions for each variant based on the viewport width.
|
|
36
|
+
* Finally, we add a catch-all for the smallest screens.
|
|
37
|
+
* This approach ensures that the browser will select the correct image variant based on the viewport width.
|
|
38
|
+
* @see https://developer.mozilla.org/en-US/docs/Learn/HTML/Multimedia_and_embedding/Responsive_images#resolution_switching_different_sizes
|
|
39
|
+
* @param {ImageVariant[]} variants - Array of processed image variants
|
|
40
|
+
* @returns {string} sizes attribute string
|
|
41
|
+
* @private
|
|
42
|
+
*/
|
|
43
|
+
static generateSizes(variants) {
|
|
44
|
+
if (!variants?.length)
|
|
45
|
+
return '';
|
|
46
|
+
const sortedVariants = [...variants].sort((a, b) => b.width - a.width);
|
|
47
|
+
const [largest, ...rest] = sortedVariants;
|
|
48
|
+
const conditions = [
|
|
49
|
+
`(min-width: ${largest.width}px) ${largest.width}px`,
|
|
50
|
+
...rest
|
|
51
|
+
.map((variant) => {
|
|
52
|
+
if (variant.width >= ImageUtils.BREAKPOINTS.desktop) {
|
|
53
|
+
return `(min-width: ${variant.width}px) ${ImageUtils.VIEWPORT_SIZES.desktop}`;
|
|
54
|
+
}
|
|
55
|
+
if (variant.width >= ImageUtils.BREAKPOINTS.tablet) {
|
|
56
|
+
return `(min-width: ${variant.width}px) ${ImageUtils.VIEWPORT_SIZES.tablet}`;
|
|
57
|
+
}
|
|
58
|
+
return null;
|
|
59
|
+
})
|
|
60
|
+
.filter(Boolean),
|
|
61
|
+
ImageUtils.VIEWPORT_SIZES.mobile,
|
|
62
|
+
];
|
|
63
|
+
return conditions.join(', ');
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Generates a styles string based on image layout and config
|
|
67
|
+
* @param {ImageLayout} layout - Image layout type
|
|
68
|
+
* @param {LayoutAttributes} config - Image layout configuration
|
|
69
|
+
* @returns {string} styles string
|
|
70
|
+
* @private
|
|
71
|
+
*/
|
|
72
|
+
static generateLayoutStyles(config) {
|
|
73
|
+
const layout = config.layout || ImageUtils.DEFAULT_LAYOUT;
|
|
74
|
+
const styles = [['object-fit', 'cover']];
|
|
75
|
+
if (config.aspectRatio) {
|
|
76
|
+
styles.push(['aspect-ratio', config.aspectRatio]);
|
|
89
77
|
}
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
78
|
+
switch (layout) {
|
|
79
|
+
case 'fixed':
|
|
80
|
+
if (config.width) {
|
|
81
|
+
styles.push(['width', `${config.width}px`], ['min-width', `${config.width}px`]);
|
|
82
|
+
}
|
|
83
|
+
if (config.height) {
|
|
84
|
+
styles.push(['height', `${config.height}px`], ['min-height', `${config.height}px`]);
|
|
85
|
+
}
|
|
86
|
+
break;
|
|
87
|
+
case 'constrained':
|
|
88
|
+
styles.push(['width', '100%']);
|
|
89
|
+
if (config.width && config.height) {
|
|
90
|
+
styles.push(['max-width', `${config.width}px`], ['max-height', `${config.height}px`]);
|
|
91
|
+
if (!config.aspectRatio) {
|
|
92
|
+
styles.push(['aspect-ratio', `${config.width}/${config.height}`]);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
else if (config.height) {
|
|
96
|
+
styles.push(['height', `${config.height}px`], ['min-height', `${config.height}px`]);
|
|
97
|
+
}
|
|
98
|
+
else if (config.width) {
|
|
99
|
+
styles.push(['max-width', `${config.width}px`]);
|
|
100
|
+
}
|
|
101
|
+
else if (!config.aspectRatio) {
|
|
102
|
+
styles.push(['aspect-ratio', `${config.attributes.width}/${config.attributes.height}`]);
|
|
103
|
+
}
|
|
104
|
+
break;
|
|
105
|
+
case 'full-width':
|
|
106
|
+
styles.push(['width', '100%']);
|
|
107
|
+
if (config.height) {
|
|
108
|
+
styles.push(['height', `${config.height}px`], ['min-height', `${config.height}px`]);
|
|
109
|
+
}
|
|
110
|
+
break;
|
|
95
111
|
}
|
|
96
|
-
|
|
112
|
+
return styles;
|
|
97
113
|
}
|
|
98
|
-
return styles;
|
|
99
|
-
}
|
|
100
114
|
}
|
|
101
|
-
export {
|
|
102
|
-
ImageUtils
|
|
103
|
-
};
|
package/src/index.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export * from
|
|
2
|
-
export * from
|
|
3
|
-
export * from
|
|
1
|
+
export * from './image-processor.js';
|
|
2
|
+
export * from './plugin.js';
|
|
3
|
+
export * from './types.js';
|
package/src/plugin.d.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* ImageProcessorPlugin
|
|
3
3
|
* @module @ecopages/image-processor
|
|
4
4
|
*/
|
|
5
|
-
import { Processor, type EcoBuildPlugin, type ProcessorConfig } from '@ecopages/core/
|
|
5
|
+
import { Processor, type EcoBuildPlugin, type ProcessorConfig } from '@ecopages/core/processor';
|
|
6
6
|
import { ImageProcessor } from './image-processor.js';
|
|
7
7
|
import type { ImageSize, ImageSpecifications } from './types.js';
|
|
8
8
|
/**
|
|
@@ -32,19 +32,18 @@ export interface ImageProcessorConfig {
|
|
|
32
32
|
* ImageMap
|
|
33
33
|
* This is the representation of the image map in the virtual module
|
|
34
34
|
*/
|
|
35
|
-
export type ImageMap
|
|
35
|
+
export type { ImageMap } from './image-runtime-state.js';
|
|
36
36
|
/**
|
|
37
37
|
* ImageProcessorPlugin
|
|
38
38
|
* A Processor for optimizing images.
|
|
39
39
|
*/
|
|
40
40
|
export declare class ImageProcessorPlugin extends Processor<ImageProcessorConfig> {
|
|
41
41
|
private processor;
|
|
42
|
-
private buildContributionsPrepared;
|
|
43
42
|
private resolvedConfig?;
|
|
44
43
|
processedImages: Record<string, ImageSpecifications>;
|
|
45
|
-
constructor(config: Omit<ProcessorConfig<ImageProcessorConfig>, 'name'
|
|
46
|
-
|
|
47
|
-
|
|
44
|
+
constructor(config: Omit<ProcessorConfig<ImageProcessorConfig>, 'name'>);
|
|
45
|
+
private handleImageChanges;
|
|
46
|
+
plugins(): EcoBuildPlugin[];
|
|
48
47
|
/**
|
|
49
48
|
* Replaces image-map contents without swapping the backing object.
|
|
50
49
|
*
|
|
@@ -54,22 +53,21 @@ export declare class ImageProcessorPlugin extends Processor<ImageProcessorConfig
|
|
|
54
53
|
*/
|
|
55
54
|
private replaceProcessedImages;
|
|
56
55
|
/**
|
|
57
|
-
*
|
|
58
|
-
* manifest.
|
|
56
|
+
* Resolves processor config and creates the sharp-backed worker instance.
|
|
59
57
|
*/
|
|
60
|
-
|
|
58
|
+
private initializeProcessor;
|
|
61
59
|
private getRuntimeVirtualModulePath;
|
|
62
60
|
private getGeneratedOutputPath;
|
|
63
|
-
private hasGeneratedOutputs;
|
|
64
|
-
private rehydrateGeneratedOutputs;
|
|
65
61
|
/**
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
* @returns
|
|
62
|
+
* Restores in-memory image state from previously generated dist artifacts.
|
|
63
|
+
*
|
|
64
|
+
* @returns `true` when state was restored without invoking sharp.
|
|
69
65
|
*/
|
|
70
|
-
private
|
|
66
|
+
private syncProcessedImagesFromDisk;
|
|
67
|
+
private ensureGeneratedOutputs;
|
|
68
|
+
private writeGeneratedFile;
|
|
71
69
|
/**
|
|
72
|
-
*
|
|
70
|
+
* Ensures optimized image outputs and virtual-module state exist on disk.
|
|
73
71
|
*/
|
|
74
72
|
setup(): Promise<void>;
|
|
75
73
|
/**
|
|
@@ -87,13 +85,13 @@ export declare class ImageProcessorPlugin extends Processor<ImageProcessorConfig
|
|
|
87
85
|
*/
|
|
88
86
|
private generateTypes;
|
|
89
87
|
/**
|
|
90
|
-
*
|
|
88
|
+
* Writes the ambient declaration package for `ecopages:images`.
|
|
91
89
|
*/
|
|
92
|
-
|
|
90
|
+
private writeVirtualModuleTypes;
|
|
93
91
|
/**
|
|
94
92
|
* Get the image processor instance.
|
|
95
93
|
* @returns The image processor instance.
|
|
96
94
|
*/
|
|
97
95
|
getProcessor(): ImageProcessor | undefined;
|
|
98
96
|
}
|
|
99
|
-
export declare const imageProcessorPlugin: (config: Omit<ProcessorConfig<ImageProcessorConfig>, "name"
|
|
97
|
+
export declare const imageProcessorPlugin: (config: Omit<ProcessorConfig<ImageProcessorConfig>, "name">) => ImageProcessorPlugin;
|