Skip to content
Merged
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
1 change: 1 addition & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ name: CI

on:
push:
branches: [main]
pull_request:
workflow_dispatch:

Expand Down
22 changes: 11 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ toolbar icon into that project's logo.
- Two rival frameworks on one page → 😈, and the popup lists everything.

Click the icon for the details: what was found, which version (as precisely as
the page allows), what it was built on, and the exact byte patterns that led to
that conclusion.
the page allows), what evidence was absorbed, and the exact byte patterns that
led to that conclusion.

![The extension on anthropic.com: the toolbar icon has become the jQuery mark,
and the popup reads "jQuery v3.5.1 - with Rspack", listing jQuery under UI
Expand Down Expand Up @@ -81,10 +81,10 @@ Visit a few sites and watch the icon:

| Site | Expected |
| --- | --- |
| <https://nextjs.org> | Next.js, built on React + Turbopack |
| <https://vuejs.org> | VitePress, built on Vue + Vite |
| <https://nextjs.org> | Next.js, absorbing React + Turbopack traces |
| <https://vuejs.org> | VitePress, absorbing Vue + Vite traces |
| <https://angular.dev> | Angular 22.1.3 |
| <https://svelte.dev> | SvelteKit, built on Svelte 5 + Vite |
| <https://svelte.dev> | SvelteKit, absorbing Svelte 5 + Vite traces |
| <https://jquery.com> | jQuery 4.0.0 |
| <https://stackoverflow.com> | Svelte 5, with jQuery, Stimulus and webpack |

Expand Down Expand Up @@ -185,12 +185,12 @@ first entry of an array (Lit's `litElementVersions`) and `.v` as a `Set`
which is what stops SvelteKit's build id, a 13-digit timestamp sitting in a
property called `version`, being reported as a release.

### Built on
### Absorbed evidence

Next.js *is* React and ships webpack or Turbopack. Reporting all three as
separate findings would be technically true and useless, so a meta-framework
absorbs what is intrinsic to it and the popup shows those as chips under the
card, evidence and all.
absorbs what is intrinsic to it and the popup shows those traces as chips under
the card, evidence and all.

Only intrinsic relationships are folded in. React on webpack is a *choice*, not
a fact about React, so those stay two findings — and Astro keeps its islands
Expand All @@ -209,9 +209,9 @@ React is a normal Tuesday, not a contradiction.
hardly ever the most interesting thing about a page, so anything else found
beside it wins. Everything else sorts on the weight of its evidence, which is
what puts Alpine ahead of the Preact-based search widget on alpinejs.dev.
- **Rspack ≤ 1.x is webpack, byte for byte.** Rspack ships a deliberately
- **Rspack ≤ 1.x leaves webpack-shaped traces.** Rspack ships a deliberately
webpack-compatible runtime: 0.7 and 1.x emit `webpackChunk*` and
`data-webpack` exactly like webpack 5. The `ruid` stamp rescues 1.0+, but an
`data-webpack` markers like webpack 5. The `ruid` stamp rescues 1.0+, but an
Rspack 0.x site is reported as webpack 5 and there is no signal to do better.
Rspack 2's ESM chunks are the opposite case: no chunk global and no
`data-rspack`, just the exported `__rspack_esm_id`/`__rspack_esm_ids` names —
Expand Down Expand Up @@ -300,7 +300,7 @@ checks they are loadable. That is the whole of it.
worse than no patterns.
2. Add an entry to the right file in `src/signatures/`, with `seen:` noting what
you checked it against. Set `category`, and add a relation at the bottom of
the file if it is built on something else.
the file if another finding should be absorbed into it.
3. Put the project's own logo in as `icons/src/<id>.svg` (or `.png` if that is
all they publish) and run `npm run icons`, which writes `icons/<id>.png` at
128 px. That one file is what the repo keeps; `npm run build` derives the
Expand Down
8 changes: 4 additions & 4 deletions src/engine.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
return root.StackSignatures || [];
}

