@lonik/oh-image 1.2.0 → 1.2.2

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
@@ -1,30 +1,40 @@
1
- # react-components-starter
1
+ # Oh Image
2
2
 
3
- A starter for creating a React component library.
3
+ The missing `<Image />` component for Vite and React.
4
4
 
5
- ## Development
5
+ For full documentation, visit [docs](https://lukonik.github.io/oh-image).
6
6
 
7
- - Install dependencies:
7
+ ## Installation
8
8
 
9
9
  ```bash
10
- npm install
10
+ npm install @lonik/oh-image sharp --save
11
11
  ```
12
12
 
13
- - Run the playground:
13
+ ## Usage
14
14
 
15
- ```bash
16
- npm run play
17
- ```
15
+ ### 1. Register the Vite plugin
18
16
 
19
- - Run the unit tests:
17
+ ```ts
18
+ // vite.config.ts
19
+ import { defineConfig } from "vite";
20
+ import react from "@vitejs/plugin-react";
21
+ import { ohImage } from "@lonik/oh-image/plugin";
20
22
 
21
- ```bash
22
- npm run test
23
+ export default defineConfig({
24
+ plugins: [react(), ohImage()],
25
+ });
23
26
  ```
24
27
 
25
- - Build the library:
28
+ ### 2. Use the Image component
26
29
 
27
- ```bash
28
- npm run build
30
+ ```tsx
31
+ import { Image } from "@lonik/oh-image/react";
32
+ import heroImg from "./hero.jpg?oh";
33
+
34
+ function App() {
35
+ return <Image src={heroImg} alt="Hero" />;
36
+ }
29
37
  ```
30
- # tsdown-template
38
+ ## License
39
+
40
+ [MIT](./LICENSE)
package/dist/plugin.d.ts CHANGED
@@ -14,8 +14,6 @@ interface ImageOptions {
14
14
  height?: number | null;
15
15
  /** Output format for the main image (e.g., 'webp', 'avif', 'png') */
16
16
  format?: keyof FormatEnum | null;
17
- /** Blur amount (true for default blur, or a number for sigma value) */
18
- blur?: number | boolean;
19
17
  /** Whether to generate a placeholder image for lazy loading */
20
18
  placeholder?: boolean;
21
19
  /** Breakpoints array - widths in pixels for responsive srcSet generation */
package/dist/plugin.js CHANGED
@@ -1,13 +1,14 @@
1
1
  import { basename, dirname, extname, join, parse } from "node:path";
2
- import { randomBytes } from "node:crypto";
2
+ import { createHash } from "node:crypto";
3
3
  import { mkdir, readFile, writeFile } from "node:fs/promises";
4
4
  import queryString from "query-string";
5
5
  import sharp from "sharp";
6
6
  import pLimit from "p-limit";
7
7
 
8
8
  //#region src/plugin/utils.ts
9
- function getRandomString(length = 32) {
10
- return randomBytes(Math.ceil(length * 3 / 4)).toString("base64").slice(0, length).replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
9
+ async function getFileHash(filePath) {
10
+ const content = await readFile(filePath);
11
+ return createHash("sha256").update(content).digest("hex").slice(0, 16);
11
12
  }
12
13
  async function readFileSafe(path) {
13
14
  try {
@@ -79,7 +80,7 @@ const DEFAULT_CONFIGS = {
79
80
  1920
80
81
  ],
81
82
  format: "webp",
82
- placeholder: false
83
+ placeholder: true
83
84
  };
84
85
  const PROCESS_KEY = "oh";
85
86
  const SUPPORTED_IMAGE_FORMATS = /\.(jpe?g|png|webp|avif|gif|svg)(\?.*)?$/i;
@@ -102,9 +103,8 @@ function ohImage(options) {
102
103
  const fileId = basename(url);
103
104
  return join(cacheDir, fileId);
104
105
  }
105
- function genIdentifier(uri, format, prefix) {
106
- const fileId = basename(uri);
107
- const uniqueFileId = `${prefix}-${getRandomString()}-${fileId}.${format}`;
106
+ function genIdentifier(uri, format, prefix, hash) {
107
+ const uniqueFileId = `${prefix}-${hash}-${basename(uri)}.${format}`;
108
108
  if (!isBuild) return join(DEV_DIR, uniqueFileId);
109
109
  return join(assetsDir, config.distDir, uniqueFileId);
110
110
  }
@@ -150,11 +150,12 @@ function ohImage(options) {
150
150
  const origin = parsed.path;
151
151
  const { name, ext } = parse(parsed.path);
152
152
  const metadata = await sharp(parsed.path).metadata();
153
+ const hash = await getFileHash(origin);
153
154
  const mergedOptions = {
154
155
  ...config,
155
156
  ...parsed.options
156
157
  };
157
- const mainIdentifier = genIdentifier(name, mergedOptions.format ?? ext.slice(1), "main");
158
+ const mainIdentifier = genIdentifier(name, mergedOptions.format ?? ext.slice(1), "main", hash);
158
159
  const mainEntry = {
159
160
  width: mergedOptions.width,
160
161
  height: mergedOptions.height,
@@ -178,7 +179,7 @@ function ohImage(options) {
178
179
  placeholderWidth = Math.max(Math.round(metadata.width / metadata.height * PLACEHOLDER_IMG_SIZE), 1);
179
180
  placeholderHeight = PLACEHOLDER_IMG_SIZE;
180
181
  }
181
- const placeholderIdentifier = genIdentifier(name, DEFAULT_IMAGE_FORMAT, "placeholder");
182
+ const placeholderIdentifier = genIdentifier(name, DEFAULT_IMAGE_FORMAT, "placeholder", hash);
182
183
  const placeholderEntry = {
183
184
  width: placeholderWidth,
184
185
  height: placeholderHeight,
@@ -192,7 +193,7 @@ function ohImage(options) {
192
193
  if (mergedOptions.bps) {
193
194
  const srcSets = [];
194
195
  for (const breakpoint of mergedOptions.bps) {
195
- const srcSetIdentifier = genIdentifier(name, DEFAULT_IMAGE_FORMAT, `breakpoint-${breakpoint}`);
196
+ const srcSetIdentifier = genIdentifier(name, DEFAULT_IMAGE_FORMAT, `breakpoint-${breakpoint}`, hash);
196
197
  const srcSetEntry = {
197
198
  width: breakpoint,
198
199
  format: DEFAULT_IMAGE_FORMAT,
package/dist/react.d.ts CHANGED
@@ -21,7 +21,9 @@ declare module "*?oh" {
21
21
  //#endregion
22
22
  //#region src/react/types.d.ts
23
23
  type ImageSrcType = string | ImageSrc;
24
- interface ImageProps extends Partial<Pick<ImgHTMLAttributes<HTMLImageElement>, "alt" | "fetchPriority" | "decoding" | "loading" | "height" | "width" | "srcSet" | "className" | "sizes" | "style">> {
24
+ interface ImageProps extends Partial<Pick<ImgHTMLAttributes<HTMLImageElement>, "fetchPriority" | "decoding" | "loading" | "height" | "width" | "srcSet" | "className" | "sizes" | "style">> {
25
+ /** Alternative text for the image, required for accessibility. Use an empty string for decorative images. */
26
+ alt: string;
25
27
  /** Configures the Image component to load the image immediately. */
26
28
  asap?: boolean;
27
29
  /** */
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@lonik/oh-image",
3
3
  "type": "module",
4
- "version": "1.2.0",
4
+ "version": "1.2.2",
5
5
  "description": "A React component library for optimized image handling.",
6
6
  "author": "Luka Onikadze <lukonik@gmail.com>",
7
7
  "license": "MIT",
@@ -73,5 +73,14 @@
73
73
  "dependencies": {
74
74
  "p-limit": "^7.3.0",
75
75
  "query-string": "^9.3.1"
76
- }
76
+ },
77
+ "keywords": [
78
+ "react",
79
+ "reactjs",
80
+ "react-components",
81
+ "react-component-library",
82
+ "vite",
83
+ "vitejs",
84
+ "vite-plugin"
85
+ ]
77
86
  }