diff --git a/cdn/README.md b/cdn/README.md index 4bdfa84..6c7eac7 100644 --- a/cdn/README.md +++ b/cdn/README.md @@ -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 ``: + +```html + +``` + +--- + +## 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 `` tag** + +You can inject a `` element by declaring a special `` tag with the `name="pathscale-cdn"` and a JSON string as its `content`: + +```html + +``` + +This will be replaced at runtime with: + +```html + +``` + +**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 + + +``` + +These will be automatically rewritten into: + +```html + + +``` + + +> ### 👉 Why meta?
+> Using `` instead of `` ensures HTML5 validity.
+> Since the `href` attribute is required on `` elements. +> +> However, you can use `` 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. +``` diff --git a/cdn/benchie.js b/cdn/benchie.js index 89af314..bf25297 100644 --- a/cdn/benchie.js +++ b/cdn/benchie.js @@ -70,6 +70,7 @@ async function resolveElementResource(el, cdnBase) { /** * Helper to convert into a real + * Expects JSON in the `content` attribute */ async function resolveMetaCdnElement(metaEl, cdnBase) { // Ensure the element is the expected @@ -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; @@ -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)) diff --git a/rollup.config.js b/rollup.config.js index 5957f64..3f5a39b 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -63,7 +63,12 @@ const template = ({ attributes, files, meta, publicPath, title }) => { const file = addVersion(fileName); const href = `${publicPath}${file}`; // It will be replaces by by Benchie in browser runtime - return ``; + const contentJson = JSON.stringify({ + tag: "link", + rel: "stylesheet", + href: href, + }); + return ``; }) .join("\n"); @@ -81,8 +86,7 @@ const template = ({ attributes, files, meta, publicPath, title }) => { const url = "https://vue3.dev"; const imageUrl = `${url}/vue3-ui.png`; - return ` - + return `