/** Relations pushed by the signature files: `id` is built on `builtOn`. */
/** Relations pushed by the signature files: `id` absorbs `builtOn`. */
function relations() {
return root.StackRelations || [];
}
Expand Down Expand Up @@ -232,12 +232,12 @@
}

/**
* Fold a technology's evidence into the thing that is built on top of it.
* Fold one technology's evidence into a more specific finding.
*
* Next.js *is* React and ships webpack or Turbopack; reporting all three as
* separate findings would be technically true and useless. Only intrinsic
* relationships belong here -- React on webpack is a choice, not a fact
* about React, so those stay two findings.
* relationships and deliberate compatibility traces belong here -- React on
* webpack is a choice, not a fact about React, so those stay two findings.
*/
function applyRelations(detections, notes) {
const byId = new Map(detections.map((d) => [d.id, d]));
Expand Down
2 changes: 1 addition & 1 deletion src/popup.css
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ main {
flex: none;
}

/* ---------- "built on" strip ---------- */
/* ---------- absorbed evidence strip ---------- */

.built-on {
display: flex;
Expand Down
4 changes: 2 additions & 2 deletions src/popup.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,10 @@
);
}

/** The technologies a detection was folded out of, as a compact strip. */
/** The technologies whose evidence was folded into this detection. */
function renderBuiltOn(d) {
const strip = el('div', { className: 'built-on' }, [
el('span', { className: 'built-on-label', textContent: 'built on' }),
el('span', { className: 'built-on-label', textContent: 'absorbed' }),
]);
for (const b of d.builtOn) {
strip.append(
Expand Down
2 changes: 1 addition & 1 deletion src/signatures/bundlers.js
Original file line number Diff line number Diff line change
Expand Up @@ -422,7 +422,7 @@
{
id: 'rspack',
builtOn: ['webpack'],
note: "Rspack ships a webpack-compatible runtime, so this page's webpack markers are attributed to Rspack.",
note: "Rspack ships webpack-compatible runtime markers, so this page's webpack traces are attributed to Rspack.",
},
{
id: 'vite',
Expand Down
4 changes: 2 additions & 2 deletions src/signatures/meta.js
Original file line number Diff line number Diff line change
Expand Up @@ -531,12 +531,12 @@
{
id: 'vitepress',
builtOn: ['vue', 'vite', 'rollup', 'esbuild'],
note: 'VitePress is a Vue site generator built on Vite, so those markers are attributed to VitePress.',
note: 'VitePress is a Vue site generator that uses Vite, so those markers are attributed to VitePress.',
},
{
id: 'rspress',
builtOn: ['react', 'rspack', 'webpack'],
note: 'Rspress is a React site generator built on Rsbuild/Rspack, so those markers are attributed to Rspress.',
note: 'Rspress is a React site generator that uses Rsbuild/Rspack, so those markers are attributed to Rspress.',
},
{
id: 'astro',
Expand Down
4 changes: 2 additions & 2 deletions test/run.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,8 @@ const CASES = [
// A Next.js webpack build: the Next markers in the chunk registry win over
// the plain webpack reading, and webpack arrives folded in.
{ dir: 'next-webpack', primary: 'next', version: null, builtOn: ['webpack'], only: true },
// Rspack 1.x stamps its exact version into the runtime, which is the only
// thing separating it from webpack 5 -- its runtime is webpack's otherwise.
// Rspack 1.x stamps its exact version into a webpack-compatible runtime,
// which is what separates these markers from plain webpack 5.
{ dir: 'rspack1', primary: 'rspack', version: '1.5.8', builtOn: ['webpack'], only: true },
{ dir: 'rspack2', primary: 'rspack', version: '≥ 2', only: true },
{ dir: 'turbopack', primary: 'turbopack', version: null, only: true },
Expand Down
Loading