astro-lqip 1.4.0 → 1.5.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
@@ -9,6 +9,14 @@
9
9
 
10
10
  Native extended Astro components for generating low quality image placeholders (LQIP).
11
11
 
12
+ ## ✨ Features
13
+ - 🖼️ Supports both `<Image>` and `<Picture>` components.
14
+ - 🎨 Multiple LQIP techniques: base64, solid color, CSS via gradients and SVG.
15
+ - 🚀 Easy to use, just replace the native Astro components with the ones from [astro-lqip](https://astro-lqip.web.app/).
16
+ - 🔧 Fully compatible with [Astro's image optimization features](https://docs.astro.build/en/guides/images/).
17
+ - 🌍 Supports both local and remote images.
18
+ - ⚙️ Supports SSR mode with [Node Adapter](https://docs.astro.build/en/guides/integrations-guide/node/).
19
+
12
20
  ## ⬇️ Installation
13
21
 
14
22
  NPM:
@@ -73,7 +81,7 @@ Both `<Image>` and `<Picture>` components support all the props of the [native A
73
81
  - `lqipSize`: The size of the LQIP image, which can be any number from `4` to `64`. (default is 4)
74
82
 
75
83
  > [!WARNING]
76
- > A major size in the `lqipSize` prop can significantly impact the performance of your application.
84
+ > A high value for `lqipSize` can significantly increase the total size of your website.
77
85
 
78
86
  Example:
79
87
 
@@ -92,15 +100,6 @@ import otherImage from './path/to/other-image.png';
92
100
  > [!TIP]
93
101
  > For the `<Image>` component, a `parentAttributes` prop similar to `pictureAttributes` has been added.
94
102
 
95
- ## 📝 ToDo
96
-
97
- - [x] Add support for Image component.
98
- - [x] Add support for more lqip techniques.
99
- - [x] Test for remote images.
100
- - [x] Optimize current CSS usage.
101
- - [x] Improve docs page.
102
- - [ ] Test support for SSR mode.
103
-
104
103
  ## 💡 Knowledge
105
104
 
106
105
  Since this integration is built on top of Astro native `<Image>` and `<Picture>` components, you can refer to the [Astro documentation](https://docs.astro.build/en/guides/images/) for more information on how to use it.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "astro-lqip",
3
- "version": "1.4.0",
3
+ "version": "1.5.0",
4
4
  "description": "Native extended Astro components for generating low quality image placeholders (LQIP).",
5
5
  "keywords": [
6
6
  "astro",
@@ -37,18 +37,18 @@
37
37
  "plaiceholder": "3.0.0"
38
38
  },
39
39
  "devDependencies": {
40
- "@eslint/js": "9.36.0",
41
- "@typescript-eslint/parser": "8.44.1",
42
- "astro": "5.13.11",
43
- "bumpp": "10.2.3",
44
- "eslint": "9.36.0",
40
+ "@eslint/js": "9.37.0",
41
+ "@typescript-eslint/parser": "8.46.1",
42
+ "astro": "5.14.5",
43
+ "bumpp": "10.3.1",
44
+ "eslint": "9.37.0",
45
45
  "eslint-plugin-astro": "1.3.1",
46
- "eslint-plugin-jsonc": "2.20.1",
46
+ "eslint-plugin-jsonc": "2.21.0",
47
47
  "eslint-plugin-jsx-a11y": "6.10.2",
48
- "eslint-plugin-package-json": "0.56.3",
49
- "eslint-plugin-yml": "1.18.0",
48
+ "eslint-plugin-package-json": "0.56.4",
49
+ "eslint-plugin-yml": "1.19.0",
50
50
  "globals": "16.4.0",
51
- "jiti": "2.6.0",
51
+ "jiti": "2.6.1",
52
52
  "nano-staged": "0.8.0",
53
53
  "neostandard": "0.12.2",
54
54
  "simple-git-hooks": "2.13.1"
@@ -16,13 +16,15 @@ type Props = (LocalImageProps | RemoteImageProps) & LqipProps & {
16
16
  const { class: className, lqip = 'base64', lqipSize = 4, parentAttributes = {}, ...props } = Astro.props as Props
17
17
 
18
18
  const isDevelopment = import.meta.env.MODE === 'development'
19
+ const isPrerendered = Astro.isPrerendered
19
20
 
20
21
  const { combinedStyle } = await useLqipImage({
21
22
  src: props.src,
22
23
  lqip,
23
24
  lqipSize,
24
25
  styleProps: parentAttributes.style ?? {},
25
- isDevelopment
26
+ isDevelopment,
27
+ isPrerendered
26
28
  })
27
29
 
28
30
  const combinedParentAttributes = {
@@ -13,13 +13,15 @@ type Props = AstroPictureProps & LqipProps
13
13
  const { class: className, lqip = 'base64', lqipSize = 4, pictureAttributes = {}, ...props } = Astro.props as Props
14
14
 
15
15
  const isDevelopment = import.meta.env.MODE === 'development'
16
+ const isPrerendered = Astro.isPrerendered
16
17
 
17
18
  const { combinedStyle } = await useLqipImage({
18
19
  src: props.src,
19
20
  lqip,
20
21
  lqipSize,
21
22
  styleProps: pictureAttributes.style ?? {},
22
- isDevelopment
23
+ isDevelopment,
24
+ isPrerendered
23
25
  })
24
26
 
25
27
  const combinedPictureAttributes = {
@@ -2,9 +2,10 @@ import type { LqipType } from './lqip.type'
2
2
 
3
3
  export type ComponentsOptions = {
4
4
  src: string | object
5
- lqip?: LqipType
6
- lqipSize?: number
7
- styleProps?: Record<string, any>
8
- forbiddenVars?: string[]
9
- isDevelopment?: boolean
5
+ lqip: LqipType
6
+ lqipSize: number
7
+ styleProps: Record<string, any>
8
+ forbiddenVars: string[]
9
+ isDevelopment: boolean | undefined
10
+ isPrerendered: boolean | undefined
10
11
  }
@@ -0,0 +1 @@
1
+ export type ImagePath = string | { src: string } | Promise<{ default: { src: string } }>
@@ -1,4 +1,5 @@
1
1
  export * from './components-options.type'
2
+ export * from './image-path.type'
2
3
  export * from './lqip.type'
3
4
  export * from './plaiceholder.type'
4
5
  export * from './props.type'
@@ -6,7 +6,12 @@ import { PREFIX } from '../constants'
6
6
 
7
7
  import { getPlaiceholder } from 'plaiceholder'
8
8
 
9
- export async function generateLqip(imagePath: string, isDevelopment: boolean, lqipType: LqipType, lqipSize: number) {
9
+ export async function generateLqip(
10
+ imagePath: string,
11
+ lqipType: LqipType,
12
+ lqipSize: number,
13
+ isDevelopment: boolean | undefined
14
+ ) {
10
15
  try {
11
16
  const buffer = await readFile(imagePath)
12
17
  const plaiceholderResult = await getPlaiceholder(buffer, { size: lqipSize })
@@ -18,7 +18,13 @@ async function ensureCacheDir() {
18
18
  }
19
19
  }
20
20
 
21
- export async function getLqip(imagePath: { src: string }, isDevelopment: boolean, lqipType: LqipType, lqipSize: number) {
21
+ export async function getLqip(
22
+ imagePath: { src: string },
23
+ lqipType: LqipType,
24
+ lqipSize: number,
25
+ isDevelopment: boolean | undefined,
26
+ isPrerendered: boolean | undefined
27
+ ) {
22
28
  if (!imagePath?.src) return undefined
23
29
 
24
30
  if (isRemoteUrl(imagePath.src)) {
@@ -33,7 +39,7 @@ export async function getLqip(imagePath: { src: string }, isDevelopment: boolean
33
39
  await writeFile(tempPath, buffer)
34
40
 
35
41
  try {
36
- const lqip = await generateLqip(tempPath, isDevelopment, lqipType, lqipSize)
42
+ const lqip = await generateLqip(tempPath, lqipType, lqipSize, isDevelopment)
37
43
  return lqip
38
44
  } finally {
39
45
  await unlink(tempPath)
@@ -42,12 +48,17 @@ export async function getLqip(imagePath: { src: string }, isDevelopment: boolean
42
48
 
43
49
  if (isDevelopment && imagePath.src.startsWith('/@fs/')) {
44
50
  const filePath = imagePath.src.replace(/^\/@fs/, '').split('?')[0]
45
- return await generateLqip(filePath, isDevelopment, lqipType, lqipSize)
51
+ return await generateLqip(filePath, lqipType, lqipSize, isDevelopment)
52
+ }
53
+
54
+ if (!isPrerendered && !isDevelopment) {
55
+ const filePath = join(process.cwd(), 'dist', 'client', imagePath.src)
56
+ return await generateLqip(filePath, lqipType, lqipSize, isDevelopment)
46
57
  }
47
58
 
48
59
  if (!isDevelopment && imagePath.src.startsWith('/_astro/')) {
49
60
  const buildPath = join(process.cwd(), 'dist', imagePath.src)
50
- return await generateLqip(buildPath, isDevelopment, lqipType, lqipSize)
61
+ return await generateLqip(buildPath, lqipType, lqipSize, isDevelopment)
51
62
  }
52
63
 
53
64
  return undefined
@@ -1,6 +1,10 @@
1
- export async function resolveImagePath(path: string | { src: string }) {
1
+ import type { ImagePath } from '../types'
2
+
3
+ export async function resolveImagePath(path: ImagePath) {
2
4
  // If it's a string, we can't resolve it here. ex: Remote images URLs
3
5
  if (typeof path === 'string') return null
6
+ // Handle dynamic imports
7
+ if ('then' in path && typeof path.then === 'function') return (await path).default
4
8
  if ('src' in path) return path
5
9
  return null
6
10
  }
@@ -13,7 +13,8 @@ export async function useLqipImage({
13
13
  lqipSize = 4,
14
14
  styleProps = {},
15
15
  forbiddenVars = ['--lqip-background', '--z-index', '--opacity'],
16
- isDevelopment = false
16
+ isDevelopment,
17
+ isPrerendered
17
18
  }: ComponentsOptions) {
18
19
  let getImagePath: string | { src: string } | null
19
20
 
@@ -28,7 +29,7 @@ export async function useLqipImage({
28
29
  let lqipImage
29
30
  if (getImagePath) {
30
31
  const lqipInput = typeof getImagePath === 'string' ? { src: getImagePath } : getImagePath
31
- lqipImage = await getLqip(lqipInput, isDevelopment, lqip, lqipSize)
32
+ lqipImage = await getLqip(lqipInput, lqip, lqipSize, isDevelopment, isPrerendered)
32
33
  }
33
34
 
34
35
  let svgHTML = ''