Skip to content

Commit cce2a00

Browse files
committed
refactor(images): separate client and server image utilities for improved organization and functionality
1 parent baf988c commit cce2a00

File tree

6 files changed

+100
-69
lines changed

6 files changed

+100
-69
lines changed

.eslintcache

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

app/components/ProxiedPrismicImage.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
* Much simpler than the previous implementation.
77
*/
88
import type { PrismicImageProps } from '@prismicio/vue'
9-
import { generateSrcSet, transformImageField } from '../../utils/prismic-images'
9+
import { generateSrcSet, transformImageField } from '../../utils/prismic-images-client'
1010
1111
const props = defineProps<PrismicImageProps & {
1212
width?: number | string

modules/prismic-images.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import process from 'node:process'
88
import { defineNuxtModule } from '@nuxt/kit'
99
import consola from 'consola'
1010
import environment from '../lib/env'
11-
import { downloadMissingImages, fetchPrismicImages } from '../utils/prismic-images'
11+
import { downloadMissingImages, fetchPrismicImages } from '../utils/prismic-images-server'
1212

1313
const prismicAccessToken = process.env.PRISMIC_ACCESS_TOKEN!
1414

shared/utils/image-proxy.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import type { ImageField } from '@prismicio/client'
2-
import { transformImageUrl } from '../../utils/prismic-images'
2+
import { transformImageUrl } from '../../utils/prismic-images-client'
33

44
export function transformImageFieldToLocal(baseUrl: string, field: ImageField): ImageField {
55
if (!field.url)

utils/prismic-images-client.ts

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
/**
2+
* Client-safe Prismic image utilities
3+
* These functions can be used in Vue components and other client-side code
4+
*/
5+
6+
const IMAGE_FOLDER = 'assets/images/prismic'
7+
8+
// Transform Prismic URL to local URL (client-safe)
9+
export function transformImageUrl(baseUrl: string, url: string): string {
10+
if (!url?.includes('prismic'))
11+
return url
12+
13+
const fileName = normalizeFileName(url.split('/').pop() || 'image')
14+
return `${baseUrl.replace(/\/$/, '')}/${IMAGE_FOLDER}/${fileName}`
15+
}
16+
17+
// Transform image field with responsive variants (client-safe)
18+
export function transformImageField(baseUrl: string, field: any): any {
19+
const transformed = { ...field }
20+
21+
if (field.url) {
22+
transformed.url = transformImageUrl(baseUrl, field.url)
23+
}
24+
25+
// Handle responsive variants
26+
const responsiveViews = ['Lg', 'Md', 'Sm', 'Xs'] as const
27+
for (const view of responsiveViews) {
28+
const variant = (field as any)[view]
29+
if (variant?.url) {
30+
(transformed as any)[view] = {
31+
...variant,
32+
url: transformImageUrl(baseUrl, variant.url),
33+
}
34+
}
35+
}
36+
37+
return transformed
38+
}
39+
40+
// Generate srcSet from transformed field (client-safe)
41+
export function generateSrcSet(field: any, widths?: number[] | string): { src: string, srcSet: string } {
42+
const defaultWidths = [640, 768, 1024, 1280, 1536]
43+
const _targetWidths = widths || defaultWidths
44+
45+
const src = field.url || ''
46+
const srcSetEntries: string[] = []
47+
48+
// Add main image
49+
if (src && field.dimensions?.width) {
50+
srcSetEntries.push(`${src} ${field.dimensions.width}w`)
51+
}
52+
53+
// Add responsive variants
54+
const responsiveViews = ['Xs', 'Sm', 'Md', 'Lg'] as const
55+
for (const view of responsiveViews) {
56+
const variant = (field as any)[view]
57+
if (variant?.url && variant.dimensions?.width) {
58+
srcSetEntries.push(`${variant.url} ${variant.dimensions.width}w`)
59+
}
60+
}
61+
62+
return {
63+
src,
64+
srcSet: srcSetEntries.join(', '),
65+
}
66+
}
67+
68+
// Client-safe filename normalization
69+
function normalizeFileName(fileName: string): string {
70+
// Extract just the base filename and extension, removing Prismic URL parameters
71+
// Example: "image.png_auto_compress_format_rect_0_0_100_100" -> "image.png"
72+
const extensionMatch = fileName.match(/\.(jpg|jpeg|png|gif|webp|svg|avif)/i)
73+
if (extensionMatch) {
74+
const extensionIndex = fileName.indexOf(extensionMatch[0])
75+
const baseFileName = fileName.substring(0, extensionIndex + extensionMatch[0].length)
76+
fileName = baseFileName
77+
}
78+
79+
return fileName
80+
.replace(/%([0-9A-F]{2})/gi, (_, hex) => {
81+
const char = String.fromCharCode(Number.parseInt(hex, 16))
82+
return /[\w.-]/.test(char) ? char : '_'
83+
})
84+
.replace(/[^\w.-]/g, '_')
85+
.replace(/_+/g, '_')
86+
.replace(/^_+|_+$/g, '') || 'image'
87+
}

utils/prismic-images.ts renamed to utils/prismic-images-server.ts

Lines changed: 9 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
/**
2+
* Server-only Prismic image utilities
3+
* These functions use Node.js APIs and can only run on the server
4+
*/
15
import type { BlogPageDocument, ExchangeDocument, NavigationDocument, PageDocument } from '~~/prismicio-types'
26
import { filter } from '@prismicio/client'
37
import consola from 'consola'
@@ -16,67 +20,7 @@ export interface ImageInfo {
1620

1721
const IMAGE_FOLDER = 'assets/images/prismic'
1822

19-
// Transform Prismic URL to local URL
20-
export function transformImageUrl(baseUrl: string, url: string): string {
21-
if (!url?.includes('prismic'))
22-
return url
23-
24-
const fileName = normalizeFileName(url.split('/').pop() || 'image')
25-
return `${baseUrl.replace(/\/$/, '')}/${IMAGE_FOLDER}/${fileName}`
26-
}
27-
28-
// Transform image field with responsive variants
29-
export function transformImageField(baseUrl: string, field: any): any {
30-
const transformed = { ...field }
31-
32-
if (field.url) {
33-
transformed.url = transformImageUrl(baseUrl, field.url)
34-
}
35-
36-
// Handle responsive variants
37-
const responsiveViews = ['Lg', 'Md', 'Sm', 'Xs'] as const
38-
for (const view of responsiveViews) {
39-
const variant = (field as any)[view]
40-
if (variant?.url) {
41-
(transformed as any)[view] = {
42-
...variant,
43-
url: transformImageUrl(baseUrl, variant.url),
44-
}
45-
}
46-
}
47-
48-
return transformed
49-
}
50-
51-
// Generate srcSet from transformed field
52-
export function generateSrcSet(field: any, widths?: number[] | string): { src: string, srcSet: string } {
53-
const defaultWidths = [640, 768, 1024, 1280, 1536]
54-
const _targetWidths = widths || defaultWidths
55-
56-
const src = field.url || ''
57-
const srcSetEntries: string[] = []
58-
59-
// Add main image
60-
if (src && field.dimensions?.width) {
61-
srcSetEntries.push(`${src} ${field.dimensions.width}w`)
62-
}
63-
64-
// Add responsive variants
65-
const responsiveViews = ['Xs', 'Sm', 'Md', 'Lg'] as const
66-
for (const view of responsiveViews) {
67-
const variant = (field as any)[view]
68-
if (variant?.url && variant.dimensions?.width) {
69-
srcSetEntries.push(`${variant.url} ${variant.dimensions.width}w`)
70-
}
71-
}
72-
73-
return {
74-
src,
75-
srcSet: srcSetEntries.join(', '),
76-
}
77-
}
78-
79-
// Extract all images from Prismic document
23+
// Extract all images from Prismic document (server-only)
8024
export function extractImagesFromDocument(baseUrl: string, document: any): ImageInfo[] {
8125
const images: ImageInfo[] = []
8226

@@ -152,7 +96,7 @@ function normalizeFileName(fileName: string): string {
15296
.replace(/^_+|_+$/g, '') || 'image'
15397
}
15498

155-
// Fetch all Prismic data and extract images
99+
// Fetch all Prismic data and extract images (server-only)
156100
export async function fetchPrismicImages(prismicAccessToken: string, showDrafts = false): Promise<ImageInfo[]> {
157101
consola.info('🌐 Fetching Prismic data...')
158102

@@ -183,7 +127,7 @@ export async function fetchPrismicImages(prismicAccessToken: string, showDrafts
183127
return uniqueImages
184128
}
185129

186-
// Download missing images
130+
// Download missing images (server-only)
187131
export async function downloadMissingImages(images: ImageInfo[]): Promise<void> {
188132
if (import.meta.client)
189133
return
@@ -271,7 +215,7 @@ async function findMissingImages(images: ImageInfo[]): Promise<ImageInfo[]> {
271215
}
272216
}
273217

274-
// Prismic API helpers
218+
// Prismic API helpers (server-only)
275219
async function fetchDocuments<T>(
276220
documentType: string,
277221
prismicAccessToken: string,
@@ -306,7 +250,7 @@ async function fetchDocument<T>(
306250
return response.results[0] || null
307251
}
308252
catch (error) {
309-
console.warn(`⚠️ Failed to fetch ${documentType}:`, error)
253+
consola.warn(`⚠️ Failed to fetch ${documentType}:`, error)
310254
return null
311255
}
312256
}

0 commit comments

Comments
 (0)