@ecopages/image-processor 0.2.1 → 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 CHANGED
@@ -6,16 +6,18 @@ It provides automatic image processing (e.g. converting and compressing to WebP)
6
6
 
7
7
  ## Features
8
8
 
9
- - **Automatic Image Optimization**: Converts and compresses images to modern formats at build time.
9
+ Build contributions use one `plugins(app)` method with server and browser environment declarations. Image processing, type generation and the cache restore run in `setup()`; `ecopages types` runs it. The virtual image module resolves through the implementation for the requested environment.
10
+
11
+ - **Automatic Image Optimization**: Converts and compresses images to modern formats at build time. Each variant is named from a hash of its encoded bytes, so a quality or format change gets a new URL.
10
12
  - **Responsive Image Generation**: Creates multiple variants for different screen sizes.
11
13
  - **Virtual Module Integration**: Type-safe imports through `ecopages:images`.
12
- - **Ecopages Components**: Ready-to-use HTML (`EcoImage`) and React (`EcoImage`) components.
14
+ - **Ecopages Components**: Ready-to-use HTML, Ecopages JSX, and React (`EcoImage`) components.
13
15
  - **Multiple Layout Options**: Fixed, constrained, and full-width layouts built-in.
14
16
 
15
17
  ## Installation
16
18
 
17
19
  ```bash
18
- bunx jsr add @ecopages/image-processor
20
+ bun add @ecopages/image-processor
19
21
  ```
20
22
 
21
23
  ## Configuration
@@ -24,7 +26,7 @@ Import and register the processor in your `eco.config.ts`:
24
26
 
25
27
  ```typescript
26
28
  import path from 'node:path';
27
- import { ConfigBuilder } from '@ecopages/core/config-builder';
29
+ import { defineConfig } from '@ecopages/core/config';
28
30
  import { ImageProcessorPlugin } from '@ecopages/image-processor';
29
31
 
30
32
  const imageProcessor = new ImageProcessorPlugin({
@@ -46,11 +48,7 @@ const imageProcessor = new ImageProcessorPlugin({
46
48
  },
47
49
  });
48
50
 
49
- export default await new ConfigBuilder()
50
- .setRootDir(import.meta.dirname)
51
- .setBaseUrl(import.meta.env.ECOPAGES_BASE_URL)
52
- .setProcessors([imageProcessor])
53
- .build();
51
+ export default defineConfig({ processors: [imageProcessor] });
54
52
  ```
55
53
 
56
54
  ## Usage
@@ -68,11 +66,22 @@ import { heroImage, profilePicture } from 'ecopages:images';
68
66
  > **No manual dependencies required.**
69
67
  > Ecopages automatically detects these virtual module imports and processes them during the build, enabling effective tree-shaking for only the required images.
70
68
 
69
+ ## TypeScript Setup
70
+
71
+ Add one import to the app `modules.d.ts`:
72
+
73
+ ```typescript
74
+ import '@ecopages/image-processor/types';
75
+ ```
76
+
77
+ That declares `ecopages:images`. Named exports are generated at dev/build time into
78
+ `node_modules/@types/ecopages-image-processor`, which TypeScript loads automatically.
79
+
71
80
  ### Components
72
81
 
73
- The plugin provides ready-to-use components for HTML (`@kitajs/html`) and React:
82
+ The plugin provides ready-to-use components for string HTML (KitaJS), Ecopages JSX, and React.
74
83
 
75
- **HTML Component:**
84
+ **HTML Component** (returns a markup string; use as a function, or in string-based JSX runtimes like KitaJS):
76
85
 
77
86
  ```typescript
78
87
  import { EcoImage } from '@ecopages/image-processor/component/html';
@@ -85,6 +94,14 @@ EcoImage({
85
94
  });
86
95
  ```
87
96
 
97
+ **Ecopages JSX Component:**
98
+
99
+ ```jsx
100
+ import { EcoImage } from '@ecopages/image-processor/component/jsx';
101
+
102
+ <EcoImage {...heroImage} alt="Hero banner" layout="constrained" priority />;
103
+ ```
104
+
88
105
  **React Component:**
89
106
 
