Skip to content

Commit

Permalink
feat(common): add cloudflare loader (#47082)
Browse files Browse the repository at this point in the history
Closes #46315

PR Close #47082
  • Loading branch information
khempenius authored and Pawel Kozlowski committed Aug 16, 2022
1 parent 3836ebb commit bff870d
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 0 deletions.
@@ -0,0 +1,60 @@
/**
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/

import {Provider, ɵ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 {IMAGE_LOADER, ImageLoaderConfig} from './image_loader';

/**
* Function that generates a built-in ImageLoader for Cloudflare Image Resizing
* and turns it into an Angular provider. Note: Cloudflare has multiple image
* products - this provider is specifically for Cloudflare Image Resizing;
* it will not work with Cloudflare Images or Cloudflare Polish.
*
* @param path Your domain name
* 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);

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;
}
}];

if (ngDevMode && Boolean(options.ensurePreconnect) === true) {
providers.push({provide: PRECONNECT_CHECK_BLOCKLIST, useValue: [path], multi: true});
}

return providers;
}

function throwInvalidPathError(path: unknown): never {
throw new RuntimeError(
RuntimeErrorCode.INVALID_INPUT,
`CloudflareLoader has detected an invalid path: ` +
`expecting a path like https://<ZONE>/cdn-cgi/image/<OPTIONS>/<SOURCE-IMAGE>` +
`but got: \`${path}\``);
}
18 changes: 18 additions & 0 deletions packages/common/test/image_loaders/image_loader_spec.ts
Expand Up @@ -7,6 +7,7 @@
*/

import {IMAGE_LOADER, ImageLoader, PRECONNECT_CHECK_BLOCKLIST} from '@angular/common/src/directives/ng_optimized_image';
import {provideCloudflareLoader} from '@angular/common/src/directives/ng_optimized_image/image_loaders/cloudflare_loader';
import {provideCloudinaryLoader} from '@angular/common/src/directives/ng_optimized_image/image_loaders/cloudinary_loader';
import {provideImageKitLoader} from '@angular/common/src/directives/ng_optimized_image/image_loaders/imagekit_loader';
import {provideImgixLoader} from '@angular/common/src/directives/ng_optimized_image/image_loaders/imgix_loader';
Expand Down Expand Up @@ -246,4 +247,21 @@ describe('Built-in image directive loaders', () => {
});
});
});

describe('Cloudflare loader', () => {
function createCloudflareLoader(path: string): ImageLoader {
const injector = createEnvironmentInjector([provideCloudflareLoader(path)]);
return injector.get(IMAGE_LOADER);
}
it('should construct an image loader with the given path', () => {
const loader = createCloudflareLoader('https://mysite.com');
let config = {src: 'img.png'};
expect(loader(config)).toBe('https://mysite.com/cdn-cgi/image/format=auto/img.png');
});
it('should construct an image loader with the given path', () => {
const loader = createCloudflareLoader('https://mysite.com');
const config = {src: 'img.png', width: 100};
expect(loader(config)).toBe('https://mysite.com/cdn-cgi/image/format=auto,width=100/img.png');
});
});
});

0 comments on commit bff870d

Please sign in to comment.