@ecopages/image-processor 0.2.0-alpha.4 → 0.2.0-alpha.7
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/CHANGELOG.md +7 -8
- package/README.md +41 -151
- package/package.json +3 -3
- package/src/bun-plugins.d.ts +1 -1
- package/src/bun-plugins.js +1 -1
- package/src/bun-plugins.ts +2 -2
- package/src/component/html.d.ts +1 -1
- package/src/component/html.js +1 -1
- package/src/component/html.ts +1 -1
- package/src/component/react.d.ts +1 -1
- package/src/component/react.js +1 -1
- package/src/component/react.ts +1 -1
- package/src/constants.d.ts +1 -1
- package/src/constants.ts +1 -1
- package/src/image-plugins.d.ts +1 -1
- package/src/image-plugins.js +1 -1
- package/src/image-plugins.ts +2 -2
- package/src/image-processor.d.ts +2 -2
- package/src/image-processor.js +1 -1
- package/src/image-processor.ts +3 -3
- package/src/image-renderer.d.ts +1 -1
- package/src/image-renderer.js +2 -2
- package/src/image-renderer.ts +3 -3
- package/src/image-utils.d.ts +2 -2
- package/src/image-utils.js +1 -1
- package/src/image-utils.ts +2 -2
- package/src/index.d.ts +3 -3
- package/src/index.js +3 -3
- package/src/index.ts +3 -3
- package/src/plugin.d.ts +22 -3
- package/src/plugin.js +126 -17
- package/src/plugin.ts +156 -35
package/CHANGELOG.md
CHANGED
|
@@ -8,16 +8,15 @@ All notable changes to `@ecopages/image-processor` are documented here.
|
|
|
8
8
|
|
|
9
9
|
### Features
|
|
10
10
|
|
|
11
|
-
-
|
|
12
|
-
-
|
|
11
|
+
- Added `image-plugins.ts` with shared image plugin creation so the processor can target multiple build adapters.
|
|
12
|
+
- Added `bun-plugins.ts` with Bun-specific build adapter helpers aligned with the shared image plugin layer.
|
|
13
13
|
|
|
14
|
-
###
|
|
14
|
+
### Bug Fixes
|
|
15
15
|
|
|
16
|
-
-
|
|
17
|
-
- `
|
|
18
|
-
-
|
|
16
|
+
- Switched public internal imports to explicit relative ESM specifiers so Node thin-host builds can externalize the package without `ERR_MODULE_NOT_FOUND`.
|
|
17
|
+
- Inlined the generated `ecopages:images` declaration source so bundled runtime bootstrap no longer depends on a sibling `types` module at runtime.
|
|
18
|
+
- Re-emitted generated image outputs after static export cleanup so routes that reference `/images/...` keep their optimized files inside `dist`.
|
|
19
19
|
|
|
20
20
|
### Tests
|
|
21
21
|
|
|
22
|
-
-
|
|
23
|
-
- `image-processor.test.ts` and `image-utils.test.ts` updated.
|
|
22
|
+
- Added image processor and renderer coverage for the current build pipeline.
|
package/README.md
CHANGED
|
@@ -1,35 +1,38 @@
|
|
|
1
1
|
# @ecopages/image-processor
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Image processing pipeline for responsive, optimized images in Ecopages.
|
|
4
|
+
|
|
5
|
+
It provides automatic image processing (e.g. converting and compressing to WebP) and virtual module integration, allowing you to import your optimized images safely and directly via `ecopages:images`.
|
|
4
6
|
|
|
5
7
|
## Features
|
|
6
8
|
|
|
7
|
-
- **Automatic Image Optimization**: Converts and compresses images to modern formats
|
|
8
|
-
- **Responsive Image Generation**: Creates multiple
|
|
9
|
-
- **Virtual Module Integration**:
|
|
10
|
-
- **
|
|
11
|
-
- **Multiple Layout Options**:
|
|
12
|
-
- **Ecopages Integration**: Seamlessly integrated with the ecopages framework
|
|
9
|
+
- **Automatic Image Optimization**: Converts and compresses images to modern formats at build time.
|
|
10
|
+
- **Responsive Image Generation**: Creates multiple variants for different screen sizes.
|
|
11
|
+
- **Virtual Module Integration**: Type-safe imports through `ecopages:images`.
|
|
12
|
+
- **Ecopages Components**: Ready-to-use HTML (`EcoImage`) and React (`EcoImage`) components.
|
|
13
|
+
- **Multiple Layout Options**: Fixed, constrained, and full-width layouts built-in.
|
|
13
14
|
|
|
14
15
|
## Installation
|
|
15
16
|
|
|
16
17
|
```bash
|
|
17
|
-
|
|
18
|
+
bunx jsr add @ecopages/image-processor
|
|
18
19
|
```
|
|
19
20
|
|
|
20
21
|
## Configuration
|
|
21
22
|
|
|
23
|
+
Import and register the processor in your `eco.config.ts`:
|
|
24
|
+
|
|
22
25
|
```typescript
|
|
23
26
|
import path from 'node:path';
|
|
24
|
-
import { ConfigBuilder } from '@ecopages/core';
|
|
27
|
+
import { ConfigBuilder } from '@ecopages/core/config-builder';
|
|
25
28
|
import { ImageProcessorPlugin } from '@ecopages/image-processor';
|
|
26
29
|
|
|
27
30
|
const imageProcessor = new ImageProcessorPlugin({
|
|
28
31
|
name: 'ecopages-image-processor',
|
|
29
32
|
type: 'image',
|
|
30
33
|
options: {
|
|
31
|
-
sourceDir: path.resolve(import.meta.
|
|
32
|
-
outputDir: path.resolve(import.meta.
|
|
34
|
+
sourceDir: path.resolve(import.meta.dirname, 'src/images'),
|
|
35
|
+
outputDir: path.resolve(import.meta.dirname, 'dist/images'),
|
|
33
36
|
publicPath: '/images',
|
|
34
37
|
acceptedFormats: ['jpg', 'jpeg', 'png', 'webp'],
|
|
35
38
|
quality: 80,
|
|
@@ -44,175 +47,62 @@ const imageProcessor = new ImageProcessorPlugin({
|
|
|
44
47
|
});
|
|
45
48
|
|
|
46
49
|
export default await new ConfigBuilder()
|
|
47
|
-
.setRootDir(import.meta.
|
|
50
|
+
.setRootDir(import.meta.dirname)
|
|
48
51
|
.setBaseUrl(import.meta.env.ECOPAGES_BASE_URL)
|
|
49
52
|
.setProcessors([imageProcessor])
|
|
50
53
|
.build();
|
|
51
54
|
```
|
|
52
55
|
|
|
53
|
-
### Configuration Options
|
|
54
|
-
|
|
55
|
-
#### ImageProcessorConfig
|
|
56
|
-
|
|
57
|
-
| Option | Type | Default | Description |
|
|
58
|
-
| ----------------- | --------------------------------------- | ----------------------------- | ------------------------------------- |
|
|
59
|
-
| `sourceDir` | `string` | `'/src/public/assets/images'` | Source directory for images |
|
|
60
|
-
| `outputDir` | `string` | `'/dist/assets/optimized'` | Output directory for processed images |
|
|
61
|
-
| `publicPath` | `string` | `'/assets/optimized'` | Public URL path for images |
|
|
62
|
-
| `sizes` | `Array<{width: number, label: string}>` | `[]` | Image variants configuration |
|
|
63
|
-
| `quality` | `number` | `80` | Output image quality (0-100) |
|
|
64
|
-
| `format` | `'webp' \| 'jpeg' \| 'png' \| 'avif'` | `'webp'` | Output image format |
|
|
65
|
-
| `acceptedFormats` | `string[]` | `['jpg','jpeg','png','webp']` | Accepted input formats |
|
|
66
|
-
|
|
67
56
|
## Usage
|
|
68
57
|
|
|
69
58
|
### Virtual Module System
|
|
70
59
|
|
|
71
|
-
The `ecopages:images` virtual module provides a
|
|
60
|
+
The `ecopages:images` virtual module provides a type-safe way to import processed images:
|
|
72
61
|
|
|
73
62
|
```typescript
|
|
74
|
-
//
|
|
75
|
-
import { heroImage, profilePicture
|
|
76
|
-
|
|
77
|
-
// Names are automatically converted to camelCase
|
|
78
|
-
// example:
|
|
79
|
-
// src/images/hero-image.jpg -> heroImage
|
|
80
|
-
// src/images/profile_picture.png -> profilePicture
|
|
63
|
+
// Imports from your source directory are resolved automatically and camelCased
|
|
64
|
+
import { heroImage, profilePicture } from 'ecopages:images';
|
|
81
65
|
```
|
|
82
66
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
- **TypeScript Integration**: Full autocompletion support for image names
|
|
88
|
-
- **Automatic Processing**: Images are processed at build time
|
|
89
|
-
- **Tree Shaking**: Only imported images and their required metadata are included in the final bundle
|
|
90
|
-
- **Type Safety**: Prevents imports of non-existent images
|
|
91
|
-
- **Unified API**: Consistent way to handle images across your project
|
|
67
|
+
> [!TIP]
|
|
68
|
+
> **No manual dependencies required.**
|
|
69
|
+
> Ecopages automatically detects these virtual module imports and processes them during the build, enabling effective tree-shaking for only the required images.
|
|
92
70
|
|
|
93
|
-
###
|
|
71
|
+
### Components
|
|
94
72
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
```typescript
|
|
98
|
-
import { myImage } from 'ecopages:images';
|
|
99
|
-
|
|
100
|
-
// myImage contains:
|
|
101
|
-
// {
|
|
102
|
-
// attributes: {
|
|
103
|
-
// src: string,
|
|
104
|
-
// width: number, // original image width
|
|
105
|
-
// height: number, // original image height
|
|
106
|
-
// sizes: string,
|
|
107
|
-
// srcset: string
|
|
108
|
-
// },
|
|
109
|
-
// variants: Array<{ width, height, src, label }>
|
|
110
|
-
// }
|
|
111
|
-
```
|
|
73
|
+
The plugin provides ready-to-use components for HTML (`@kitajs/html`) and React:
|
|
112
74
|
|
|
113
|
-
|
|
75
|
+
**HTML Component:**
|
|
114
76
|
|
|
115
77
|
```typescript
|
|
116
78
|
import { EcoImage } from '@ecopages/image-processor/component/html';
|
|
117
79
|
|
|
118
|
-
// Basic usage
|
|
119
80
|
EcoImage({
|
|
120
|
-
...
|
|
121
|
-
width: 800,
|
|
122
|
-
height: 600,
|
|
123
|
-
alt: 'My image',
|
|
124
|
-
});
|
|
125
|
-
|
|
126
|
-
// Advanced usage
|
|
127
|
-
EcoImage({
|
|
128
|
-
...myImage,
|
|
129
|
-
alt: 'My image',
|
|
81
|
+
...heroImage,
|
|
130
82
|
layout: 'constrained',
|
|
83
|
+
alt: 'Hero banner',
|
|
131
84
|
priority: true,
|
|
132
|
-
aspectRatio: '16/9',
|
|
133
|
-
staticVariant: 'xl',
|
|
134
85
|
});
|
|
135
86
|
```
|
|
136
87
|
|
|
137
|
-
|
|
88
|
+
**React Component:**
|
|
138
89
|
|
|
139
90
|
```jsx
|
|
140
|
-
import { EcoImage } from
|
|
141
|
-
|
|
142
|
-
// Basic usage
|
|
143
|
-
<EcoImage
|
|
144
|
-
{...myImage}
|
|
145
|
-
alt="My image"
|
|
146
|
-
/>
|
|
147
|
-
|
|
148
|
-
// Advanced usage
|
|
149
|
-
<EcoImage
|
|
150
|
-
{...myImage}
|
|
151
|
-
alt="My image"
|
|
152
|
-
layout="constrained"
|
|
153
|
-
priority
|
|
154
|
-
aspectRatio="16/9"
|
|
155
|
-
staticVariant="xl"
|
|
156
|
-
/>
|
|
157
|
-
```
|
|
158
|
-
|
|
159
|
-
### Component Props
|
|
160
|
-
|
|
161
|
-
The component accepts all standard HTML/React image attributes (`src`, `alt`, `data-*`, `crossOrigin`, etc.) in addition to the following specific props:
|
|
162
|
-
|
|
163
|
-
| Prop | Type | Default | Description |
|
|
164
|
-
| --------------- | ------------------------------------------ | ------------------- | -------------------------------------------- |
|
|
165
|
-
| `width` | `number` | From image metadata | Original width, can be overridden if needed |
|
|
166
|
-
| `height` | `number` | From image metadata | Original height, can be overridden if needed |
|
|
167
|
-
| `priority` | `boolean` | `false` | Prioritize loading |
|
|
168
|
-
| `layout` | `'fixed' \| 'constrained' \| 'full-width'` | `'constrained'` | Layout behavior |
|
|
169
|
-
| `staticVariant` | `string` | - | Force specific size variant |
|
|
170
|
-
| `aspectRatio` | `string` | From width/height | Override the natural aspect ratio |
|
|
171
|
-
| `unstyled` | `boolean` | `false` | Disable default styling |
|
|
172
|
-
|
|
173
|
-
Note: Images imported through `ecopages:images` automatically include their width and height metadata, preventing layout shifts by default. These values can be overridden when needed, for example when using a different aspect ratio or specific layout requirements.
|
|
91
|
+
import { EcoImage } from '@ecopages/image-processor/component/react';
|
|
174
92
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
### Fixed Layout
|
|
178
|
-
|
|
179
|
-
```typescript
|
|
180
|
-
EcoImage({
|
|
181
|
-
...myImage,
|
|
182
|
-
layout: 'fixed',
|
|
183
|
-
width: 400,
|
|
184
|
-
height: 300,
|
|
185
|
-
alt: 'Fixed image',
|
|
186
|
-
});
|
|
93
|
+
<EcoImage {...heroImage} alt="Hero banner" layout="constrained" priority />;
|
|
187
94
|
```
|
|
188
95
|
|
|
189
|
-
###
|
|
190
|
-
|
|
191
|
-
```typescript
|
|
192
|
-
EcoImage({
|
|
193
|
-
...myImage,
|
|
194
|
-
layout: 'constrained',
|
|
195
|
-
width: 800,
|
|
196
|
-
alt: 'Constrained image',
|
|
197
|
-
});
|
|
198
|
-
```
|
|
199
|
-
|
|
200
|
-
### Full-Width Layout
|
|
201
|
-
|
|
202
|
-
```typescript
|
|
203
|
-
EcoImage({
|
|
204
|
-
...myImage,
|
|
205
|
-
layout: 'full-width',
|
|
206
|
-
alt: 'Full-width image',
|
|
207
|
-
});
|
|
208
|
-
```
|
|
209
|
-
|
|
210
|
-
## Best Practices
|
|
96
|
+
### Component Props
|
|
211
97
|
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
98
|
+
The components accept standard HTML/React attributes plus these specifics:
|
|
99
|
+
|
|
100
|
+
| Prop | Type | Default |
|
|
101
|
+
| :-------------- | :----------------------------------------- | :-------------- |
|
|
102
|
+
| `layout` | `'fixed' \| 'constrained' \| 'full-width'` | `'constrained'` |
|
|
103
|
+
| `priority` | `boolean` | `false` |
|
|
104
|
+
| `width` | `number` | From metadata |
|
|
105
|
+
| `height` | `number` | From metadata |
|
|
106
|
+
| `aspectRatio` | `string` | Natural ratio |
|
|
107
|
+
| `staticVariant` | `string` | - |
|
|
108
|
+
| `unstyled` | `boolean` | `false` |
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ecopages/image-processor",
|
|
3
|
-
"version": "0.2.0-alpha.
|
|
3
|
+
"version": "0.2.0-alpha.7",
|
|
4
4
|
"description": "Image processor, transform and optimize images for web",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"image",
|
|
@@ -15,10 +15,10 @@
|
|
|
15
15
|
"directory": "packages/processors/image-processor"
|
|
16
16
|
},
|
|
17
17
|
"peerDependencies": {
|
|
18
|
-
"@ecopages/core": "0.2.0-alpha.
|
|
18
|
+
"@ecopages/core": "0.2.0-alpha.7"
|
|
19
19
|
},
|
|
20
20
|
"dependencies": {
|
|
21
|
-
"@ecopages/file-system": "0.2.0-alpha.
|
|
21
|
+
"@ecopages/file-system": "0.2.0-alpha.7",
|
|
22
22
|
"@ecopages/logger": "latest",
|
|
23
23
|
"react": "^19",
|
|
24
24
|
"react-dom": "^19",
|
package/src/bun-plugins.d.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* @module @ecopages/image-processor/bun-plugins
|
|
4
4
|
*/
|
|
5
5
|
import type { EcoBuildPlugin } from '@ecopages/core/build/build-types';
|
|
6
|
-
import type { ImageMap } from './plugin';
|
|
6
|
+
import type { ImageMap } from './plugin.js';
|
|
7
7
|
/**
|
|
8
8
|
* This function creates a plugin for bundling the image specifications.
|
|
9
9
|
* https://bun.sh/docs/runtime/plugins#virtual-modules
|
package/src/bun-plugins.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { anyCaseToCamelCase } from "./utils";
|
|
1
|
+
import { anyCaseToCamelCase } from "./utils.js";
|
|
2
2
|
function createPluginResult(exports) {
|
|
3
3
|
return {
|
|
4
4
|
contents: `${Object.entries(exports).map(([key, value]) => `export const ${anyCaseToCamelCase(key)} = ${JSON.stringify(value)};`).join("\n")}`,
|
package/src/bun-plugins.ts
CHANGED
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import type { EcoBuildOnLoadResult, EcoBuildPlugin } from '@ecopages/core/build/build-types';
|
|
7
|
-
import type { ImageMap } from './plugin';
|
|
8
|
-
import { anyCaseToCamelCase } from './utils';
|
|
7
|
+
import type { ImageMap } from './plugin.ts';
|
|
8
|
+
import { anyCaseToCamelCase } from './utils.ts';
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* This function creates the plugin result for the image specifications.
|
package/src/component/html.d.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Image component that renders the image as a string.
|
|
3
3
|
* @module @ecopages/image-processor/component/html
|
|
4
4
|
*/
|
|
5
|
-
import { type EcoImageProps } from '../image-renderer';
|
|
5
|
+
import { type EcoImageProps } from '../image-renderer.js';
|
|
6
6
|
/**
|
|
7
7
|
* EcoImage
|
|
8
8
|
* This component generates the image element based on the provided props as a string
|
package/src/component/html.js
CHANGED
package/src/component/html.ts
CHANGED
package/src/component/react.d.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* @module @ecopages/image-processor/component/react
|
|
4
4
|
*/
|
|
5
5
|
import { type JSX } from 'react';
|
|
6
|
-
import { type EcoImageProps } from '../image-renderer';
|
|
6
|
+
import { type EcoImageProps } from '../image-renderer.js';
|
|
7
7
|
/**
|
|
8
8
|
* EcoImage
|
|
9
9
|
* This component generates the image element based on the provided props as JSX
|
package/src/component/react.js
CHANGED
package/src/component/react.ts
CHANGED
package/src/constants.d.ts
CHANGED
package/src/constants.ts
CHANGED
package/src/image-plugins.d.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* @module @ecopages/image-processor/image-plugins
|
|
4
4
|
*/
|
|
5
5
|
import type { EcoBuildPlugin } from '@ecopages/core/build/build-types';
|
|
6
|
-
import type { ImageMap } from './plugin';
|
|
6
|
+
import type { ImageMap } from './plugin.js';
|
|
7
7
|
/**
|
|
8
8
|
* This function creates a plugin for bundling the image specifications.
|
|
9
9
|
* https://bun.sh/docs/runtime/plugins#virtual-modules
|
package/src/image-plugins.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { anyCaseToCamelCase } from "./utils";
|
|
1
|
+
import { anyCaseToCamelCase } from "./utils.js";
|
|
2
2
|
function createPluginResult(exports) {
|
|
3
3
|
return {
|
|
4
4
|
contents: `${Object.entries(exports).map(([key, value]) => `export const ${anyCaseToCamelCase(key)} = ${JSON.stringify(value)};`).join("\n")}`,
|
package/src/image-plugins.ts
CHANGED
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import type { EcoBuildOnLoadResult, EcoBuildPlugin } from '@ecopages/core/build/build-types';
|
|
7
|
-
import type { ImageMap } from './plugin';
|
|
8
|
-
import { anyCaseToCamelCase } from './utils';
|
|
7
|
+
import type { ImageMap } from './plugin.ts';
|
|
8
|
+
import { anyCaseToCamelCase } from './utils.ts';
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* This function creates the plugin result for the image specifications.
|
package/src/image-processor.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { ImageMap, ImageProcessorConfig } from './plugin';
|
|
2
|
-
import type { ImageSpecifications } from './types';
|
|
1
|
+
import type { ImageMap, ImageProcessorConfig } from './plugin.js';
|
|
2
|
+
import type { ImageSpecifications } from './types.js';
|
|
3
3
|
/**
|
|
4
4
|
* ImageProcessor
|
|
5
5
|
* This is the core class for processing images.
|
package/src/image-processor.js
CHANGED
|
@@ -3,7 +3,7 @@ import { deepMerge } from "@ecopages/core/utils/deep-merge";
|
|
|
3
3
|
import { fileSystem } from "@ecopages/file-system";
|
|
4
4
|
import { Logger } from "@ecopages/logger";
|
|
5
5
|
import sharp from "sharp";
|
|
6
|
-
import { ImageUtils } from "./image-utils";
|
|
6
|
+
import { ImageUtils } from "./image-utils.js";
|
|
7
7
|
const appLogger = new Logger("[@ecopages/image-processor]", {
|
|
8
8
|
debug: process.env.ECOPAGES_LOGGER_DEBUG === "true"
|
|
9
9
|
});
|
package/src/image-processor.ts
CHANGED
|
@@ -3,9 +3,9 @@ import { deepMerge } from '@ecopages/core/utils/deep-merge';
|
|
|
3
3
|
import { fileSystem } from '@ecopages/file-system';
|
|
4
4
|
import { Logger } from '@ecopages/logger';
|
|
5
5
|
import sharp from 'sharp';
|
|
6
|
-
import { ImageUtils } from './image-utils';
|
|
7
|
-
import type { ImageMap, ImageProcessorConfig } from './plugin';
|
|
8
|
-
import type { ImageAttributes, ImageSpecifications, ImageVariant } from './types';
|
|
6
|
+
import { ImageUtils } from './image-utils.ts';
|
|
7
|
+
import type { ImageMap, ImageProcessorConfig } from './plugin.ts';
|
|
8
|
+
import type { ImageAttributes, ImageSpecifications, ImageVariant } from './types.ts';
|
|
9
9
|
|
|
10
10
|
const appLogger = new Logger('[@ecopages/image-processor]', {
|
|
11
11
|
debug: process.env.ECOPAGES_LOGGER_DEBUG === 'true',
|
package/src/image-renderer.d.ts
CHANGED
package/src/image-renderer.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { DEFAULT_LAYOUT } from "./constants";
|
|
2
|
-
import { ImageUtils } from "./image-utils";
|
|
1
|
+
import { DEFAULT_LAYOUT } from "./constants.js";
|
|
2
|
+
import { ImageUtils } from "./image-utils.js";
|
|
3
3
|
class LayoutAttributesManager {
|
|
4
4
|
static shouldIncludeWidthHeight(layout) {
|
|
5
5
|
return layout === "fixed";
|
package/src/image-renderer.ts
CHANGED
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
* @module
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import { DEFAULT_LAYOUT } from './constants';
|
|
7
|
-
import { ImageUtils } from './image-utils';
|
|
8
|
-
import type { ImageSpecifications, ImageVariant } from './types';
|
|
6
|
+
import { DEFAULT_LAYOUT } from './constants.ts';
|
|
7
|
+
import { ImageUtils } from './image-utils.ts';
|
|
8
|
+
import type { ImageSpecifications, ImageVariant } from './types.ts';
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* Image layout options
|
package/src/image-utils.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { EcoImageProps } from './image-renderer';
|
|
1
|
+
import type { EcoImageProps } from './image-renderer.js';
|
|
2
2
|
/**
|
|
3
3
|
* ImageUtils
|
|
4
4
|
* This class contains utility methods for working with images
|
|
@@ -7,7 +7,7 @@ import type { EcoImageProps } from './image-renderer';
|
|
|
7
7
|
export declare class ImageUtils {
|
|
8
8
|
private static readonly BREAKPOINTS;
|
|
9
9
|
private static readonly VIEWPORT_SIZES;
|
|
10
|
-
static readonly DEFAULT_LAYOUT: import("./image-renderer").ImageLayout;
|
|
10
|
+
static readonly DEFAULT_LAYOUT: import("./image-renderer.js").ImageLayout;
|
|
11
11
|
/**
|
|
12
12
|
* Generates a srcset string from processed image variants using relative paths
|
|
13
13
|
* @param {ImageVariant[]} variants - Array of processed image variants
|
package/src/image-utils.js
CHANGED
package/src/image-utils.ts
CHANGED
package/src/index.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export * from './image-processor';
|
|
2
|
-
export * from './plugin';
|
|
3
|
-
export * from './types';
|
|
1
|
+
export * from './image-processor.js';
|
|
2
|
+
export * from './plugin.js';
|
|
3
|
+
export * from './types.js';
|
package/src/index.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export * from "./image-processor";
|
|
2
|
-
export * from "./plugin";
|
|
3
|
-
export * from "./types";
|
|
1
|
+
export * from "./image-processor.js";
|
|
2
|
+
export * from "./plugin.js";
|
|
3
|
+
export * from "./types.js";
|
package/src/index.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export * from './image-processor';
|
|
2
|
-
export * from './plugin';
|
|
3
|
-
export * from './types';
|
|
1
|
+
export * from './image-processor.ts';
|
|
2
|
+
export * from './plugin.ts';
|
|
3
|
+
export * from './types.ts';
|
package/src/plugin.d.ts
CHANGED
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import { Processor, type ProcessorConfig } from '@ecopages/core/plugins/processor';
|
|
6
6
|
import type { EcoBuildPlugin } from '@ecopages/core/build/build-types';
|
|
7
|
-
import { ImageProcessor } from './image-processor';
|
|
8
|
-
import type { ImageSize, ImageSpecifications } from './types';
|
|
7
|
+
import { ImageProcessor } from './image-processor.js';
|
|
8
|
+
import type { ImageSize, ImageSpecifications } from './types.js';
|
|
9
9
|
/**
|
|
10
10
|
* Configuration for the image processor
|
|
11
11
|
*/
|
|
@@ -40,10 +40,29 @@ export type ImageMap = Record<string, ImageSpecifications>;
|
|
|
40
40
|
*/
|
|
41
41
|
export declare class ImageProcessorPlugin extends Processor<ImageProcessorConfig> {
|
|
42
42
|
private processor;
|
|
43
|
+
private buildContributionsPrepared;
|
|
44
|
+
private resolvedConfig?;
|
|
43
45
|
processedImages: Record<string, ImageSpecifications>;
|
|
44
46
|
constructor(config: Omit<ProcessorConfig<ImageProcessorConfig>, 'name' | 'description'>);
|
|
45
47
|
get buildPlugins(): EcoBuildPlugin[];
|
|
46
48
|
get plugins(): EcoBuildPlugin[];
|
|
49
|
+
/**
|
|
50
|
+
* Replaces image-map contents without swapping the backing object.
|
|
51
|
+
*
|
|
52
|
+
* @remarks
|
|
53
|
+
* The build/runtime virtual-module plugins close over `processedImages`, so
|
|
54
|
+
* mutating the existing object keeps those plugins live after preparation.
|
|
55
|
+
*/
|
|
56
|
+
private replaceProcessedImages;
|
|
57
|
+
/**
|
|
58
|
+
* Prepares the image virtual-module state before config build seals the app
|
|
59
|
+
* manifest.
|
|
60
|
+
*/
|
|
61
|
+
prepareBuildContributions(): Promise<void>;
|
|
62
|
+
private getRuntimeVirtualModulePath;
|
|
63
|
+
private getGeneratedOutputPath;
|
|
64
|
+
private hasGeneratedOutputs;
|
|
65
|
+
private rehydrateGeneratedOutputs;
|
|
47
66
|
/**
|
|
48
67
|
* Generate dependencies for processor.
|
|
49
68
|
* It is ossible to define which one should be included in the final bundle based on the environment.
|
|
@@ -51,7 +70,7 @@ export declare class ImageProcessorPlugin extends Processor<ImageProcessorConfig
|
|
|
51
70
|
*/
|
|
52
71
|
private generateDependencies;
|
|
53
72
|
/**
|
|
54
|
-
*
|
|
73
|
+
* Prepares build contributions if not already done and rehydrates previously generated image outputs.
|
|
55
74
|
*/
|
|
56
75
|
setup(): Promise<void>;
|
|
57
76
|
/**
|
package/src/plugin.js
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
|
-
import { fileURLToPath } from "node:url";
|
|
3
2
|
import { deepMerge } from "@ecopages/core/utils/deep-merge";
|
|
4
3
|
import { GENERATED_BASE_PATHS } from "@ecopages/core/constants";
|
|
5
4
|
import { fileSystem } from "@ecopages/file-system";
|
|
6
5
|
import { Processor } from "@ecopages/core/plugins/processor";
|
|
7
6
|
import { Logger } from "@ecopages/logger";
|
|
8
|
-
import { createImagePlugin, createImagePluginBundler } from "./image-plugins";
|
|
9
|
-
import { ImageProcessor } from "./image-processor";
|
|
10
|
-
import { anyCaseToCamelCase } from "./utils";
|
|
7
|
+
import { createImagePlugin, createImagePluginBundler } from "./image-plugins.js";
|
|
8
|
+
import { ImageProcessor } from "./image-processor.js";
|
|
9
|
+
import { anyCaseToCamelCase } from "./utils.js";
|
|
11
10
|
function resolveGeneratedPath(type, options) {
|
|
12
11
|
const { root, module, subPath } = options;
|
|
13
12
|
const parts = [root, GENERATED_BASE_PATHS[type], module, subPath].filter(Boolean);
|
|
@@ -16,8 +15,54 @@ function resolveGeneratedPath(type, options) {
|
|
|
16
15
|
const logger = new Logger("[@ecopages/image-processor]", {
|
|
17
16
|
debug: process.env.ECOPAGES_LOGGER_DEBUG === "true"
|
|
18
17
|
});
|
|
19
|
-
const
|
|
18
|
+
const IMAGE_VIRTUAL_MODULE_TYPES = `/**
|
|
19
|
+
* ImageAttributes
|
|
20
|
+
* These are the core attributes for the image element generated by the image processor
|
|
21
|
+
*/
|
|
22
|
+
interface ImageAttributes {
|
|
23
|
+
src: string;
|
|
24
|
+
width: number;
|
|
25
|
+
height: number;
|
|
26
|
+
sizes: string;
|
|
27
|
+
srcset?: string;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* This represents a single image variant created using the size configuration
|
|
32
|
+
*/
|
|
33
|
+
interface ImageVariant {
|
|
34
|
+
width: number;
|
|
35
|
+
height: number;
|
|
36
|
+
src: string;
|
|
37
|
+
label: string;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* These are the core attributes for the image element and the image variants
|
|
42
|
+
* This is the representation of the image element in the virtual module
|
|
43
|
+
*/
|
|
44
|
+
interface ImageSpecifications {
|
|
45
|
+
attributes: ImageAttributes;
|
|
46
|
+
variants: ImageVariant[];
|
|
47
|
+
/**
|
|
48
|
+
* A unique key used to cache the image specifications.
|
|
49
|
+
* This key should uniquely identify the combination of attributes and variants
|
|
50
|
+
* to ensure proper caching behavior.
|
|
51
|
+
*/
|
|
52
|
+
cacheKey: string;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* This is the representation of an image breakpoint
|
|
57
|
+
* This is used to generate the srcset attribute
|
|
58
|
+
*/
|
|
59
|
+
type ImageSize = {
|
|
60
|
+
width: number;
|
|
61
|
+
label: string;
|
|
62
|
+
};`;
|
|
20
63
|
class ImageProcessorPlugin extends Processor {
|
|
64
|
+
buildContributionsPrepared = false;
|
|
65
|
+
resolvedConfig;
|
|
21
66
|
processedImages = {};
|
|
22
67
|
constructor(config) {
|
|
23
68
|
const acceptedFormats = config.options?.acceptedFormats ?? ["jpg", "jpeg", "png", "webp"];
|
|
@@ -50,20 +95,26 @@ class ImageProcessorPlugin extends Processor {
|
|
|
50
95
|
return [createImagePlugin(this.processedImages)];
|
|
51
96
|
}
|
|
52
97
|
/**
|
|
53
|
-
*
|
|
54
|
-
*
|
|
55
|
-
* @
|
|
98
|
+
* Replaces image-map contents without swapping the backing object.
|
|
99
|
+
*
|
|
100
|
+
* @remarks
|
|
101
|
+
* The build/runtime virtual-module plugins close over `processedImages`, so
|
|
102
|
+
* mutating the existing object keeps those plugins live after preparation.
|
|
56
103
|
*/
|
|
57
|
-
|
|
58
|
-
const
|
|
59
|
-
|
|
104
|
+
replaceProcessedImages(images) {
|
|
105
|
+
for (const key of Object.keys(this.processedImages)) {
|
|
106
|
+
delete this.processedImages[key];
|
|
60
107
|
}
|
|
61
|
-
|
|
108
|
+
Object.assign(this.processedImages, images);
|
|
62
109
|
}
|
|
63
110
|
/**
|
|
64
|
-
*
|
|
111
|
+
* Prepares the image virtual-module state before config build seals the app
|
|
112
|
+
* manifest.
|
|
65
113
|
*/
|
|
66
|
-
async
|
|
114
|
+
async prepareBuildContributions() {
|
|
115
|
+
if (this.buildContributionsPrepared) {
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
67
118
|
if (!this.context) {
|
|
68
119
|
throw new Error("ImageProcessor requires context to be set");
|
|
69
120
|
}
|
|
@@ -80,16 +131,75 @@ class ImageProcessorPlugin extends Processor {
|
|
|
80
131
|
format: "webp"
|
|
81
132
|
};
|
|
82
133
|
const config = this.options ? deepMerge(defaultConfig, this.options) : defaultConfig;
|
|
134
|
+
this.resolvedConfig = config;
|
|
83
135
|
this.processor = new ImageProcessor(config, {
|
|
84
136
|
readCache: (key) => this.readCache(key),
|
|
85
137
|
writeCache: (key, data) => this.writeCache(key, data)
|
|
86
138
|
});
|
|
87
|
-
this.
|
|
139
|
+
this.replaceProcessedImages(await this.processor.processDirectory());
|
|
88
140
|
if (this.watchConfig) {
|
|
89
141
|
this.watchConfig.paths = [config.sourceDir];
|
|
90
142
|
}
|
|
91
143
|
this.dependencies = this.generateDependencies();
|
|
92
144
|
this.generateTypes();
|
|
145
|
+
this.buildContributionsPrepared = true;
|
|
146
|
+
}
|
|
147
|
+
getRuntimeVirtualModulePath() {
|
|
148
|
+
if (!this.context) {
|
|
149
|
+
throw new Error("ImageProcessor requires context to be set");
|
|
150
|
+
}
|
|
151
|
+
return resolveGeneratedPath("cache", {
|
|
152
|
+
root: this.context.distDir,
|
|
153
|
+
module: this.name,
|
|
154
|
+
subPath: "virtual-module.ts"
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
getGeneratedOutputPath(src) {
|
|
158
|
+
if (!this.resolvedConfig) {
|
|
159
|
+
throw new Error("ImageProcessor not initialized");
|
|
160
|
+
}
|
|
161
|
+
return path.join(this.resolvedConfig.outputDir, path.basename(src));
|
|
162
|
+
}
|
|
163
|
+
hasGeneratedOutputs() {
|
|
164
|
+
if (!this.resolvedConfig) {
|
|
165
|
+
return false;
|
|
166
|
+
}
|
|
167
|
+
if (!fileSystem.exists(this.resolvedConfig.outputDir) || !fileSystem.exists(this.getRuntimeVirtualModulePath())) {
|
|
168
|
+
return false;
|
|
169
|
+
}
|
|
170
|
+
return Object.values(this.processedImages).every((image) => {
|
|
171
|
+
const outputPaths = [image.attributes.src, ...image.variants.map((variant) => variant.src)];
|
|
172
|
+
return outputPaths.every((src) => fileSystem.exists(this.getGeneratedOutputPath(src)));
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
async rehydrateGeneratedOutputs() {
|
|
176
|
+
if (!this.processor) {
|
|
177
|
+
throw new Error("ImageProcessor not initialized");
|
|
178
|
+
}
|
|
179
|
+
if (this.hasGeneratedOutputs()) {
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
this.replaceProcessedImages(await this.processor.processDirectory());
|
|
183
|
+
this.dependencies = this.generateDependencies();
|
|
184
|
+
this.generateTypes();
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Generate dependencies for processor.
|
|
188
|
+
* It is ossible to define which one should be included in the final bundle based on the environment.
|
|
189
|
+
* @returns
|
|
190
|
+
*/
|
|
191
|
+
generateDependencies() {
|
|
192
|
+
const deps = [];
|
|
193
|
+
if (process.env.NODE_ENV === "development") {
|
|
194
|
+
}
|
|
195
|
+
return deps;
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Prepares build contributions if not already done and rehydrates previously generated image outputs.
|
|
199
|
+
*/
|
|
200
|
+
async setup() {
|
|
201
|
+
await this.prepareBuildContributions();
|
|
202
|
+
await this.rehydrateGeneratedOutputs();
|
|
93
203
|
}
|
|
94
204
|
/**
|
|
95
205
|
* Process images.
|
|
@@ -159,14 +269,13 @@ class ImageProcessorPlugin extends Processor {
|
|
|
159
269
|
if (!this.options?.outputDir) {
|
|
160
270
|
throw new Error("Output directory not set");
|
|
161
271
|
}
|
|
162
|
-
const requiredTypes = fileSystem.readFileSync(path.join(currentDir, "types.ts")).toString().replaceAll("export ", "");
|
|
163
272
|
const content = `
|
|
164
273
|
/**
|
|
165
274
|
* Do not edit manually. This file is auto-generated.
|
|
166
275
|
* This file contains the type definitions for the virtual module "ecopages:images".
|
|
167
276
|
*/
|
|
168
277
|
|
|
169
|
-
${
|
|
278
|
+
${IMAGE_VIRTUAL_MODULE_TYPES}
|
|
170
279
|
|
|
171
280
|
declare module "ecopages:images" {
|
|
172
281
|
${Object.keys(this.processedImages).map((key) => `export const ${anyCaseToCamelCase(key)}: ImageSpecifications;`).join("\n ")}
|
package/src/plugin.ts
CHANGED
|
@@ -4,7 +4,6 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import path from 'node:path';
|
|
7
|
-
import { fileURLToPath } from 'node:url';
|
|
8
7
|
import { deepMerge } from '@ecopages/core/utils/deep-merge';
|
|
9
8
|
import { GENERATED_BASE_PATHS } from '@ecopages/core/constants';
|
|
10
9
|
import { fileSystem } from '@ecopages/file-system';
|
|
@@ -12,10 +11,10 @@ import { Processor, type ProcessorConfig, type ProcessorWatchConfig } from '@eco
|
|
|
12
11
|
import type { EcoBuildPlugin } from '@ecopages/core/build/build-types';
|
|
13
12
|
import type { AssetDefinition } from '@ecopages/core/services/asset-processing-service';
|
|
14
13
|
import { Logger } from '@ecopages/logger';
|
|
15
|
-
import { createImagePlugin, createImagePluginBundler } from './image-plugins';
|
|
16
|
-
import { ImageProcessor } from './image-processor';
|
|
17
|
-
import type { ImageSize, ImageSpecifications } from './types';
|
|
18
|
-
import { anyCaseToCamelCase } from './utils';
|
|
14
|
+
import { createImagePlugin, createImagePluginBundler } from './image-plugins.ts';
|
|
15
|
+
import { ImageProcessor } from './image-processor.ts';
|
|
16
|
+
import type { ImageSize, ImageSpecifications } from './types.ts';
|
|
17
|
+
import { anyCaseToCamelCase } from './utils.ts';
|
|
19
18
|
|
|
20
19
|
function resolveGeneratedPath(
|
|
21
20
|
type: keyof typeof GENERATED_BASE_PATHS,
|
|
@@ -30,7 +29,51 @@ const logger = new Logger('[@ecopages/image-processor]', {
|
|
|
30
29
|
debug: process.env.ECOPAGES_LOGGER_DEBUG === 'true',
|
|
31
30
|
});
|
|
32
31
|
|
|
33
|
-
const
|
|
32
|
+
const IMAGE_VIRTUAL_MODULE_TYPES = `/**
|
|
33
|
+
* ImageAttributes
|
|
34
|
+
* These are the core attributes for the image element generated by the image processor
|
|
35
|
+
*/
|
|
36
|
+
interface ImageAttributes {
|
|
37
|
+
src: string;
|
|
38
|
+
width: number;
|
|
39
|
+
height: number;
|
|
40
|
+
sizes: string;
|
|
41
|
+
srcset?: string;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* This represents a single image variant created using the size configuration
|
|
46
|
+
*/
|
|
47
|
+
interface ImageVariant {
|
|
48
|
+
width: number;
|
|
49
|
+
height: number;
|
|
50
|
+
src: string;
|
|
51
|
+
label: string;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* These are the core attributes for the image element and the image variants
|
|
56
|
+
* This is the representation of the image element in the virtual module
|
|
57
|
+
*/
|
|
58
|
+
interface ImageSpecifications {
|
|
59
|
+
attributes: ImageAttributes;
|
|
60
|
+
variants: ImageVariant[];
|
|
61
|
+
/**
|
|
62
|
+
* A unique key used to cache the image specifications.
|
|
63
|
+
* This key should uniquely identify the combination of attributes and variants
|
|
64
|
+
* to ensure proper caching behavior.
|
|
65
|
+
*/
|
|
66
|
+
cacheKey: string;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* This is the representation of an image breakpoint
|
|
71
|
+
* This is used to generate the srcset attribute
|
|
72
|
+
*/
|
|
73
|
+
type ImageSize = {
|
|
74
|
+
width: number;
|
|
75
|
+
label: string;
|
|
76
|
+
};`;
|
|
34
77
|
|
|
35
78
|
/**
|
|
36
79
|
* Configuration for the image processor
|
|
@@ -68,6 +111,8 @@ export type ImageMap = Record<string, ImageSpecifications>;
|
|
|
68
111
|
*/
|
|
69
112
|
export class ImageProcessorPlugin extends Processor<ImageProcessorConfig> {
|
|
70
113
|
declare private processor: ImageProcessor;
|
|
114
|
+
private buildContributionsPrepared = false;
|
|
115
|
+
private resolvedConfig?: ImageProcessorConfig;
|
|
71
116
|
public processedImages: Record<string, ImageSpecifications> = {};
|
|
72
117
|
|
|
73
118
|
constructor(config: Omit<ProcessorConfig<ImageProcessorConfig>, 'name' | 'description'>) {
|
|
@@ -106,35 +151,29 @@ export class ImageProcessorPlugin extends Processor<ImageProcessorConfig> {
|
|
|
106
151
|
}
|
|
107
152
|
|
|
108
153
|
/**
|
|
109
|
-
*
|
|
110
|
-
*
|
|
111
|
-
* @
|
|
154
|
+
* Replaces image-map contents without swapping the backing object.
|
|
155
|
+
*
|
|
156
|
+
* @remarks
|
|
157
|
+
* The build/runtime virtual-module plugins close over `processedImages`, so
|
|
158
|
+
* mutating the existing object keeps those plugins live after preparation.
|
|
112
159
|
*/
|
|
113
|
-
private
|
|
114
|
-
const
|
|
115
|
-
|
|
116
|
-
if (process.env.NODE_ENV === 'development') {
|
|
117
|
-
/**
|
|
118
|
-
* Here we can define the dependencies for the development environment
|
|
119
|
-
* @example
|
|
120
|
-
* deps.push(
|
|
121
|
-
* AssetFactory.createInlineScriptAsset({
|
|
122
|
-
* content: `document.addEventListener("DOMContentLoaded",() => console.log("[@ecopages/image-processor] Processor is loaded"));`,
|
|
123
|
-
* attributes: {
|
|
124
|
-
* type: 'module',
|
|
125
|
-
* },
|
|
126
|
-
* }),
|
|
127
|
-
* );
|
|
128
|
-
*/
|
|
160
|
+
private replaceProcessedImages(images: ImageMap): void {
|
|
161
|
+
for (const key of Object.keys(this.processedImages)) {
|
|
162
|
+
delete this.processedImages[key];
|
|
129
163
|
}
|
|
130
164
|
|
|
131
|
-
|
|
165
|
+
Object.assign(this.processedImages, images);
|
|
132
166
|
}
|
|
133
167
|
|
|
134
168
|
/**
|
|
135
|
-
*
|
|
169
|
+
* Prepares the image virtual-module state before config build seals the app
|
|
170
|
+
* manifest.
|
|
136
171
|
*/
|
|
137
|
-
async
|
|
172
|
+
override async prepareBuildContributions(): Promise<void> {
|
|
173
|
+
if (this.buildContributionsPrepared) {
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
|
|
138
177
|
if (!this.context) {
|
|
139
178
|
throw new Error('ImageProcessor requires context to be set');
|
|
140
179
|
}
|
|
@@ -154,23 +193,110 @@ export class ImageProcessorPlugin extends Processor<ImageProcessorConfig> {
|
|
|
154
193
|
};
|
|
155
194
|
|
|
156
195
|
const config = this.options ? deepMerge(defaultConfig, this.options) : defaultConfig;
|
|
196
|
+
this.resolvedConfig = config;
|
|
157
197
|
|
|
158
198
|
this.processor = new ImageProcessor(config, {
|
|
159
199
|
readCache: (key) => this.readCache(key),
|
|
160
200
|
writeCache: (key, data) => this.writeCache(key, data),
|
|
161
201
|
});
|
|
162
202
|
|
|
163
|
-
this.
|
|
203
|
+
this.replaceProcessedImages(await this.processor.processDirectory());
|
|
164
204
|
|
|
165
205
|
if (this.watchConfig) {
|
|
166
206
|
this.watchConfig.paths = [config.sourceDir];
|
|
167
207
|
}
|
|
168
208
|
|
|
169
209
|
this.dependencies = this.generateDependencies();
|
|
210
|
+
this.generateTypes();
|
|
211
|
+
this.buildContributionsPrepared = true;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
private getRuntimeVirtualModulePath(): string {
|
|
215
|
+
if (!this.context) {
|
|
216
|
+
throw new Error('ImageProcessor requires context to be set');
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
return resolveGeneratedPath('cache', {
|
|
220
|
+
root: this.context.distDir,
|
|
221
|
+
module: this.name,
|
|
222
|
+
subPath: 'virtual-module.ts',
|
|
223
|
+
});
|
|
224
|
+
}
|
|
170
225
|
|
|
226
|
+
private getGeneratedOutputPath(src: string): string {
|
|
227
|
+
if (!this.resolvedConfig) {
|
|
228
|
+
throw new Error('ImageProcessor not initialized');
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
return path.join(this.resolvedConfig.outputDir, path.basename(src));
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
private hasGeneratedOutputs(): boolean {
|
|
235
|
+
if (!this.resolvedConfig) {
|
|
236
|
+
return false;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
if (
|
|
240
|
+
!fileSystem.exists(this.resolvedConfig.outputDir) ||
|
|
241
|
+
!fileSystem.exists(this.getRuntimeVirtualModulePath())
|
|
242
|
+
) {
|
|
243
|
+
return false;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
return Object.values(this.processedImages).every((image) => {
|
|
247
|
+
const outputPaths = [image.attributes.src, ...image.variants.map((variant) => variant.src)];
|
|
248
|
+
return outputPaths.every((src) => fileSystem.exists(this.getGeneratedOutputPath(src)));
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
private async rehydrateGeneratedOutputs(): Promise<void> {
|
|
253
|
+
if (!this.processor) {
|
|
254
|
+
throw new Error('ImageProcessor not initialized');
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
if (this.hasGeneratedOutputs()) {
|
|
258
|
+
return;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
this.replaceProcessedImages(await this.processor.processDirectory());
|
|
262
|
+
this.dependencies = this.generateDependencies();
|
|
171
263
|
this.generateTypes();
|
|
172
264
|
}
|
|
173
265
|
|
|
266
|
+
/**
|
|
267
|
+
* Generate dependencies for processor.
|
|
268
|
+
* It is ossible to define which one should be included in the final bundle based on the environment.
|
|
269
|
+
* @returns
|
|
270
|
+
*/
|
|
271
|
+
private generateDependencies(): AssetDefinition[] {
|
|
272
|
+
const deps: AssetDefinition[] = [];
|
|
273
|
+
|
|
274
|
+
if (process.env.NODE_ENV === 'development') {
|
|
275
|
+
/**
|
|
276
|
+
* Here we can define the dependencies for the development environment
|
|
277
|
+
* @example
|
|
278
|
+
* deps.push(
|
|
279
|
+
* AssetFactory.createInlineScriptAsset({
|
|
280
|
+
* content: `document.addEventListener("DOMContentLoaded",() => console.log("[@ecopages/image-processor] Processor is loaded"));`,
|
|
281
|
+
* attributes: {
|
|
282
|
+
* type: 'module',
|
|
283
|
+
* },
|
|
284
|
+
* }),
|
|
285
|
+
* );
|
|
286
|
+
*/
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
return deps;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
* Prepares build contributions if not already done and rehydrates previously generated image outputs.
|
|
294
|
+
*/
|
|
295
|
+
async setup(): Promise<void> {
|
|
296
|
+
await this.prepareBuildContributions();
|
|
297
|
+
await this.rehydrateGeneratedOutputs();
|
|
298
|
+
}
|
|
299
|
+
|
|
174
300
|
/**
|
|
175
301
|
* Process images.
|
|
176
302
|
* @param images
|
|
@@ -254,18 +380,13 @@ export class ImageProcessorPlugin extends Processor<ImageProcessorConfig> {
|
|
|
254
380
|
throw new Error('Output directory not set');
|
|
255
381
|
}
|
|
256
382
|
|
|
257
|
-
const requiredTypes = fileSystem
|
|
258
|
-
.readFileSync(path.join(currentDir, 'types.ts'))
|
|
259
|
-
.toString()
|
|
260
|
-
.replaceAll('export ', '');
|
|
261
|
-
|
|
262
383
|
const content = `
|
|
263
384
|
/**
|
|
264
385
|
* Do not edit manually. This file is auto-generated.
|
|
265
386
|
* This file contains the type definitions for the virtual module "ecopages:images".
|
|
266
387
|
*/
|
|
267
388
|
|
|
268
|
-
${
|
|
389
|
+
${IMAGE_VIRTUAL_MODULE_TYPES}
|
|
269
390
|
|
|
270
391
|
declare module "ecopages:images" {
|
|
271
392
|
${Object.keys(this.processedImages)
|