Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
121 changes: 120 additions & 1 deletion cdn/README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,122 @@
```shell
# Benchie CDN Helper

Benchie is a small helper script that dynamically selects the fastest CDN at runtime, based on response time. It fetches and caches resources like images, css or js, and injects them into the DOM using blob URLs. This improves performance and flexibility without requiring HTML changes for different CDNs.

---

## Setup

To enable Benchie, include the following script in your `<head>`:

```html
<script>
// Define a list of CDN base URLs to test
// The script will use the fastest one
const $__CDN_LIST = [
window.location.origin, // fallback to current origin
// Add additional CDN origins below
// e.g. 'https://cdn.example.com', 'https://static.mycdn.net'
];

// Paste the contents of benchie.min.js here
</script>
```

---

## Usage

To declare resources that should be rewritten to blob URLs and loaded via the best available CDN, use the following HTML attributes:

### 1. **Declarative `<meta>` tag**

You can inject a `<link>` element by declaring a special `<meta>` tag with the `name="pathscale-cdn"` and a JSON string as its `content`:

```html
<meta name="pathscale-cdn" content='{"tag":"link","rel":"stylesheet","href":"/app.css?v=1.0.0"}'>
```

This will be replaced at runtime with:

```html
<link rel="stylesheet" href="blob:<resolved-url>">
```

**Important:**

* The `content` value must be a **valid JSON string**.
* Currently only `tag: link` is supported.

### 2. **Using `data-src` and `data-href`**

For existing tags, you can use:

```html
<img data-src="/image.png">
<script data-src="/script.js"></script>
```

These will be automatically rewritten into:

```html
<img src="blob:<url>">
<script src="blob:<url>"></script>
```


> ### 👉 Why meta?<br>
> Using `<meta name="pathscale-cdn" content='...'>` instead of `<link data-href="...">` ensures HTML5 validity.<br>
> Since the `href` attribute is required on `<link>` elements.
>
> However, you can use `<link data-href="...">` if HTML5 validation is not a concern in your case.

---

## Global Helpers

When Benchie loads, it exposes the following global values:

### `window.t`

A globally available async function for resolving blob URLs manually:

```js
const blobUrl = await window.t('/some-resource.js', window.$__CDN);
```

### `window.$__CDN`

The base CDN URL that was selected at runtime (e.g. `https://cdn.example.com`).
This is determined by racing all URLs from the `$__CDN_LIST`.

---

## Build Instructions

To build the minified version of Benchie:

1. Navigate to the `cdn` directory:

```bash
cd cdn
```

2. Run the build script (requires [Bun](https://bun.sh)):

```bash
bun run build-benchie.ts
```

This will generate `cdn/benchie.min.js` from the source file `cdn/benchie.js`, using Bun’s built-in minifier.

---

## License

This code is proprietary and confidential:

```
PathScale CONFIDENTIAL
© 2025 PathScale PTE Ltd. All rights reserved.
Do not distribute without prior written permission.
```
15 changes: 9 additions & 6 deletions cdn/benchie.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ async function resolveElementResource(el, cdnBase) {

/**
* Helper to convert <meta name="pathscale-cdn"> into a real <link>
* Expects JSON in the `content` attribute
*/
async function resolveMetaCdnElement(metaEl, cdnBase) {
// Ensure the element is the expected <meta name="pathscale-cdn">
Expand All @@ -84,11 +85,13 @@ async function resolveMetaCdnElement(metaEl, cdnBase) {
const content = metaEl.getAttribute('content');
if (!content) return;

const params = {};
content.split(',').forEach((part) => {
const [key, value] = part.split('=').map((s) => s.trim());
if (key && value) params[key] = value;
});
let params;
try {
params = JSON.parse(content);
} catch {
console.warn('Invalid JSON in pathscale-cdn meta tag:', content);
return;
}

if (params.tag !== 'link') return;

Expand Down Expand Up @@ -134,7 +137,7 @@ window.addEventListener("DOMContentLoaded", async function () {
const dataSrcElements = Array.from(document.querySelectorAll("[data-src]"));
const dataHrefElements = Array.from(document.querySelectorAll("[data-href]"));

const metaRewrites = cdnMetaElements.map(el => resolveMetaCdnElement(el));
const metaRewrites = cdnMetaElements.map(el => resolveMetaCdnElement(el, $__CDN));

const srcRewrites = dataSrcElements.map(el =>
fetchAndCache(el.dataset.src, $__CDN).then(blobUrl => el.setAttribute("src", blobUrl))
Expand Down
10 changes: 7 additions & 3 deletions rollup.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,12 @@ const template = ({ attributes, files, meta, publicPath, title }) => {
const file = addVersion(fileName);
const href = `${publicPath}${file}`;
// It will be replaces by <link rel="stylesheet" href="..."> by Benchie in browser runtime
return `<meta name="pathscale-cdn" content="tag=link, rel=stylesheet, href=${href}">`;
const contentJson = JSON.stringify({
tag: "link",
rel: "stylesheet",
href: href,
});
return `<meta name="pathscale-cdn" content='${contentJson}'>`;
})
.join("\n");

Expand All @@ -81,8 +86,7 @@ const template = ({ attributes, files, meta, publicPath, title }) => {
const url = "https://vue3.dev";
const imageUrl = `${url}/vue3-ui.png`;

return `
<!doctype html>
return `<!doctype html>
<html${makeHtmlAttributes(attributes.html)}>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
Expand Down