Skip to content

Commit 887dd39

Browse files
YoannMa11bit
andauthored
Add support for SEO-friendly filenames in generated URL (#78)
* Add support for SEO-friendly filenames * Add changesets --------- Co-authored-by: Ivan Buryak <ivan.buryak@gmail.com>
1 parent 47680b9 commit 887dd39

6 files changed

Lines changed: 90 additions & 0 deletions

File tree

.changeset/gentle-hounds-relate.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@imgproxy/imgproxy-js-core": minor
3+
---
4+
5+
Add support for SEO-friendly filenames in generated URLs. The `URL` object passed to `generateUrl()` and `generateImageInfoUrl()` now accepts an optional `filename` field, which is appended to `base64` and `encrypted` URLs (see [`IMGPROXY_BASE64_URL_INCLUDES_FILENAME`](https://docs.imgproxy.net/configuration/options#source-image-urls)). Thanks @YoannMa!

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ The `imgproxy-js-core` library exposes a method called `generateUrl`, which take
8686
- `plain`: A plain URL.
8787
- `base64`: A base64 encoded URL.
8888
- `encoded`: An AES-CBC encrypted URL.
89+
- `filename` (optional): A SEO-friendly filename that will be appended to `base64` or `encrypted` URLs (requires [`IMGPROXY_BASE64_URL_INCLUDES_FILENAME`](https://docs.imgproxy.net/configuration/options#source-image-urls) to be enabled on the imgproxy server). Not allowed for `plain` URLs.
8990
- `options` (optional): An object that contains [imgproxy options](https://docs.imgproxy.net/generating_the_url?id=processing-options).
9091

9192
For a detailed description of the available options, please refer to the [imgproxy documentation](https://docs.imgproxy.net/generating_the_url?id=processing-options), as well as the option types files in the `imgproxy-js-core` library.
@@ -106,6 +107,7 @@ The `imgproxy-js-core` library exposes a method called `generateImageInfoUrl`, w
106107
- `plain`: A plain URL.
107108
- `base64`: A base64 encoded URL.
108109
- `encoded`: An AES-CBC encrypted URL.
110+
- `filename` (optional): A SEO-friendly filename that will be appended to `base64` or `encrypted` URLs (requires [`IMGPROXY_BASE64_URL_INCLUDES_FILENAME`](https://docs.imgproxy.net/configuration/options#source-image-urls) to be enabled on the imgproxy server). Not allowed for `plain` URLs.
109111
- `options` (optional): An object that contains [imgproxy options](https://docs.imgproxy.net/getting_the_image_info?id=info-options).
110112

111113
For a detailed description of the available options, please refer to the [imgproxy documentation](https://docs.imgproxy.net/getting_the_image_info?id=info-options), as well as the option types files in the `imgproxy-js-core` library.

src/methods/generateImageInfoUrl.test.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,4 +115,37 @@ describe("generateImageInfoUrl", () => {
115115
)
116116
).toEqual("/test:test2/plain/https://example.com/host/pic.png");
117117
});
118+
119+
it("should return base64 url with SEO friendly filename", () => {
120+
expect(
121+
generateUrl({
122+
value: "aHR0cHM6Ly9leGFtcGxlLmNvbS9pbWFnZS9waWMucG5n",
123+
filename: "pic.png",
124+
type: "base64",
125+
})
126+
).toEqual("/aHR0cHM6Ly9leGFtcGxlLmNvbS9pbWFnZS9waWMucG5n/pic.png");
127+
});
128+
129+
it("should return encrypted url with SEO friendly filename", () => {
130+
expect(
131+
generateUrl({
132+
value:
133+
"hLhDnxN9acjq3LDooARQ3t6OU1UwAG1IeXsM2b7qxOyMP4DF+GsbBdnG1K9B0+bz",
134+
filename: "pic.png",
135+
type: "encrypted",
136+
})
137+
).toEqual(
138+
"/enc/hLhDnxN9acjq3LDooARQ3t6OU1UwAG1IeXsM2b7qxOyMP4DF+GsbBdnG1K9B0+bz/pic.png"
139+
);
140+
});
141+
142+
it("should throw an error if url.filename is set on a plain url", () => {
143+
expect(() =>
144+
generateUrl({
145+
value: "https://example.com/host/pic.png",
146+
type: "plain",
147+
filename: "pic.png",
148+
})
149+
).toThrow("url.filename is only valid for base64 or encrypted url");
150+
});
118151
});

src/methods/generateImageInfoUrl.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ const correctUrlTypes = {
1212
export type URLImageInfo = {
1313
value: string;
1414
type: "plain" | "base64" | "encrypted";
15+
filename?: string;
1516
};
1617

1718
const allModules = Object.values(optionModules);
@@ -30,6 +31,10 @@ const generateImageInfoUrl = (
3031
);
3132
guardIsValidVal(correctUrlTypes, url.type, "url.type");
3233

34+
if (url.filename && url.type === "plain") {
35+
throw new Error("url.filename is only valid for base64 or encrypted url");
36+
}
37+
3338
let optsPart = "";
3439
if (options) {
3540
const modules = settings?.onlyPresets ? presetOnlyModule : allModules;
@@ -52,6 +57,10 @@ const generateImageInfoUrl = (
5257
urlPart = `/enc/${url.value}`;
5358
}
5459

60+
if (url.filename) {
61+
urlPart += `/${url.filename}`;
62+
}
63+
5564
return `${optsPart}${urlPart}`;
5665
};
5766

src/methods/generateUrl.test.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,4 +93,37 @@ describe("generateUrl", () => {
9393
)
9494
).toEqual("/preset1:preset2/plain/https://example.com/host/pic.png");
9595
});
96+
97+
it("should return base64 url with SEO friendly filename", () => {
98+
expect(
99+
generateUrl({
100+
value: "aHR0cHM6Ly9leGFtcGxlLmNvbS9pbWFnZS9waWMucG5n",
101+
filename: "pic.png",
102+
type: "base64",
103+
})
104+
).toEqual("/aHR0cHM6Ly9leGFtcGxlLmNvbS9pbWFnZS9waWMucG5n/pic.png");
105+
});
106+
107+
it("should return encrypted url with SEO friendly filename", () => {
108+
expect(
109+
generateUrl({
110+
value:
111+
"hLhDnxN9acjq3LDooARQ3t6OU1UwAG1IeXsM2b7qxOyMP4DF+GsbBdnG1K9B0+bz",
112+
filename: "pic.png",
113+
type: "encrypted",
114+
})
115+
).toEqual(
116+
"/enc/hLhDnxN9acjq3LDooARQ3t6OU1UwAG1IeXsM2b7qxOyMP4DF+GsbBdnG1K9B0+bz/pic.png"
117+
);
118+
});
119+
120+
it("should throw an error if url.filename is set on a plain url", () => {
121+
expect(() =>
122+
generateUrl({
123+
value: "https://example.com/host/pic.png",
124+
type: "plain",
125+
filename: "pic.png",
126+
})
127+
).toThrow("url.filename is only valid for base64 or encrypted url");
128+
});
96129
});

src/methods/generateUrl.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,10 @@ const generateUrl = (
2626
);
2727
guardIsValidVal(correctUrlTypes, url.type, "url.type");
2828

29+
if (url.filename && url.type === "plain") {
30+
throw new Error("url.filename is only valid for base64 or encrypted url");
31+
}
32+
2933
let optsPart = "";
3034
if (options) {
3135
const modules = settings?.onlyPresets ? presetOnlyModule : allModules;
@@ -48,6 +52,10 @@ const generateUrl = (
4852
urlPart = `/enc/${url.value}`;
4953
}
5054

55+
if (url.filename) {
56+
urlPart += `/${url.filename}`;
57+
}
58+
5159
return `${optsPart}${urlPart}`;
5260
};
5361

0 commit comments

Comments
 (0)