From 88db5c7a6f8c8922892f84d0e83d638c68cf7a84 Mon Sep 17 00:00:00 2001 From: swwind Date: Sat, 29 Aug 2026 17:14:54 +0800 Subject: [PATCH 1/3] add release ci --- .github/workflows/ci.yml | 7 ----- .github/workflows/release.yml | 56 +++++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+), 7 deletions(-) create mode 100644 .github/workflows/release.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1555507..ba2710a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,23 +14,16 @@ jobs: - uses: actions/setup-node@v4 with: - node-version: '22' cache: npm - # The build downscales the toolbar icons with sharp, so the dev - # dependencies have to be there before anything below runs. - name: Install dependencies run: npm ci - # Matches the signature rules against the real bundle output committed - # under test/fixtures. - name: Signature tests run: npm test - name: Build both browser targets run: npm run build - # Catches a manifest that points at a file the build did not copy, or the - # two manifests drifting apart. - name: Validate build output run: npm run validate diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..73f748b --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,56 @@ +name: Release Extension + +on: + workflow_dispatch: + +jobs: + publish_firefox: + environment: firefox-release + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-node@v4 + with: + cache: npm + + - name: Install dependencies + run: npm ci + + - name: Build + run: npm run build + + - name: Publish to Firefox Add-ons + run: | + npx web-ext@latest sign \ + --source-dir ./dist/firefox \ + --channel listed \ + --api-key "${{ secrets.AMO_JWT_ISSUER }}" \ + --api-secret "${{ secrets.AMO_JWT_SECRET }}" + + publish_chrome: + environment: chrome-release + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-node@v4 + with: + cache: npm + + - name: Install dependencies + run: npm ci + + - name: Build + run: npm run build + + - name: Publish to Chrome Web Store + uses: mnao305/chrome-extension-upload@v6.0.0 + with: + file-path: dist/chrome.zip + extension-id: jagakebomapmaajkbbldhbilhgedlkmp + client-id: ${{ secrets.CLIENT_ID }} + client-secret: ${{ secrets.CLIENT_SECRET }} + refresh-token: ${{ secrets.REFRESH_TOKEN }} From 78764b41d9f209ec359deebe277e4ac3df7bb834 Mon Sep 17 00:00:00 2001 From: swwind Date: Sat, 29 Aug 2026 17:19:44 +0800 Subject: [PATCH 2/3] docs: modify README --- README.md | 343 ++++-------------------------------------------------- 1 file changed, 24 insertions(+), 319 deletions(-) diff --git a/README.md b/README.md index 1e582fa..0b6edc0 100644 --- a/README.md +++ b/README.md @@ -1,29 +1,19 @@ # Web Stack Detector -A Firefox and Chrome extension that works out what the page you are looking at -was built with — the framework, the UI library and the bundler — and turns the -toolbar icon into that project's logo. +A Firefox and Chrome extension that identifies the web stack used by the page +you are viewing and changes the toolbar icon to match it. -- A Next.js site → the Next.js mark. -- A Vue SPA on Vite → the Vue mark, with Vite in the popup. -- Built with Rspack and nothing else recognisable → the Rspack crab. -- Two rival frameworks on one page → 😈, and the popup lists everything. +![The extension popup](example.png) -Click the icon for the details: what was found, which version (as precisely as -the page allows), what evidence was absorbed, and the exact byte patterns that -led to that conclusion. +## Install -![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 -LIBRARY and Rspack v1.3.9 under BUNDLER with a webpack 5 chip folded into it, -both with high confidence and evidence to unfold](example.png) - -Not on any store — clone it and load it yourself. +- [Install from the Chrome Web Store](https://chromewebstore.google.com/detail/web-stack-detector/jagakebomapmaajkbbldhbilhgedlkmp) +- [Install from Firefox Add-ons](https://addons.mozilla.org/en-US/firefox/addon/web-stack-detector/) ## Build -Needs Node 20+. The build copies files, picks the right manifest and downscales -the toolbar icons, which is the one thing that needs a dependency (sharp). +Requires Node.js 20 or later. The build copies the extension files, selects the +appropriate manifest, and resizes toolbar icons. ```sh git clone https://github.com/swwind/web-stack-detector.git @@ -32,288 +22,18 @@ npm install npm run build ``` -That writes two loadable folders: - -``` -dist/chrome manifest with a service-worker background -dist/firefox manifest with an event-page background + a gecko id -``` - -They share every line of code and differ only in the manifest. - -## Install in Chrome - -1. Open `chrome://extensions` -2. Turn on **Developer mode** (top right) -3. Click **Load unpacked** and pick the `dist/chrome` folder - -The icon appears straight away and survives restarts. Chrome shows a -*"Disable developer mode extensions"* warning on startup — that is the normal -nag for any unpacked extension. - -Click the puzzle-piece icon and pin *Web Stack Detector* so the logo stays visible -in the toolbar, which is rather the point of it. - -After changing the source, run `npm run build` again and press **reload** ↻ on -the extension's card. - -## Install in Firefox - -1. Open `about:debugging#/runtime/this-firefox` -2. Click **Load Temporary Add-on…** -3. Pick `dist/firefox/manifest.json` (the file, not the folder) - -Then **grant site access**, or it will detect much less: Firefox MV3 makes host -permissions opt-in, so until you allow it the extension can read the page but -never the script files themselves. - -- Click the puzzle-piece icon → the gear next to *Web Stack Detector* → **Always - Allow on All Sites** -- Or `about:addons` → Web Stack Detector → **Permissions** → *Access your data for - all websites* - -**Temporary add-ons disappear when Firefox restarts.** Loading it again is the -same three steps. A permanent install would need the add-on signed by Mozilla. - -## Check it works - -Visit a few sites and watch the icon: - -| Site | Expected | -| --- | --- | -| | Next.js, absorbing React + Turbopack traces | -| | VitePress, absorbing Vue + Vite traces | -| | Angular 22.1.3 | -| | SvelteKit, absorbing Svelte 5 + Vite traces | -| | jQuery 4.0.0 | -| | Svelte 5, with jQuery, Stimulus and webpack | - -Those are the verdicts it actually produced when run against the live sites. - -## What it detects - -Three categories, in the order they claim the icon: a **framework** says more -about a page than the **UI library** underneath it, which says more than the -**bundler** underneath that. - -### Frameworks - -| | Recognised by | Version | -| --- | --- | --- | -| **Next.js** | `window.next`, `__NEXT_DATA__`, `self.__next_f`, `/_next/static/`, the `webpackChunk_N_E` registry | **exact**, off `window.next.version` | -| **Fresh** | Fresh 1's `/_frsh/` runtime assets and `__FRSH_STATE`; Fresh 2's `f-client-nav` / `f-partial` attributes | `≤ 1` or `≥ 2`, from the runtime marker | -| **Nuxt** | `useNuxtApp`, `__NUXT__`, `__buildAssetsURL`, `/_nuxt/` | none | -| **SvelteKit** | `__sveltekit_…`, `/_app/immutable/`, `data-sveltekit-preload-data` | none | -| **Astro** | `` and its runtime, `astro:page-load`, `/_astro/`, `data-astro-cid-…` | **exact** from the generator meta tag | -| **Gatsby** | `___loader`, `___chunkMapping`, `id="___gatsby"`, `/page-data/` | **exact** from the generator meta tag | -| **Docusaurus** | `window.docusaurus`, `id="__docusaurus"` | **exact** from the generator meta tag | -| **VitePress** | `__VITEPRESS__`, `__VP_HASH_MAP__` | **exact** from the generator meta tag | -| **Rspress** | `id="__rspress_root"` (2.x), the `rspress-doc`/`rspress-nav` theme classes, the `rspress-theme-appearance` script | **exact** from the generator meta tag | -| **Remix** | `__remixContext`; Remix 3's `rmx-…`/`data-remix-…` attributes, `rmxc-…` classes and `@remix-run/ui` requests | **exact** for Remix 3, off the asset path | - -### UI libraries - -| | Recognised by | Version | -| --- | --- | --- | -| **React** | `__reactFiber$…` / `__reactProps$…` on DOM nodes, `_reactListening…`, the minified error-decoder URL | major only, from the decoder URL moving to `react.dev` in 19 | -| **Preact** | the mangled `__k`/`__c`/`__e`/`__b` vnode internals, `__k` on DOM nodes, `window.preact` | none | -| **Vue** | `__vue_app__` and `_vnode` on DOM nodes, `__VUE__`, `__v_isVNode`, `__vccOpts`, `data-v-…` | 2 vs 3; exact from a dev-build banner | -| **Angular** | `ng-version` on the root element, `__ngContext__`, `_nghost-`/`_ngcontent-`, `ɵcmp` | **exact**, off `ng-version` | -| **AngularJS** | `window.angular`, `ng-app`/`ng-controller`, the `ng-scope` class | **exact**, off `angular.version.full` | -| **Svelte** | `window.__svelte`, `svelte.dev/e/…` error URLs, `svelte-…` scoped classes | **major**, off `__svelte.v` | -| **Solid** | `_$DX_DELEGATE`, `$$click`-style handlers on DOM nodes | none | -| **Qwik** | `q:container` / `q:version` attributes, `_qc_`, `window.qwikevents` | **exact**, off `q:version` | -| **Lit** | `litElementVersions` on window, `$lit$` template markers | **exact**, off `litElementVersions` | -| **Alpine.js** | `window.Alpine`, `_x_…` on DOM nodes, `x-data`/`x-show` | **exact**, off `Alpine.version` | -| **htmx** | `window.htmx`, `hx-get`/`hx-boost` attributes | **exact**, off `htmx.version` | -| **jQuery** | `window.jQuery`, the `jQuery` data expando, the banner comment | **exact** | -| **Stimulus** | `window.Stimulus`, `data-controller` | none | -| **Ember.js** | `EmberENV`, `__ember_auto_import__`, the `ember-view` class | none | -| **Backbone.js** | `window.Backbone` | **exact**, off `Backbone.VERSION` | -| **Knockout** | `window.ko`, `__ko__` on DOM nodes | **exact**, off `ko.version` | - -### Bundlers - -| | Recognised by | Version | -| --- | --- | --- | -| **Vite** | `vite:preloadError`, `Unable to preload CSS for`, `__vite__mapDeps`, the `