mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
refactor(common): remove code duplication in loaders (#47082)
This change introduces common infrastructure for image loaders. This removes code duplication and makes it easier to write loaders - a loader author just needs to provide a loader config to the URL mapping function. PR Close #47082
This commit is contained in:
committed by
Pawel Kozlowski
parent
bff870db61
commit
c23f32c38e
+13
-27
@@ -6,13 +6,12 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {Provider, ɵRuntimeError as RuntimeError} from '@angular/core';
|
||||
import {ɵRuntimeError as RuntimeError} from '@angular/core';
|
||||
|
||||
import {RuntimeErrorCode} from '../../../errors';
|
||||
import {PRECONNECT_CHECK_BLOCKLIST} from '../preconnect_link_checker';
|
||||
import {isValidPath, normalizePath, normalizeSrc} from '../util';
|
||||
import {normalizeSrc} from '../util';
|
||||
|
||||
import {IMAGE_LOADER, ImageLoaderConfig} from './image_loader';
|
||||
import {createImageLoader, ImageLoaderConfig} from './image_loader';
|
||||
|
||||
/**
|
||||
* Function that generates a built-in ImageLoader for Cloudflare Image Resizing
|
||||
@@ -24,31 +23,18 @@ import {IMAGE_LOADER, ImageLoaderConfig} from './image_loader';
|
||||
* e.g. https://mysite.com
|
||||
* @returns Provider that provides an ImageLoader function
|
||||
*/
|
||||
export function provideCloudflareLoader(path: string, options: {ensurePreconnect?: boolean} = {
|
||||
ensurePreconnect: true
|
||||
}) {
|
||||
if (ngDevMode && !isValidPath(path)) {
|
||||
throwInvalidPathError(path);
|
||||
}
|
||||
path = normalizePath(path);
|
||||
export const provideCloudflareLoader =
|
||||
createImageLoader(cloudflareLoaderFactory, throwInvalidPathError);
|
||||
|
||||
const providers: Provider[] = [{
|
||||
provide: IMAGE_LOADER,
|
||||
useValue: (config: ImageLoaderConfig) => {
|
||||
let params = `format=auto`;
|
||||
if (config.width) {
|
||||
params += `,width=${config.width.toString()}`;
|
||||
}
|
||||
const url = `${path}/cdn-cgi/image/${params}/${normalizeSrc(config.src)}`;
|
||||
return url;
|
||||
function cloudflareLoaderFactory(path: string) {
|
||||
return (config: ImageLoaderConfig) => {
|
||||
let params = `format=auto`;
|
||||
if (config.width) {
|
||||
params += `,width=${config.width.toString()}`;
|
||||
}
|
||||
}];
|
||||
|
||||
if (ngDevMode && Boolean(options.ensurePreconnect) === true) {
|
||||
providers.push({provide: PRECONNECT_CHECK_BLOCKLIST, useValue: [path], multi: true});
|
||||
}
|
||||
|
||||
return providers;
|
||||
const url = `${path}/cdn-cgi/image/${params}/${normalizeSrc(config.src)}`;
|
||||
return url;
|
||||
};
|
||||
}
|
||||
|
||||
function throwInvalidPathError(path: unknown): never {
|
||||
|
||||
+15
-33
@@ -6,13 +6,12 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {Provider, ɵRuntimeError as RuntimeError} from '@angular/core';
|
||||
import {ɵRuntimeError as RuntimeError} from '@angular/core';
|
||||
|
||||
import {RuntimeErrorCode} from '../../../errors';
|
||||
import {PRECONNECT_CHECK_BLOCKLIST} from '../preconnect_link_checker';
|
||||
import {isValidPath, normalizePath, normalizeSrc} from '../util';
|
||||
import {normalizeSrc} from '../util';
|
||||
|
||||
import {IMAGE_LOADER, ImageLoaderConfig} from './image_loader';
|
||||
import {createImageLoader, ImageLoaderConfig} from './image_loader';
|
||||
|
||||
/**
|
||||
* Function that generates a built-in ImageLoader for Cloudinary
|
||||
@@ -29,37 +28,20 @@ import {IMAGE_LOADER, ImageLoaderConfig} from './image_loader';
|
||||
* present in the document's `<head>`.
|
||||
* @returns Set of providers to configure the Cloudinary loader.
|
||||
*/
|
||||
export function provideCloudinaryLoader(path: string, options: {ensurePreconnect?: boolean} = {
|
||||
ensurePreconnect: true
|
||||
}): Provider[] {
|
||||
if (ngDevMode && !isValidPath(path)) {
|
||||
throwInvalidPathError(path);
|
||||
}
|
||||
path = normalizePath(path);
|
||||
export const provideCloudinaryLoader =
|
||||
createImageLoader(cloudinaryLoaderFactory, throwInvalidPathError);
|
||||
|
||||
const providers: Provider[] = [{
|
||||
provide: IMAGE_LOADER,
|
||||
useValue: (config: ImageLoaderConfig) => {
|
||||
// Example of a Cloudinary image URL:
|
||||
// https://res.cloudinary.com/mysite/image/upload/c_scale,f_auto,q_auto,w_600/marketing/tile-topics-m.png
|
||||
let params = `f_auto,q_auto`; // sets image format and quality to "auto"
|
||||
if (config.width) {
|
||||
params += `,w_${config.width}`;
|
||||
}
|
||||
const url = `${path}/image/upload/${params}/${normalizeSrc(config.src)}`;
|
||||
return url;
|
||||
function cloudinaryLoaderFactory(path: string) {
|
||||
return (config: ImageLoaderConfig) => {
|
||||
// Example of a Cloudinary image URL:
|
||||
// https://res.cloudinary.com/mysite/image/upload/c_scale,f_auto,q_auto,w_600/marketing/tile-topics-m.png
|
||||
let params = `f_auto,q_auto`; // sets image format and quality to "auto"
|
||||
if (config.width) {
|
||||
params += `,w_${config.width}`;
|
||||
}
|
||||
}];
|
||||
|
||||
if (ngDevMode && Boolean(options.ensurePreconnect) === true) {
|
||||
providers.push({
|
||||
provide: PRECONNECT_CHECK_BLOCKLIST,
|
||||
useValue: [path],
|
||||
multi: true,
|
||||
});
|
||||
}
|
||||
|
||||
return providers;
|
||||
const url = `${path}/image/upload/${params}/${normalizeSrc(config.src)}`;
|
||||
return url;
|
||||
};
|
||||
}
|
||||
|
||||
function throwInvalidPathError(path: unknown): never {
|
||||
|
||||
@@ -6,7 +6,10 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {InjectionToken} from '@angular/core';
|
||||
import {InjectionToken, Provider} from '@angular/core';
|
||||
|
||||
import {PRECONNECT_CHECK_BLOCKLIST} from '../preconnect_link_checker';
|
||||
import {isValidPath, normalizePath, normalizeSrc} from '../util';
|
||||
|
||||
/**
|
||||
* Config options recognized by the image loader function.
|
||||
@@ -37,3 +40,24 @@ export const IMAGE_LOADER = new InjectionToken<ImageLoader>('ImageLoader', {
|
||||
providedIn: 'root',
|
||||
factory: () => noopImageLoader,
|
||||
});
|
||||
|
||||
export function createImageLoader(
|
||||
urlFn: (path: string) => ImageLoader,
|
||||
invalidPathFn: (path: unknown) => void,
|
||||
) {
|
||||
return function provideImageLoader(
|
||||
path: string, options: {ensurePreconnect?: boolean} = {ensurePreconnect: true}) {
|
||||
if (ngDevMode && !isValidPath(path)) {
|
||||
invalidPathFn(path);
|
||||
}
|
||||
path = normalizePath(path);
|
||||
|
||||
const providers: Provider[] = [{provide: IMAGE_LOADER, useValue: urlFn(path)}];
|
||||
|
||||
if (ngDevMode && Boolean(options.ensurePreconnect) === true) {
|
||||
providers.push({provide: PRECONNECT_CHECK_BLOCKLIST, useValue: [path], multi: true});
|
||||
}
|
||||
|
||||
return providers;
|
||||
};
|
||||
}
|
||||
|
||||
+15
-33
@@ -6,13 +6,12 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {Provider, ɵRuntimeError as RuntimeError} from '@angular/core';
|
||||
import {ɵRuntimeError as RuntimeError} from '@angular/core';
|
||||
|
||||
import {RuntimeErrorCode} from '../../../errors';
|
||||
import {PRECONNECT_CHECK_BLOCKLIST} from '../preconnect_link_checker';
|
||||
import {isValidPath, normalizePath, normalizeSrc} from '../util';
|
||||
import {normalizeSrc} from '../util';
|
||||
|
||||
import {IMAGE_LOADER, ImageLoaderConfig} from './image_loader';
|
||||
import {createImageLoader, ImageLoaderConfig} from './image_loader';
|
||||
|
||||
/**
|
||||
* Function that generates a built-in ImageLoader for ImageKit
|
||||
@@ -28,37 +27,20 @@ import {IMAGE_LOADER, ImageLoaderConfig} from './image_loader';
|
||||
* present in the document's `<head>`.
|
||||
* @returns Set of providers to configure the ImageKit loader.
|
||||
*/
|
||||
export function provideImageKitLoader(path: string, options: {ensurePreconnect?: boolean} = {
|
||||
ensurePreconnect: true
|
||||
}): Provider[] {
|
||||
if (ngDevMode && !isValidPath(path)) {
|
||||
throwInvalidPathError(path);
|
||||
}
|
||||
path = normalizePath(path);
|
||||
export const provideImageKitLoader =
|
||||
createImageLoader(imagekitLoaderFactory, throwInvalidPathError);
|
||||
|
||||
const providers: Provider[] = [{
|
||||
provide: IMAGE_LOADER,
|
||||
useValue: (config: ImageLoaderConfig) => {
|
||||
// Example of an ImageKit image URL:
|
||||
// https://ik.imagekit.io/demo/tr:w-300,h-300/medium_cafe_B1iTdD0C.jpg
|
||||
let params = `tr:q-auto`; // applies the "auto quality" transformation
|
||||
if (config.width) {
|
||||
params += `,w-${config.width?.toString()}`;
|
||||
}
|
||||
const url = `${path}/${params}/${normalizeSrc(config.src)}`;
|
||||
return url;
|
||||
export function imagekitLoaderFactory(path: string) {
|
||||
return (config: ImageLoaderConfig) => {
|
||||
// Example of an ImageKit image URL:
|
||||
// https://ik.imagekit.io/demo/tr:w-300,h-300/medium_cafe_B1iTdD0C.jpg
|
||||
let params = `tr:q-auto`; // applies the "auto quality" transformation
|
||||
if (config.width) {
|
||||
params += `,w-${config.width?.toString()}`;
|
||||
}
|
||||
}];
|
||||
|
||||
if (ngDevMode && Boolean(options.ensurePreconnect) === true) {
|
||||
providers.push({
|
||||
provide: PRECONNECT_CHECK_BLOCKLIST,
|
||||
useValue: [path],
|
||||
multi: true,
|
||||
});
|
||||
}
|
||||
|
||||
return providers;
|
||||
const url = `${path}/${params}/${normalizeSrc(config.src)}`;
|
||||
return url;
|
||||
};
|
||||
}
|
||||
|
||||
function throwInvalidPathError(path: unknown): never {
|
||||
|
||||
@@ -6,13 +6,12 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {Provider, ɵRuntimeError as RuntimeError} from '@angular/core';
|
||||
import {ɵRuntimeError as RuntimeError} from '@angular/core';
|
||||
|
||||
import {RuntimeErrorCode} from '../../../errors';
|
||||
import {PRECONNECT_CHECK_BLOCKLIST} from '../preconnect_link_checker';
|
||||
import {isValidPath, normalizePath, normalizeSrc} from '../util';
|
||||
import {normalizeSrc} from '../util';
|
||||
|
||||
import {IMAGE_LOADER, ImageLoaderConfig} from './image_loader';
|
||||
import {createImageLoader, ImageLoaderConfig} from './image_loader';
|
||||
|
||||
/**
|
||||
* Function that generates a built-in ImageLoader for Imgix and turns it
|
||||
@@ -26,34 +25,16 @@ import {IMAGE_LOADER, ImageLoaderConfig} from './image_loader';
|
||||
* present in the document's `<head>`.
|
||||
* @returns Set of providers to configure the Imgix loader.
|
||||
*/
|
||||
export function provideImgixLoader(path: string, options: {ensurePreconnect?: boolean} = {
|
||||
ensurePreconnect: true
|
||||
}): Provider[] {
|
||||
if (ngDevMode && !isValidPath(path)) {
|
||||
throwInvalidPathError(path);
|
||||
}
|
||||
path = normalizePath(path);
|
||||
export const provideImgixLoader = createImageLoader(imgixLoaderFactory, throwInvalidPathError);
|
||||
|
||||
const providers: Provider[] = [{
|
||||
provide: IMAGE_LOADER,
|
||||
useValue: (config: ImageLoaderConfig) => {
|
||||
const url = new URL(`${path}/${normalizeSrc(config.src)}`);
|
||||
// This setting ensures the smallest allowable format is set.
|
||||
url.searchParams.set('auto', 'format');
|
||||
config.width && url.searchParams.set('w', config.width.toString());
|
||||
return url.href;
|
||||
}
|
||||
}];
|
||||
|
||||
if (ngDevMode && Boolean(options.ensurePreconnect) === true) {
|
||||
providers.push({
|
||||
provide: PRECONNECT_CHECK_BLOCKLIST,
|
||||
useValue: [path],
|
||||
multi: true,
|
||||
});
|
||||
}
|
||||
|
||||
return providers;
|
||||
function imgixLoaderFactory(path: string) {
|
||||
return (config: ImageLoaderConfig) => {
|
||||
const url = new URL(`${path}/${normalizeSrc(config.src)}`);
|
||||
// This setting ensures the smallest allowable format is set.
|
||||
url.searchParams.set('auto', 'format');
|
||||
config.width && url.searchParams.set('w', config.width.toString());
|
||||
return url.href;
|
||||
};
|
||||
}
|
||||
|
||||
function throwInvalidPathError(path: unknown): never {
|
||||
|
||||
Reference in New Issue
Block a user