cfSrc y cfSrcSet
Paquetes: @tiendana/ngx-core/ui @tiendana/api-types
Directivas para cargar imágenes transformando URLs al endpoint de CloudFront (cloudfront.net).
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
| Input | Tipo | Descripción |
|---|---|---|
cfSrc | string | File | Attachment | null | Fuente de la imagen |
defaultCfsrc | string | Imagen 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
| Input | Tipo | Descripción |
|---|---|---|
cfSrcSet | string | Attachment | null | Fuente para srcset |
defaultCfsrcSet | string | Fallback 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
| Directiva | Endpoint | Uso |
|---|---|---|
cdnSrc / cdnSrcSet | cdn-public.tiendana.com | Endpoint privado de Tiendana. No se exporta desde @tiendana/ngx-core/ui (ver cdnSrc) |
cfSrc / cfSrcSet | cloudfront.net | CloudFront 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.comen lugar decloudfront.net, pero no está exportada en la API pública