90
107
  ```jsx
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ecopages/image-processor",
3
- "version": "0.2.1",
3
+ "version": "0.3.0",
4
4
  "description": "Image processor, transform and optimize images for web",
5
5
  "keywords": [
6
6
  "image",
@@ -9,20 +9,29 @@
9
9
  "license": "MIT",
10
10
  "main": "./src/image-processor.js",
11
11
  "type": "module",
12
+ "publishConfig": {
13
+ "access": "public"
14
+ },
12
15
  "repository": {
13
16
  "type": "git",
14
- "url": "https://github.com/ecopages/ecopages.git",
17
+ "url": "git+https://github.com/ecopages/ecopages.git",
15
18
  "directory": "packages/processors/image-processor"
16
19
  },
17
20
  "peerDependencies": {
18
- "@ecopages/core": "0.2.1"
21
+ "@ecopages/core": "0.3.0",
22
+ "@ecopages/jsx": "^0.4.0"
23
+ },
24
+ "peerDependenciesMeta": {
25
+ "@ecopages/jsx": {
26
+ "optional": true
27
+ }
19
28
  },
20
29
  "dependencies": {
21
- "@ecopages/file-system": "0.2.1",
30
+ "@ecopages/file-system": "0.3.0",
22
31
  "@ecopages/logger": "^0.2.3",
23
- "react": "^19",
24
- "react-dom": "^19",
25
- "sharp": "^0.34.5"
32
+ "react": "^19.2.6",
33
+ "react-dom": "^19.2.6",
34
+ "sharp": "^0.35.3"
26
35
  },
27
36
  "exports": {
28
37
  ".": {
@@ -30,34 +39,35 @@
30
39
  "types": "./src/index.d.ts"
31
40
  },
32
41
  "./types": {
33
- "types": "./src/types.d.ts"
42
+ "types": "./src/image-types.d.ts"
34
43
  },
35
44
  "./component/html": {
36
45
  "default": "./src/component/html.js",
37
46
  "types": "./src/component/html.d.ts"
38
47
  },
48
+ "./component/jsx": {
49
+ "default": "./src/component/jsx.js",
50
+ "types": "./src/component/jsx.d.ts"
51
+ },
39
52
  "./component/react": {
40
53
  "default": "./src/component/react.js",
41
54
  "types": "./src/component/react.d.ts"
42
55
  },
43
56
  "./types.ts": {
44
- "types": "./src/types.d.ts"
57
+ "types": "./src/image-types.d.ts"
45
58
  },
46
59
  "./component/html.ts": {
47
60
  "default": "./src/component/html.js",
48
61
  "types": "./src/component/html.d.ts"
49
62
  },
63
+ "./component/jsx.ts": {
64
+ "default": "./src/component/jsx.js",
65
+ "types": "./src/component/jsx.d.ts"
66
+ },
50
67
  "./component/react.ts": {
51
68
  "default": "./src/component/react.js",
52
69
  "types": "./src/component/react.d.ts"
53
70
  }
54
71
  },
55
- "typesVersions": {
56
- "*": {
57
- "ecopages:images": [
58
- "./virtual-module.d.ts"
59
- ]
60
- }
61
- },
62
72
  "types": "./src/index.d.ts"
63
- }
73
+ }
@@ -1,7 +1,13 @@
1
- import { renderer } from "../image-renderer.js";
2
- const EcoImage = (props) => {
3
- return renderer.renderToString(props);
4
- };
5
- export {
6
- EcoImage
1
+ /**
2
+ * Image component that renders the image as a string.
3
+ * @module @ecopages/image-processor/component/html
4
+ */
5
+ import { renderer } from '../image-renderer.js';
6
+ /**
7
+ * EcoImage
8
+ * This component generates the image element based on the provided props as a string
9
+ * @param props {@link EcoImageProps}
10
+ */
11
+ export const EcoImage = (props) => {
12
+ return renderer.renderToString(props);
7
13
  };
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Image component that renders as an Ecopages JSX element.
3
+ * @module @ecopages/image-processor/component/jsx
4
+ */
5
+ import { type JsxRenderable } from '@ecopages/jsx';
6
+ import { type EcoImageProps } from '../image-renderer.js';
7
+ /**
8
+ * EcoImage
9
+ * This component generates the image element based on the provided props as JSX
10
+ * @param props {@link EcoImageProps}
11
+ */
12
+ export declare const EcoImage: (props: EcoImageProps) => JsxRenderable;
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Image component that renders as an Ecopages JSX element.
3
+ * @module @ecopages/image-processor/component/jsx
4
+ */
5
+ import { jsx } from '@ecopages/jsx';
6
+ import { renderer } from '../image-renderer.js';
7
+ /**
8
+ * EcoImage
9
+ * This component generates the image element based on the provided props as JSX
10
+ * @param props {@link EcoImageProps}
11
+ */
12
+ export const EcoImage = (props) => {
13
+ const attributes = renderer.generateAttributes(props);
14
+ if (!attributes) {
15
+ return null;
16
+ }
17
+ return jsx('img', attributes);
18
+ };
@@ -1,11 +1,18 @@
1
- import { createElement } from "react";
2
- import { renderer } from "../image-renderer.js";
3
- const EcoImage = (props) => {
4
- return createElement("img", {
5
- ...renderer.generateAttributesJsx(props),
6
- suppressHydrationWarning: true
7
- });
8
- };
9
- export {
10
- EcoImage
1
+ /**
2
+ * Image component that renders the image as a string.
3
+ * @module @ecopages/image-processor/component/react
4
+ */
5
+ import { createElement } from 'react';
6
+ import { renderer } from '../image-renderer.js';
7
+ /**
8
+ * EcoImage
9
+ * This component generates the image element based on the provided props as JSX
10
+ * @param props {@link EcoImageProps}
11
+ * @returns
12
+ */
13
+ export const EcoImage = (props) => {
14
+ return createElement('img', {
15
+ ...renderer.generateAttributesJsx(props),
16
+ suppressHydrationWarning: true,
17
+ });
11
18
  };
package/src/constants.js CHANGED
@@ -1,4 +1,5 @@
1
- const DEFAULT_LAYOUT = "constrained";
2
- export {
3
- DEFAULT_LAYOUT
4
- };
1
+ /**
2
+ * Default image layout
3
+ * @constant "constrained"
4
+ */
5
+ export const DEFAULT_LAYOUT = 'constrained';
@@ -2,21 +2,13 @@
2
2
  * This file contains the plugins for bundling the image specifications.
3
3
  * @module @ecopages/image-processor/image-plugins
4
4
  */
5
- import type { EcoBuildPlugin } from '@ecopages/core/build/build-types';
5
+ import type { EcoBuildPlugin } from '@ecopages/core/processor';
6
6
  import type { ImageMap } from './plugin.js';
7
7
  /**
8
- * This function creates a plugin for bundling the image specifications.
9
- * https://bun.sh/docs/runtime/plugins#virtual-modules
10
- * @param exports
11
- * @returns
8
+ * Declares `ecopages:images` as a virtual module for server builds.
12
9
  */
13
10
  export declare function createImagePlugin(exports: ImageMap): EcoBuildPlugin;
14
11
  /**
15
- * This function creates a plugin for bundling the image specifications.
16
- * Due to some limitations in the bundler, we need to use a different approach.
17
- * https://bun.sh/docs/runtime/plugins#virtual-modules > bun-v1.2.5
18
- * (This feature is currently only available at runtime with Bun.plugin and not yet supported in the bundler, but you can mimic the behavior using onResolve and onLoad.)
19
- * @param exports
20
- * @returns
12
+ * Resolves `ecopages:images` with `onResolve` and `onLoad` for browser builds.
21
13
  */
22
14
  export declare function createImagePluginBundler(exports: ImageMap): EcoBuildPlugin;
@@ -1,33 +1,44 @@
1
- import { anyCaseToCamelCase } from "./utils.js";
1
+ /**
2
+ * This file contains the plugins for bundling the image specifications.
3
+ * @module @ecopages/image-processor/image-plugins
4
+ */
5
+ import { anyCaseToCamelCase } from './utils.js';
6
+ /**
7
+ * This function creates the plugin result for the image specifications.
8
+ */
2
9
  function createPluginResult(exports) {
3
- return {
4
- contents: `${Object.entries(exports).map(([key, value]) => `export const ${anyCaseToCamelCase(key)} = ${JSON.stringify(value)};`).join("\n")}`,
5
- loader: "ts"
6
- };
10
+ return {
11
+ contents: `${Object.entries(exports)
12
+ .map(([key, value]) => `export const ${anyCaseToCamelCase(key)} = ${JSON.stringify(value)};`)
13
+ .join('\n')}`,
14
+ loader: 'ts',
15
+ };
7
16
  }
8
- function createImagePlugin(exports) {
9
- return {
10
- name: "ecopages:images",
11
- setup(build) {
12
- build.module("ecopages:images", () => createPluginResult(exports));
13
- }
14
- };
17
+ /**
18
+ * Declares `ecopages:images` as a virtual module for server builds.
19
+ */
20
+ export function createImagePlugin(exports) {
21
+ return {
22
+ name: 'ecopages:images',
23
+ setup(build) {
24
+ build.module('ecopages:images', () => createPluginResult(exports));
25
+ },
26
+ };
15
27
  }
16
- function createImagePluginBundler(exports) {
17
- return {
18
- name: "ecopages:images",
19
- setup(build) {
20
- build.onResolve({ filter: /^ecopages:images$/ }, () => {
21
- return {
22
- namespace: "ecopages-images",
23
- path: "ecopages:images"
24
- };
25
- });
26
- build.onLoad({ filter: /.*/, namespace: "ecopages-images" }, () => createPluginResult(exports));
27
- }
28
- };
28
+ /**
29
+ * Resolves `ecopages:images` with `onResolve` and `onLoad` for browser builds.
30
+ */
31
+ export function createImagePluginBundler(exports) {
32
+ return {
33
+ name: 'ecopages:images',
34
+ setup(build) {
35
+ build.onResolve({ filter: /^ecopages:images$/ }, () => {
36
+ return {
37
+ namespace: 'ecopages-images',
38
+ path: 'ecopages:images',
39
+ };
40
+ });
41
+ build.onLoad({ filter: /.*/, namespace: 'ecopages-images' }, () => createPluginResult(exports));
42
+ },
43
+ };
29
44
  }
30
- export {
31
- createImagePlugin,
32
- createImagePluginBundler
33
- };
@@ -13,7 +13,13 @@ export declare class ImageProcessor {
13
13
  writeCache: <T>(key: string, data: T) => Promise<void>;
14
14
  });
15
15
  private calculateDimensions;
16
- private getOutputPath;
16
+ /**
17
+ * @remarks
18
+ * Includes encoding options so a quality or format change cannot reuse a previous
19
+ * variant. File names come from a hash of the encoded bytes, not this key.
20
+ */
21
+ private encodingCacheKey;
22
+ private writeEncodedVariant;
17
23
  processImage(imagePath: string): Promise<ImageSpecifications | null>;
18
24
  processDirectory(): Promise<ImageMap>;
19
25
  }