Saltar al contenido principal

cfSrc y cfSrcSet

Paquetes: @tiendana/ngx-core/ui @tiendana/api-types

Directivas para cargar imágenes transformando URLs al endpoint de CloudFront (cloudfront.net).

Tipo Attachment

El tipo Attachment proviene de @tiendana/api-types y representa objetos de archivos en la plataforma Tiendana.

cfSrc​

Directiva para el atributo src. Soporta URLs string, File objects y Attachment con preview local.

Características​

✅ Transforma URLs a cloudfront.net
✅ Preview local de File objects vía FileReader
✅ Soporte para Attachment de @tiendana/api-types
✅ Fallback automático en error
✅ Signals reactivos

API​

InputTipoDescripción
cfSrcstring | File | Attachment | nullFuente de la imagen
defaultCfsrcstringImagen por defecto

Uso Básico​

// URL simple
<img [cfSrc]="'assets/images/logo.svg'" />

// Attachment
<img [cfSrc]="product().image" />

Con File Preview​

@Component({
template: `
<input type="file" (change)="onFileChange($event)">

@if (selectedFile()) {
<img [cfSrc]="selectedFile()!" />
}
`
})
export class FilePreviewComponent {
selectedFile = signal<File | null>(null);

onFileChange(event: Event) {
const input = event.target as HTMLInputElement;
if (input.files?.[0]) {
this.selectedFile.set(input.files[0]);
}
}
}

Fallback Personalizado​

<img 
[cfSrc]="user.avatar"
[defaultCfsrc]="'assets/icons/default-avatar.svg'"
/>

cfSrcSet​

Directiva para el atributo srcset en elementos <source>.

API​

InputTipoDescripción
cfSrcSetstring | Attachment | nullFuente para srcset
defaultCfsrcSetstringFallback por defecto

Uso con Picture​

<picture>
<source
[cfSrcSet]="'images/hero-2x.jpg'"
media="(min-width: 1200px)"
/>
<source
[cfSrcSet]="'images/hero-1x.jpg'"
/>
<img [cfSrc]="'images/hero.jpg'" />
</picture>

Diferencia con cdnSrc​

DirectivaEndpointUso
cdnSrc / cdnSrcSetcdn-public.tiendana.comEndpoint privado de Tiendana. No se exporta desde @tiendana/ngx-core/ui (ver cdnSrc)
cfSrc / cfSrcSetcloudfront.netCloudFront directo

Ambas siguen el mismo patrón; la diferencia es el endpoint de destino:

// cdnSrc → cdn-public.tiendana.com
<img [cdnSrc]="'assets/logo.svg'" />
<!-- → https://cdn-public.tiendana.com/assets/logo.svg -->

// cfSrc → cloudfront.net
<img [cfSrc]="'assets/logo.svg'" />
<!-- → https://d1234abcd.cloudfront.net/assets/logo.svg -->

Responsive Images​

Art Direction​

<picture>
<source
[cfSrcSet]="'banners/desktop-wide.jpg'"
media="(min-width: 1024px)"
/>
<source
[cfSrcSet]="'banners/tablet-square.jpg'"
media="(min-width: 768px)"
/>
<img [cfSrc]="'banners/mobile-vertical.jpg'" />
</picture>

Selectores​

cfSrc actúa sobre img[cfSrc] y source[cfSrc]; cfSrcSet solo sobre source[cfSrcSet]. No existe un cfSrcSet para <img>: para cambiar de resolución usa <picture> con varios <source>.

Con Attachment Objects​

interface Product {
images: {
thumbnail: Attachment;
medium: Attachment;
large: Attachment;
}
}

<picture>
<source
[cfSrcSet]="product.images.large"
media="(min-width: 1024px)"
/>
<source
[cfSrcSet]="product.images.medium"
media="(min-width: 768px)"
/>
<img [cfSrc]="product.images.thumbnail" />
</picture>

WebP Support​

<picture>
<source
[cfSrcSet]="'images/hero.webp'"
type="image/webp"
/>
<source
[cfSrcSet]="'images/hero.jpg'"
type="image/jpeg"
/>
<img [cfSrc]="'images/hero.jpg'" />
</picture>

Implementación Interna​

cfSrc Transform​

transform: value => {
if (typeof value === 'string') {
return getCloudfrontUrl(value);
} else if (value instanceof File) {
this.readFile(value); // FileReader + Observable
return null;
} else if (value) {
return getCloudfrontUrlAttachment(value);
}
return null;
}

Computed Source​

Prioridad: File preview → Fallback → cfSrc → Default

src = computed(() => {
return this.localFilePreview()
?? this.sourceFallback()
?? this.cfSrc()
?? this.defaultCfsrc();
});

Error Handling​

@HostListener('error')
onError(): void {
if (currentSrc === this.localFilePreview()) {
this.localFilePreview.set(null);
}
this.sourceFallback.set(this.defaultCfsrc());
}

Upload con Preview​

@Component({
template: `
<label for="upload">
@if (preview()) {
<img [cfSrc]="preview()!" class="preview" />
} @else {
<div class="placeholder">Subir imagen</div>
}
</label>
<input
id="upload"
type="file"
(change)="handleFile($event)"
accept="image/*"
>
`
})
export class ImageUploadComponent {
preview = signal<File | null>(null);

handleFile(event: Event) {
const input = event.target as HTMLInputElement;
if (input.files?.[0]) {
this.preview.set(input.files[0]);
}
}
}

Performance​

  • FileReader asíncrono (no bloquea UI)
  • Observable con take(1) para auto-complete
  • Computed signal reactivo
  • Cache de navegador para default images

Accesibilidad​

<img 
[cfSrc]="product.image"
[alt]="product.name"
loading="lazy"
width="800"
height="600"
/>

Directivas Relacionadas​

  • cdnSrc / cdnSrcSet: usa el endpoint cdn-public.tiendana.com en lugar de cloudfront.net, pero no está exportada en la API pública