aboutsummaryrefslogtreecommitdiff
path: root/readme.md
blob: 2397467082e124996a7a2612214ad85c15e5e1de (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
# CF Image proxy

> Proxy CDN for caching static assets from third-party domains via [Cloudflare Workers](https://workers.cloudflare.com).

[![Build Status](https://github.com/transitive-bullshit/cf-image-proxy/actions/workflows/build.yml/badge.svg)](https://github.com/transitive-bullshit/cf-image-proxy/actions/workflows/build.yml) [![Prettier Code Formatting](https://img.shields.io/badge/code_style-prettier-brightgreen.svg)](https://prettier.io)

## Features

- Free 💪
- Super simple to setup and self-host
- Perfect lighthouse scores
- Handles CORS for you
- Normalizes origin URLs
- Respects `pragma: no-cache` and related headers
- Used in hundreds of prod sites

## Config

**All config is defined in [wrangler.toml](./wrangler.toml).**

0. Create a new blank [Cloudflare Worker](https://workers.cloudflare.com).
1. Fork / clone this repo
2. Update the missing values in [wrangler.toml](./wrangler.toml)
3. `npm install`
4. `npm run dev` to test locally
5. `npm run deploy` to deploy to cloudflare workers 💪

### wrangler.toml

```yaml
name = "cf-image-proxy"
type = "javascript"
webpack_config = "webpack.config.js"
account_id = "TODO"
workers_dev = true

[env.production]
zone_id = "TODO"
route = "TODO"
```

You can find your `account_id` and `zone_id` in your Cloudflare Workers settings.

Your `route` should look like `"exampledomain.com/*"`.

### Cloudflare Polish

You can optionally enable Polish in your Cloudflare zone settings if you want to enable on-the-fly image optimization as part of your CDN. In many cases, this will serve images to supported clients in an optimized `webp` format.

This may increase costs, so it's not recommended for everyone. The CF worker should support both configurations without issue.

### CDN

By default, all assets will be served with a `cache-control` header set to `public, immutable, s-maxage=31536000, max-age=31536000, stale-while-revalidate=60`, which effectively makes them cached at all levels indefinitely (or more practically until Cloudflare or your browser purges the asset from its cache).

If you want to change this `cache-control` header or add additional headers, see [src/fetch-request.js](./src/fetch-request.js).

## Usage

### Next.js Notion Starter Kit

If you're using this image proxy as part of [nextjs-notion-starter-kit](https://github.com/transitive-bullshit/nextjs-notion-starter-kit), all you need to do is set `imageCDNHost` in your `site.config.js` and your image proxy will be used automatically.

If you're not using this Next.js Notion boilerplate, then read on.

### General Usage

In the application where you want to consume your proxied images, you'll need to replace your third-party image URLs.

You can replace them with your proxy domain plus a path that contains the URI-encoded version of your original domain. In TypeScript, this looks like the following:

```ts
const imageCDNHost = 'https://exampledomain.com'

export const mapImageUrl = (imageUrl: string) => {
  if (imageUrl.startsWith('data:')) {
    return imageUrl
  }

  if (imageCDNHost) {
    // Our proxy uses Cloudflare's global CDN to cache these image assets
    return `${imageCDNHost}/${encodeURIComponent(imageUrl)}`
  } else {
    return imageUrl
  }
}
```

## Technical Notes

A few notes about the implementation:

- It is hosted via Cloudflare (CF) edge [workers](https://workers.cloudflare.com).
- It is transpiled by webpack before uploading to CF.
- CF runs our worker via V8 directly in an environment mimicking [web workers](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API).
- This means that our worker does not have access to Node.js primitives such as `fs`, `dns` and `http`.
- It does have access to a custom [web fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API).

## License

MIT © [Travis Fischer](https://transitivebullsh.it)

Support my OSS work by <a href="https://twitter.com/transitive_bs">following me on twitter <img src="https://storage.googleapis.com/saasify-assets/twitter-logo.svg" alt="twitter" height="24px" align="center"></a>