Skip to content

Commit e495754

Browse files
committed
feat: Added support for local images. Improved automated tests. Made the demo consume the latest development snapshot.
1 parent aac2ee7 commit e495754

File tree

8 files changed

+98
-23
lines changed

8 files changed

+98
-23
lines changed

README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,13 @@ Alternatively, in case you're using a custom proxy, set the proxy domain.
5858
NEXT_PUBLIC_UPLOADCARE_CUSTOM_PROXY_DOMAIN="proxy.example.com"
5959
```
6060

61+
Then set the app base path (to get relative image urls processed in Production):
62+
63+
```ini
64+
#.env
65+
NEXT_PUBLIC_UPLOADCARE_APP_BASE_PATH="https://example.com/"
66+
```
67+
6168
That's it. You may now use `@uploadcare/nextjs-loader` in your app (see [Usage](#usage)).
6269

6370
---

example/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
},
1111
"dependencies": {
1212
"next": "11.1.2",
13-
"@uploadcare/nextjs-loader": "*",
13+
"@uploadcare/nextjs-loader": "uploadcare/nextjs-loader#main",
1414
"react": "17.0.2",
1515
"react-dom": "17.0.2"
1616
},

example/pages/_app.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
import '../styles/globals.css'
21
import type { AppProps } from 'next/app'
2+
import { ReactElement } from 'react'
3+
import '../styles/globals.css'
34

4-
function MyApp({ Component, pageProps }: AppProps) {
5+
function MyApp({ Component, pageProps }: AppProps): ReactElement {
56
return <Component {...pageProps} />
67
}
78
export default MyApp

example/pages/index.tsx

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,15 @@ const Home: NextPage = () => (
6767
width={64}
6868
height={64}
6969
loader={uploadcareLoader}
70+
/>
71+
<hr className={styles.hr} />
72+
<p>Local image will be served AS IS in Development, and converted to the absolute URL and passed to the proxy in Production</p>
73+
<Image
74+
alt="A local image"
75+
src="/local_image.png"
76+
width={494}
77+
height={332}
78+
loader={uploadcareLoader}
7079
/>
7180
<hr className={styles.hr} />
7281
Checkout the documentation for{' '}

example/public/local_image.png

4.88 KB
Loading

example/yarn.lock

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,10 @@
284284
"@typescript-eslint/types" "4.33.0"
285285
eslint-visitor-keys "^2.0.0"
286286

287+
"@uploadcare/nextjs-loader@uploadcare/nextjs-loader#main":
288+
version "0.1.0"
289+
resolved "https://codeload.github.com/uploadcare/nextjs-loader/tar.gz/e9e1ba5c62374cfbc30ec79c3f1ccf0aaa9dbcb3"
290+
287291
acorn-jsx@^5.3.1:
288292
version "5.3.2"
289293
resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937"
@@ -3144,11 +3148,6 @@ unpipe@1.0.0:
31443148
resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec"
31453149
integrity sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=
31463150

3147-
uploadcare-nextjs-loader1@*:
3148-
version "0.1.0"
3149-
resolved "https://registry.yarnpkg.com/uploadcare-nextjs-loader1/-/uploadcare-nextjs-loader1-0.1.0.tgz#9c28a377ff76d06c5773ec5beb01d7e5f09ddeed"
3150-
integrity sha512-zU9pXyj2O8krjrgULAvuk/T6PaED0tUULS6OvEJsA11jbSjU5PSNhc3RRZJYkfr8bHWQ6JK1RsdYA9OAAQlkLQ==
3151-
31523151
uri-js@^4.2.2:
31533152
version "4.4.1"
31543153
resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e"

src/__tests__/uploadcare-loader.spec.ts

Lines changed: 57 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,24 +7,57 @@ describe('uploadcareLoader', () => {
77
cleanup();
88
});
99

10-
test("The loader validates the 'src' parameter", () => {
10+
test("The loader returns relative 'src' AS IS in Development environment", () => {
1111
addEnvVar('NEXT_PUBLIC_UPLOADCARE_PUBLIC_KEY', 'test-public-key');
1212

1313
const src = '/relative/image.jpg';
1414

15-
const t = () => {
15+
const result =
1616
uploadcareLoader({
1717
src,
1818
width: 0,
1919
quality: 80
2020
});
21-
};
2221

23-
expect(t).toThrow(
24-
`Failed to parse "${src}" in "uploadcareLoader", Uploadcare loader doesn't support relative images.`
25-
);
22+
expect(result).toEqual(src);
23+
24+
removeEnvVar('NEXT_PUBLIC_UPLOADCARE_PUBLIC_KEY');
25+
});
26+
27+
test("The loader builds up a relative 'src' to the absolute URL and passes it to the proxy in Production environment", () => {
28+
addEnvVar('NEXT_PUBLIC_UPLOADCARE_PUBLIC_KEY', 'test-public-key');
29+
addEnvVar('NODE_ENV', 'production');
30+
31+
// When the base path is not set through env vars.
32+
33+
const src = '/relative/image.jpg';
34+
35+
let result =
36+
uploadcareLoader({
37+
src,
38+
width: 0,
39+
quality: 80
40+
});
41+
42+
expect(result).toEqual(src);
43+
44+
// When the base path is set through env vars.
45+
46+
const basePath = 'https://example.com';
47+
addEnvVar('NEXT_PUBLIC_UPLOADCARE_APP_BASE_PATH', basePath);
48+
49+
result =
50+
uploadcareLoader({
51+
src,
52+
width: 0,
53+
quality: 80
54+
});
55+
56+
expect(result).toEqual(`${basePath}${src}`);
2657

58+
removeEnvVar('NEXT_PUBLIC_UPLOADCARE_APP_BASE_PATH');
2759
removeEnvVar('NEXT_PUBLIC_UPLOADCARE_PUBLIC_KEY');
60+
removeEnvVar('NODE_ENV');
2861
});
2962

