Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat!: new syntax for providers #133

Merged
merged 64 commits into from
Jan 19, 2025
Merged
Show file tree
Hide file tree
Changes from 45 commits
Commits
Show all changes
64 commits
Select commit Hold shift + click to select a range
263b7ed
wip
ascorbic Oct 6, 2024
16cce40
wip
ascorbic Oct 7, 2024
c8d98f4
wip more
ascorbic Oct 8, 2024
147129f
add contentstack
ascorbic Oct 9, 2024
9b9ace8
wip lots more
ascorbic Oct 11, 2024
fd496d0
Cloudinary
ascorbic Oct 13, 2024
f0aea48
Update
ascorbic Oct 13, 2024
7ccec13
Add ipx
ascorbic Oct 13, 2024
5d7d96f
Merge branch 'v1' into new-syntax
ascorbic Oct 14, 2024
bd11983
format
ascorbic Oct 14, 2024
1b3124a
Remove test
ascorbic Oct 14, 2024
6dbdda3
Change config syntax
ascorbic Oct 15, 2024
a75332e
Add more
ascorbic Oct 15, 2024
3d1761c
Add scene7 and vercel
ascorbic Oct 15, 2024
4607a91
chore: format
ascorbic Oct 15, 2024
4decbf9
Add shopify
ascorbic Oct 15, 2024
7f4b493
Simplify extractors
ascorbic Oct 16, 2024
479923b
chore: format
ascorbic Oct 16, 2024
0f1f0d5
Add uploadcare
ascorbic Oct 20, 2024
cd75260
Add wordpress
ascorbic Oct 20, 2024
f5e1f9d
Add storyblok and cf images
ascorbic Oct 20, 2024
38c2dab
Rename
ascorbic Oct 20, 2024
a956e12
Remove old
ascorbic Oct 20, 2024
7080604
chore: format
ascorbic Oct 22, 2024
0846378
Update
ascorbic Oct 22, 2024
21df6ea
Fix tests and build
ascorbic Oct 22, 2024
4c784c0
chore: format
ascorbic Oct 22, 2024
bafaeb2
Merge branch 'main' into new-syntax
ascorbic Oct 26, 2024
28e2fce
Merge branch 'main' into new-syntax
ascorbic Oct 27, 2024
86e07f0
feat: add support for cloudflare images without custom domain (#131)
ascorbic Oct 27, 2024
3e87b14
chore: add deprecation
ascorbic Oct 27, 2024
609f593
chore: format
ascorbic Oct 27, 2024
bbf10c2
Add async
ascorbic Oct 27, 2024
c011fb5
fix: simplify types
ascorbic Oct 27, 2024
897ec69
chore: format
ascorbic Oct 27, 2024
c9dea57
chore: lint
ascorbic Oct 27, 2024
0f60447
fix: include detected cdn
ascorbic Oct 27, 2024
6c1a8c3
fix: strip unsupported props
ascorbic Oct 27, 2024
461ffc3
chore: tests and docs
ascorbic Oct 27, 2024
7d93546
chore: remove duplicate definition
ascorbic Oct 27, 2024
6644649
chore: format
ascorbic Oct 27, 2024
e4e6135
chore: rename types
ascorbic Oct 27, 2024
3b6cc9c
chore: format
ascorbic Oct 27, 2024
7f9928f
chore: lint
ascorbic Oct 27, 2024
180448d
Change transformUrl syntax back to original
ascorbic Nov 30, 2024
181fecf
Update README
ascorbic Dec 1, 2024
a19f3d2
Add upgrading docs
ascorbic Dec 1, 2024
32c7b9d
Add Hygraph support
ascorbic Dec 1, 2024
a2ce9bf
Update demo
ascorbic Dec 1, 2024
055796a
Merge branch 'main' into new-syntax
ascorbic Dec 1, 2024
46c897d
Fix
ascorbic Dec 1, 2024
81c124b
Fix exports
ascorbic Dec 14, 2024
d1c2d3e
Fix cloudinary
ascorbic Dec 15, 2024
89a96dc
Add transformerfunction type
ascorbic Dec 15, 2024
a54de8d
ci: add pkg.pr.new (#153)
ascorbic Dec 15, 2024
458ca7d
Update Astro support for v5
ascorbic Dec 15, 2024
cffd0af
Merge branch 'main' into new-syntax
ascorbic Dec 15, 2024
d2222b1
Only pass needed props
ascorbic Dec 17, 2024
54f0337
Don't override options from URL with undefined ops
ascorbic Dec 28, 2024
5991ab7
Add names list
ascorbic Jan 18, 2025
eb5b899
Merge branch 'main' into new-syntax
ascorbic Jan 18, 2025
665a377
As const
ascorbic Jan 18, 2025
384f824
Names
ascorbic Jan 18, 2025
23b1781
Update contrib guide
ascorbic Jan 19, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
"[javascriptreact]": {
"editor.defaultFormatter": "denoland.vscode-deno"
},
"deno.config": "deno.jsonc",
"prettier.enable": false,
"editor.defaultFormatter": "denoland.vscode-deno"
}
4 changes: 0 additions & 4 deletions .zed/settings.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
// Folder-specific settings
//
// For a full list of overridable settings, and general information on folder-specific settings,
// see the documentation: https://zed.dev/docs/configuring-zed#settings-files
{
"lsp": {
"deno": {
Expand Down
151 changes: 127 additions & 24 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,8 @@ You can then use the `transformUrl` function to transform a URL:

```ts
const url = transformUrl(
"https://cdn.shopify.com/static/sample-images/bath_grande_crop_center.jpeg",
{
url:
"https://cdn.shopify.com/static/sample-images/bath_grande_crop_center.jpeg",
width: 800,
height: 600,
},
Expand All @@ -77,19 +76,16 @@ console.log(parsedUrl);
// width: 800,
// height: 600,
// base: "https://cdn.shopify.com/static/sample-images/bath.jpeg",
// params: {
// crop: "center",
// },
// crop: "center",
// }
```

You can bypass auto-detection by specifying the CDN:

```ts
const url = transformUrl(
"https://cdn.shopify.com/static/sample-images/bath_grande_crop_center.jpeg",
{
url:
"https://cdn.shopify.com/static/sample-images/bath_grande_crop_center.jpeg",
width: 800,
height: 600,
cdn: "shopify",
Expand All @@ -100,7 +96,124 @@ const url = transformUrl(
This is particularly useful if you are using the CDN with a custom domain which
is not auto-detected.

## Supported CDN APIs
You can also specify a fallback CDN to use if the URL is not recognised as
coming from a known CDN:

```ts
const url = transformUrl(
"https://cdn.shopify.com/static/sample-images/bath_grande_crop_center.jpeg",
{
width: 800,
height: 600,
fallback: "netlify",
},
);
```

This is useful if you are using a CDN provider that supports external images,
but you still want to use the original CDN if possible.

## Custom operations

Different CDNs support different operations. By default, the transform function
accepts the operations `width`, `height`, `quality` and `format`. You can pass
provider-specific operations as the third argument to the `transformUrl`
function:

```ts
const url = transformUrl(
"https://cdn.shopify.com/static/sample-images/bath.jpeg",
{
width: 800,
height: 600,
},
{
shopify: {
crop: "center",
},
},
);
```

You can pass options for multiple providers, which will be passed to the
provider depending on the detected CDN:

```ts
const url = transformUrl(
src,
{
width: 800,
height: 600,
},
{
shopify: {
crop: "left",
},
imgix: {
position: "left",
},
},
);
```

These options are type-safe, as we include the types for each provider.

You can do the same for provider options, such as base URLs project keys.

```ts
const url = transformUrl(
src,
{
width: 800,
height: 600,
fallback: "cloudinary",
},
{
shopify: {
crop: "left",
},
},
{
cloudinary: {
cloudName: "demo",
},
},
);
```

## Provider imports

If you know which providers you will be using, you can import them directly.
This will reduce the bundle size of your application, as only the providers you
use will be included. In this case you can pass provider-specific operations in
the object.

```ts
import { transform } from "unpic/providers/shopify";

const url = transform(
"https://cdn.shopify.com/static/sample-images/bath.jpeg",
{
width: 800,
height: 600,
crop: "center",
},
);
```

```ts
import { transformUrl } from "unpic/async";

const url = await transformUrl(
"https://cdn.shopify.com/static/sample-images/bath_grande_crop_center.jpeg",
{
width: 800,
height: 600,
},
);
```

## Supported Providers

- Adobe Dynamic Media (Scene7)
- Builder.io
Expand All @@ -118,19 +231,6 @@ is not auto-detected.
- Vercel / Next.js
- WordPress.com and Jetpack Site Accelerator

## Delegated URLs

Some transformers support URL delegation. This means that the source image URL
is also checked, and if it matches a CDN then the transform is applied directly
to the source image. For example: consider a `next/image` URL that points to an
image on Shopify. The URL is detected as a `nextjs` URL because it starts with
`/_next/image`. The `nextjs` transformer supports delegation, so the source
image URL is then checked. As it matches a Shopify domain, the transform is
applied directly to the Shopify URL. This means that the image is transformed on
the fly by Shopify, rather than by Next.js. However if the source image is not a
supported CDN, or is a local image then the `nextjs` transformer will return a
`/_next/image` URL.

## FAQs

- **What is an image CDN?** An image CDN is a service that provides a URL API
Expand All @@ -156,15 +256,18 @@ supported CDN, or is a local image then the `nextjs` transformer will return a
use your URLs then probably. Examples may be image providers such as Unsplash,
or CMSs. If it is just your own site then probably not. You can manually
specify the CDN in the arguments to `transformUrl` and `parseUrl`.
- **Can you support more params?** We deliberately just support the most common
params that are shared between all CDNs. If you need more params then you can
use the CDN-specific API directly.
- **Why do you set auto format?** If the CDN support is, and no format is
specified in `transformUrl`, the library will remove any format set in the
source image, changing it to auto-format. In most cases, this is what you
want. Almost all browsers now support modern formats such as WebP, and setting
auto-format will allow the CDN to serve the best format for the browser. If
you want to force a specific format, you can set it in `transformUrl`.
- **Why do you set fit=cover (or equivalent)** If the CDN supports it, and no
fit is specified in `transformUrl`, the library will set fit to cover. This is
because in most cases you want the image to fill the space, rather than be
contained within it. Every CDN has its own syntax for this, so it's best if we
set a default that applies to all images. If you want to force a specific fit,
you can set it in `transformUrl`.
- **Do you support SVG, animated GIF etc?** If the CDN supports it, then yes. We
don't attempt to check if a format is valid - we will just pass it through to
the CDN. If the CDN doesn't support it, then it will return an error or a
Expand Down
1 change: 0 additions & 1 deletion data/paths.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
"/cdn-cgi/image/": "cloudflare",
"/cdn-cgi/imagedelivery/": "cloudflare_images",
"/_next/image": "nextjs",
"/_next/static": "nextjs",
"/_vercel/image": "vercel",
"/is/image": "scene7",
"/_ipx/": "ipx",
Expand Down
1 change: 1 addition & 0 deletions data/subdomains.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"imgix.net": "imgix",
"wp.com": "wordpress",
"files.wordpress.com": "wordpress",
"b-cdn.net": "bunny",
"storyblok.com": "storyblok",
Expand Down
6 changes: 5 additions & 1 deletion demo/src/examples.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
],
"nextjs": [
"Next.js",
"https://netlify-plugin-nextjs-demo.netlify.app/_next/image/?url=https%3A%2F%2Fimages.unsplash.com%2Fphoto-1674255909399-9bcb2cab6489%3Fauto%3Dformat%26fit%3Dcrop%26w%3D200%26q%3D80%26h%3D100&w=384&q=75"
"https://image-component.nextjs.gallery/_next/image?url=%252F_next%252Fstatic%252Fmedia%252Fmountains.a2eb1d50.jpg"
],
"scene7": [
"Adobe Dynamic Media (Scene7)",
Expand Down Expand Up @@ -83,5 +83,9 @@
"supabase": [
"Supabase",
"https://enlyjtqaeutqbhqgkadn.supabase.co/storage/v1/object/public/sample-public-bucket/alexander-shatov-PHH_0uw9-Qw-unsplash.jpg"
],
"vercel": [
"Vercel",
"https://build-output-api-image-optimization.vercel.sh/_vercel/image?url=%2Fimages%2Frio.jpeg"
]
}
33 changes: 0 additions & 33 deletions deno.json

This file was deleted.

60 changes: 60 additions & 0 deletions deno.jsonc
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
{
"name": "@unpic/lib",
"version": "3.19.0",
"exports": {
".": "./mod.ts",
"./async": "./src/async.ts",
"./providers/astro": "./src/providers/astro.ts",
"./providers/builder.io": "./src/providers/builder.io.ts",
"./providers/bunny": "./src/providers/bunny.ts",
"./providers/cloudflare_images": "./src/providers/cloudflare_images.ts",
"./providers/cloudflare": "./src/providers/cloudflare.ts",
"./providers/cloudimage": "./src/providers/cloudimage.ts",
"./providers/cloudinary": "./src/providers/cloudinary.ts",
"./providers/contentful": "./src/providers/contentful.ts",
"./providers/contentstack": "./src/providers/contentstack.ts",
"./providers/directus": "./src/providers/directus.ts",
"./providers/imageengine": "./src/providers/imageengine.ts",
"./providers/imagekit": "./src/providers/keycdn.ts",
"./providers/imgix": "./src/providers/imgix.ts",
"./providers/keycdn": "./src/providers/keycdn.ts",
"./providers/kontent.ai": "./src/providers/kontent.ai.ts",
"./providers/netlify": "./src/providers/netlify.ts",
"./providers/nextjs": "./src/providers/nextjs.ts",
"./providers/scene7": "./src/providers/scene7.ts",
"./providers/shopify": "./src/providers/shopify.ts",
"./providers/storyblok": "./src/providers/storyblok.ts",
"./providers/supabase": "./src/providers/supabase.ts",
"./providers/uploadcare": "./src/providers/uploadcare.ts",
"./providers/vercel": "./src/providers/vercel.ts",
"./providers/wordpress": "./src/providers/wordpress.ts"
},
"tasks": {
"build:npm": "deno run --allow-all scripts/build_npm.ts"
},
"compilerOptions": {
"jsx": "react-jsx",
"jsxImportSource": "https://esm.sh/[email protected]"
},
"fmt": {
"useTabs": true
},
"imports": {
"@deno/dnt": "jsr:@deno/[email protected]",
"@std/path": "jsr:@std/[email protected]",
"@std/fs": "jsr:@std/[email protected]",
"@std/testing": "jsr:@std/[email protected]"
},
"publish": {
"include": [
"src",
"mod.ts",
"README.md",
"data"
],
"exclude": [
"**/*.test.ts"
]
},
"license": "MIT"
}
Loading