3063
test('The loader requires either a public key or a custom proxy domain', () => {
@@ -117,7 +150,7 @@ describe('uploadcareLoader', () => {
117150
removeEnvVar('NEXT_PUBLIC_UPLOADCARE_TRANSFORMATION_PARAMETERS');
118151
});
119152

120-
test("The loader doesn't process SVG and GIF", () => {
153+
test("The loader doesn't process SVG and GIF (absolute url)", () => {
121154
const src = 'https:/example.com/image.svg';
122155

123156
addEnvVar('NEXT_PUBLIC_UPLOADCARE_PUBLIC_KEY', 'test-public-key');
@@ -128,7 +161,23 @@ describe('uploadcareLoader', () => {
128161
quality: 80
129162
});
130163

131-
expect(result).toBe(`https://test-public-key.ucr.io${src}`);
164+
expect(result).toBe(src);
165+
166+
removeEnvVar('NEXT_PUBLIC_UPLOADCARE_PUBLIC_KEY');
167+
});
168+
169+
test("The loader doesn't process SVG and GIF (relative url)", () => {
170+
const src = '/image.svg';
171+
172+
addEnvVar('NEXT_PUBLIC_UPLOADCARE_PUBLIC_KEY', 'test-public-key');
173+
174+
const result = uploadcareLoader({
175+
src,
176+
width: 500,
177+
quality: 80
178+
});
179+
180+
expect(result).toBe(src);
132181

133182
removeEnvVar('NEXT_PUBLIC_UPLOADCARE_PUBLIC_KEY');
134183
});

src/utils/loader.ts

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,9 @@ export function uploadcareLoader({
3838
const proxyEndpoint =
3939
customProxyEndpoint || generateDefaultProxyEndpoint(publicKey);
4040

41-
const root = trimTrailingSlash(proxyEndpoint);
41+
const basePath = trimTrailingSlash(process.env.NEXT_PUBLIC_UPLOADCARE_APP_BASE_PATH || '');
42+
43+
const proxy = trimTrailingSlash(proxyEndpoint);
4244

4345
const isOnCdn = isCdnUrl(src, cdnDomain);
4446

@@ -53,19 +55,27 @@ export function uploadcareLoader({
5355
}
5456

5557
if (src.startsWith('/')) {
56-
throw new Error(
57-
`Failed to parse "${src}" in "uploadcareLoader", Uploadcare loader doesn't support relative images.`
58-
);
58+
return src;
59+
}
60+
}
61+
62+
// Process local images in Production.
63+
if (isProduction() && !isOnCdn && src.startsWith('/')) {
64+
const isBasePathSet = !isDotenvParamEmpty(basePath);
65+
66+
if (!isBasePathSet) {
67+
return src;
5968
}
69+
70+
return `${basePath}${src}`;
6071
}
6172

6273
const filename = getFilename(src);
6374
const extension = getExtension(filename);
6475

6576
// Some extensions are not processed by Uploadcare, e.g. SVG.
6677
if (NOT_PROCESSED_EXTENSIONS.includes(extension)) {
67-
// @todo: Test non-CDN urls.
68-
return isOnCdn ? src : `${root}${src}`;
78+
return isOnCdn ? src : `${basePath}${src}`;
6979
}
7080

7181
// Demo: https://ucarecdn.com/a6f8abc8-f92e-460a-b7a1-c5cd70a18cdb/-/format/auto/-/resize/300x/vercel.png
@@ -94,5 +104,5 @@ export function uploadcareLoader({
94104
return `${withoutFilename}${apiParamsString}${filename}`;
95105
}
96106

97-
return `${root}${apiParamsString}${src}`;
107+
return `${proxy}${apiParamsString}${src}`;
98108
}

0 commit comments

Comments
 (0)