diff --git a/.eslintignore b/.eslintignore
index 6392112d7..a305811c2 100644
--- a/.eslintignore
+++ b/.eslintignore
@@ -2,7 +2,12 @@ dist
js
**/*.d.js
coverage
+example/
example/react/src/message-data.jsx
example-test/react/src/message-data.jsx
example-test/
+spec/
+test-js/
+js-dist/
+packages/**/dist/
packages/common/mode.js
diff --git a/.eslintrc.json b/.eslintrc.json
index 33964cda4..07b781096 100644
--- a/.eslintrc.json
+++ b/.eslintrc.json
@@ -1,11 +1,17 @@
{
"extends": ["auto"],
- "ignorePatterns": ["js/*", "dist/*", "*.d.ts"],
+ "ignorePatterns": [
+ "js/*",
+ "dist/*",
+ "*.d.ts",
+ "coverage/**",
+ "vite-build.js",
+ "vite.config.js"
+ ],
"env": {
"amd": true,
"browser": true,
"jasmine": true,
- "jest": true,
"jquery": true,
"commonjs": true,
"es2020": true
@@ -13,9 +19,9 @@
"globals": {
"location": true,
"iframeResize": true,
- "parentIFrame": true
+ "parentIframe": true
},
- "parserOptions": { "ecmaVersion": 2021 },
+ "parserOptions": { "ecmaVersion": 2022, "sourceType": "module" },
"rules": {
"comma-dangle": [1, "always-multiline"],
"const-case/uppercase": 0,
@@ -42,6 +48,13 @@
"no-return-assign": [2, "except-parens"],
"no-use-before-define": 0,
"no-shadow": 0,
+ "@typescript-eslint/explicit-function-return-type": 0,
+ "@typescript-eslint/no-shadow": 0,
+ "@typescript-eslint/no-throw-literal": 0,
+ "@typescript-eslint/no-use-before-define": 0,
+ "react/destructuring-assignment": 0,
+ "react/react-in-jsx-scope": 0,
+ "react/require-default-props": 0,
"prefer-rest-params": 0,
"import/no-amd": 0,
"import/no-extraneous-dependencies": 0,
@@ -61,6 +74,7 @@
"unicorn/no-this-assignment": 0,
"unicorn/prefer-module": 0,
"unicorn/prefer-query-selector": 0,
+ "unicorn/prefer-export-from": 0,
"unicorn/prevent-abbreviations": 0,
"xss/no-mixed-html": 0
},
@@ -78,6 +92,56 @@
"xss/no-location-href-assign": 0
}
},
+ {
+ "files": ["build/**/*.js", "build-scripts/**/*.js", "vite.config/**/*.js"],
+ "parser": "@babel/eslint-parser",
+ "parserOptions": {
+ "requireConfigFile": false,
+ "sourceType": "module",
+ "ecmaVersion": 2024,
+ "babelOptions": {
+ "plugins": ["@babel/plugin-syntax-import-attributes"]
+ }
+ },
+ "rules": {
+ "import/extensions": 0,
+ "no-console": 0,
+ "no-await-in-loop": 0,
+ "no-underscore-dangle": 0,
+ "no-unsanitized/method": 0,
+ "unicorn/prefer-top-level-await": 0,
+ "security/detect-non-literal-fs-filename": 0
+ }
+ },
+ {
+ "files": ["packages/**/*.test.js", "packages/**/*.test.jsx", "packages/**/*.test.ts", "packages/**/*.test.tsx"],
+ "parserOptions": { "ecmaVersion": 2022, "sourceType": "module" },
+ "globals": {
+ "test": true,
+ "describe": true,
+ "it": true,
+ "expect": true,
+ "beforeEach": true,
+ "afterEach": true,
+ "vi": true
+ },
+ "rules": {
+ "jasmine/expect-single-argument": 0,
+ "jasmine/new-line-before-expect": 0,
+ "jasmine/no-spec-dupes": 0,
+ "jasmine/prefer-toHaveBeenCalledWith": 0,
+ "no-underscore-dangle": 0,
+ "unicorn/no-await-expression-member": 0,
+ "import/extensions": 0
+ }
+ },
+ {
+ "files": ["e2e/**/*.js"],
+ "rules": {
+ "import/extensions": 0,
+ "import/prefer-default-export": 0
+ }
+ },
{
"files": ["spec/**"],
"globals": {
@@ -108,14 +172,30 @@
"prefer-template": 0,
"yoda": 0,
"jasmine/no-disabled-tests": 0,
- "jest/expect-expect": 0,
- "jest/no-done-callback": 0,
- "jest/no-jasmine-globals": 0,
- "jest/no-test-prefixes": 0,
- "jest/prefer-to-be": 0,
"no-secrets/no-secrets": 0,
"sonarjs/no-duplicate-string": 0
}
+ },
+ {
+ "files": ["packages/react/**/*.tsx", "packages/react/**/*.jsx"],
+ "plugins": ["react"],
+ "rules": {
+ "react/react-in-jsx-scope": 0,
+ "react/require-default-props": 0
+ }
+ },
+ {
+ "files": ["packages/solid/**/*.ts", "packages/solid/**/*.tsx", "packages/solid/**/*.jsx"],
+ "plugins": ["solid"],
+ "extends": ["plugin:solid/typescript"],
+ "parserOptions": {
+ "project": "./packages/solid/tsconfig.json"
+ },
+ "rules": {
+ "react/react-in-jsx-scope": 0,
+ "react/require-default-props": 0,
+ "react/prop-types": 0
+ }
}
]
}
diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml
index e0570d70b..5d35256e5 100644
--- a/.github/FUNDING.yml
+++ b/.github/FUNDING.yml
@@ -12,8 +12,5 @@
# custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
github: davidjbradshaw
-custom: ['https://www.buymeacoffee.com/davidjbradshaw']
-# issuehunt: davidjbradshaw
-# liberapay: davidjbradshaw
-# ko_fi: davidjbradshaw
+custom: ['https://iframe-resizer.com/pricing/']
tidelift: npm/iframe-resizer
diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md
new file mode 100644
index 000000000..fd16b874f
--- /dev/null
+++ b/.github/copilot-instructions.md
@@ -0,0 +1,14 @@
+# GitHub Copilot Instructions
+
+## Before every commit/check-in
+
+**Always run `npm run eslint:fix` before committing any changes.**
+
+This is mandatory — failure to run `eslint:fix` will cause CI to fail with ESLint formatting and style errors.
+
+```bash
+npm run eslint:fix # Lint and auto-fix all issues
+npm run eslint # Lint only (to verify)
+```
+
+See `CLAUDE.md` for full project guidance.
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
index 8abca405f..ac1bb12cc 100644
--- a/.github/dependabot.yml
+++ b/.github/dependabot.yml
@@ -8,4 +8,18 @@ updates:
- package-ecosystem: "npm" # See documentation for possible values
directory: "/" # Location of package manifests
schedule:
- interval: "daily"
+ interval: "weekly"
+ open-pull-requests-limit: 10
+ groups:
+ eslint:
+ patterns: ["eslint", "eslint-*", "@typescript-eslint/*"]
+ babel:
+ patterns: ["@babel/*"]
+ rollup:
+ patterns: ["rollup", "rollup-*", "@rollup/*"]
+ vite:
+ patterns: ["vite", "vite-*", "@vitejs/*", "vitest", "@vitest/*"]
+ karma:
+ patterns: ["karma", "karma-*"]
+ playwright:
+ patterns: ["playwright", "@playwright/*"]
diff --git a/.github/workflows/claude-code-review.yml b/.github/workflows/claude-code-review.yml
index b5e8cfd4d..1a7b44d26 100644
--- a/.github/workflows/claude-code-review.yml
+++ b/.github/workflows/claude-code-review.yml
@@ -1,14 +1,7 @@
name: Claude Code Review
on:
- pull_request:
- types: [opened, synchronize, ready_for_review, reopened]
- # Optional: Only run on specific file changes
- # paths:
- # - "src/**/*.ts"
- # - "src/**/*.tsx"
- # - "src/**/*.js"
- # - "src/**/*.jsx"
+ workflow_dispatch: # Manual trigger only
jobs:
claude-review:
@@ -27,7 +20,7 @@ jobs:
steps:
- name: Checkout repository
- uses: actions/checkout@v4
+ uses: actions/checkout@v6
with:
fetch-depth: 1
diff --git a/.github/workflows/claude.yml b/.github/workflows/claude.yml
index d300267f1..4e03bc780 100644
--- a/.github/workflows/claude.yml
+++ b/.github/workflows/claude.yml
@@ -19,14 +19,14 @@ jobs:
(github.event_name == 'issues' && (contains(github.event.issue.body, '@claude') || contains(github.event.issue.title, '@claude')))
runs-on: ubuntu-latest
permissions:
- contents: read
- pull-requests: read
- issues: read
+ contents: write # Allow Claude to make commits if needed
+ pull-requests: write # Allow Claude to comment on PRs
+ issues: write # Allow Claude to comment on issues
id-token: write
- actions: read # Required for Claude to read CI results on PRs
+ actions: read # Required for Claude to read CI results on PRs
steps:
- name: Checkout repository
- uses: actions/checkout@v4
+ uses: actions/checkout@v6
with:
fetch-depth: 1
diff --git a/.github/workflows/codeql.yml.disable b/.github/workflows/codeql.yml.disable
deleted file mode 100644
index 6496c3fd2..000000000
--- a/.github/workflows/codeql.yml.disable
+++ /dev/null
@@ -1,45 +0,0 @@
-name: "CodeQL"
-
-on:
- push:
- branches: [ "master" ]
- pull_request:
- branches: [ "master" ]
- paths-ignore:
- - '**/*.md'
- - '**/*.txt'
- - 'js/**'
- schedule:
- - cron: "39 23 * * 5"
-
-jobs:
- analyze:
- name: Analyze
- runs-on: ubuntu-latest
- permissions:
- actions: read
- contents: read
- security-events: write
-
- strategy:
- fail-fast: false
- matrix:
- language: [ javascript ]
-
- steps:
- - name: Checkout
- uses: actions/checkout@v4
-
- - name: Initialize CodeQL
- uses: github/codeql-action/init@v2
- with:
- languages: ${{ matrix.language }}
- queries: +security-and-quality
-
- - name: Autobuild
- uses: github/codeql-action/autobuild@v2
-
- - name: Perform CodeQL Analysis
- uses: github/codeql-action/analyze@v2
- with:
- category: "/language:${{ matrix.language }}"
diff --git a/.github/workflows/eslint.yml b/.github/workflows/eslint.yml
index 346ea8bd2..6d93d68a6 100644
--- a/.github/workflows/eslint.yml
+++ b/.github/workflows/eslint.yml
@@ -11,23 +11,32 @@ name: ESLint
on:
push:
- branches: [ "master" ]
+ branches: [ "master", "dev" ]
pull_request:
# The branches below must be a subset of the branches above
- branches: [ "master" ]
+ branches: [ "master", "dev" ]
schedule:
- cron: '43 18 * * 4'
jobs:
eslint:
- name: Run eslint scanning
+ name: Scanning
runs-on: ubuntu-latest
permissions:
contents: read
security-events: write
steps:
- name: Checkout code
- uses: actions/checkout@v4
+ uses: actions/checkout@v6
+
+ - name: Setup Node.js
+ uses: actions/setup-node@v6
+ with:
+ node-version: '20.x'
+ cache: 'npm'
+
+ - name: Install dependencies
+ run: npm ci
- name: Install ESLint
run: npm install @microsoft/eslint-formatter-sarif@3
@@ -36,8 +45,14 @@ jobs:
run: npm run eslint:sarif
continue-on-error: true
+ - name: Ensure SARIF file exists
+ run: |
+ if [ ! -f eslint-results.sarif ]; then
+ echo '{"version":"2.1.0","runs":[]}' > eslint-results.sarif
+ fi
+
- name: Upload analysis results to GitHub
- uses: github/codeql-action/upload-sarif@v3
+ uses: github/codeql-action/upload-sarif@v4
with:
sarif_file: eslint-results.sarif
wait-for-processing: true
diff --git a/.github/workflows/jasmine.yml b/.github/workflows/jasmine.yml
new file mode 100644
index 000000000..9552f2eee
--- /dev/null
+++ b/.github/workflows/jasmine.yml
@@ -0,0 +1,52 @@
+# Integration Tests Workflow
+# Runs Jasmine/Karma integration tests for iframe-resizer
+
+name: Jasmine
+
+permissions:
+ contents: read
+
+on:
+ push:
+ branches: [ "master", "dev" ]
+ pull_request:
+ branches: [ "master", "dev" ]
+ workflow_dispatch: # Allow manual trigger
+
+jobs:
+ integration-tests:
+ name: Integration tests on Karma
+ runs-on: ubuntu-latest
+
+ strategy:
+ matrix:
+ node-version: [22.x]
+ # Single Node.js version is sufficient (browser-targeted)
+
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v6
+
+ - name: Setup Node.js ${{ matrix.node-version }}
+ uses: actions/setup-node@v6
+ with:
+ node-version: ${{ matrix.node-version }}
+ cache: 'npm'
+
+ - name: Install dependencies
+ run: npm ci
+
+ - name: Build test artifacts
+ run: npm run vite:test:ci
+
+ - name: Run integration tests
+ run: npm run test:int
+
+ - name: Upload test results
+ if: always()
+ uses: actions/upload-artifact@v7
+ with:
+ name: integration-test-results-node-${{ matrix.node-version }}
+ path: |
+ coverage/
+ retention-days: 7
diff --git a/.github/workflows/jekyll-gh-pages.oldyml b/.github/workflows/jekyll-gh-pages.oldyml
deleted file mode 100644
index 28840aa9e..000000000
--- a/.github/workflows/jekyll-gh-pages.oldyml
+++ /dev/null
@@ -1,50 +0,0 @@
-# Sample workflow for building and deploying a Jekyll site to GitHub Pages
-name: Deploy Jekyll with GitHub Pages dependencies preinstalled
-
-on:
- # Runs on pushes targeting the default branch
- push:
- branches: ["master"]
-
- # Allows you to run this workflow manually from the Actions tab
- workflow_dispatch:
-
-# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
-permissions:
- contents: read
- pages: write
- id-token: write
-
-# Allow one concurrent deployment
-concurrency:
- group: "pages"
- cancel-in-progress: true
-
-jobs:
- # Build job
- build:
- runs-on: ubuntu-latest
- steps:
- - name: Checkout
- uses: actions/checkout@v3
- - name: Setup Pages
- uses: actions/configure-pages@v3
- - name: Build with Jekyll
- uses: actions/jekyll-build-pages@v1
- with:
- source: ./
- destination: ./_site
- - name: Upload artifact
- uses: actions/upload-pages-artifact@v1
-
- # Deployment job
- deploy:
- environment:
- name: github-pages
- url: ${{ steps.deployment.outputs.page_url }}
- runs-on: ubuntu-latest
- needs: build
- steps:
- - name: Deploy to GitHub Pages
- id: deployment
- uses: actions/deploy-pages@v1
diff --git a/.github/workflows/node.js.yml b/.github/workflows/node.js.yml
deleted file mode 100644
index f77157808..000000000
--- a/.github/workflows/node.js.yml
+++ /dev/null
@@ -1,33 +0,0 @@
-# This workflow will do a clean installation of node dependencies, cache/restore them, build the source code and run tests across different versions of node
-# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-nodejs
-
-name: Node.js CI
-permissions:
- contents: read
-
-on:
- push:
- branches: [ "master" ]
- pull_request:
- branches: [ "master" ]
-
-jobs:
- build:
-
- runs-on: ubuntu-latest
-
- strategy:
- matrix:
- node-version: [20.x]
- # See supported Node.js release schedule at https://nodejs.org/en/about/releases/
-
- steps:
- - uses: actions/checkout@v4
- - name: Use Node.js ${{ matrix.node-version }}
- uses: actions/setup-node@v3
- with:
- node-version: ${{ matrix.node-version }}
- cache: 'npm'
- - run: npm ci
-# - run: npm run build:prod --if-present
- - run: npm run test:ci
diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml
index 197494e09..a875e90bb 100644
--- a/.github/workflows/playwright.yml
+++ b/.github/workflows/playwright.yml
@@ -1,7 +1,7 @@
# This workflow runs Playwright e2e tests
# For more information see: https://playwright.dev/docs/ci
-name: Playwright E2E Tests
+name: Playwright
permissions:
contents: read
@@ -13,50 +13,93 @@ on:
branches: [ "master", "dev" ]
jobs:
- test:
- timeout-minutes: 60
+ build:
+ name: Build
runs-on: ubuntu-latest
-
+ steps:
+ - uses: actions/checkout@v6
+
+ - name: Use Node.js 22.x
+ uses: actions/setup-node@v6
+ with:
+ node-version: 22.x
+ cache: 'npm'
+
+ - name: Install dependencies
+ run: npm ci
+
+ - name: Build project
+ run: TEST=1 node build-scripts/build-all.js
+
+ - name: Upload build artifacts
+ uses: actions/upload-artifact@v7
+ with:
+ name: build-output
+ path: |
+ dist/
+ js/
+ test-js/
+ retention-days: 1
+
+ e2e:
+ name: ${{ matrix.framework }}
+ needs: build
+ runs-on: ubuntu-latest
+ timeout-minutes: 15
+
strategy:
+ fail-fast: false
matrix:
- node-version: [20.x]
-
+ framework:
+ - alpine
+ - angular
+ - astro
+ - jquery
+ - parent
+ - react
+ - solid
+ - svelte
+ - vue
+ - web-component
+
steps:
- - uses: actions/checkout@v4
-
- - name: Use Node.js ${{ matrix.node-version }}
- uses: actions/setup-node@v3
+ - uses: actions/checkout@v6
+
+ - name: Use Node.js 22.x
+ uses: actions/setup-node@v6
with:
- node-version: ${{ matrix.node-version }}
+ node-version: 22.x
cache: 'npm'
-
+
- name: Install dependencies
run: npm ci
-
+
- name: Install Playwright Browsers
run: npx playwright install --with-deps chromium
-
- - name: Build project
- run: npm run rollup:debug
-
- - name: Copy built files to js-dist for e2e tests
- run: cp -r js/* js-dist/
-
+
+ - name: Download build artifacts
+ uses: actions/download-artifact@v7
+ with:
+ name: build-output
+
+ - name: Build e2e app
+ run: bash build-scripts/build-e2e-app.sh ${{ matrix.framework }}
+
- name: Run Playwright tests
- run: npm run test:e2e
-
+ run: npx playwright test e2e/tests/${{ matrix.framework }}.spec.js
+
- name: Upload test results
- uses: actions/upload-artifact@v4
+ uses: actions/upload-artifact@v7
if: always()
with:
- name: playwright-report
+ name: playwright-report-${{ matrix.framework }}
path: playwright-report/
retention-days: 30
-
+
- name: Upload test screenshots
- uses: actions/upload-artifact@v4
+ uses: actions/upload-artifact@v7
if: failure()
with:
- name: playwright-screenshots
+ name: playwright-screenshots-${{ matrix.framework }}
path: test-results/
retention-days: 30
diff --git a/.github/workflows/vitest.js.yml b/.github/workflows/vitest.js.yml
new file mode 100644
index 000000000..4f90f3b6e
--- /dev/null
+++ b/.github/workflows/vitest.js.yml
@@ -0,0 +1,26 @@
+# This workflow will do a clean installation of node dependencies, cache/restore them, build the source code and run tests across different versions of node
+# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-nodejs
+
+name: ViTest
+permissions:
+ contents: read
+
+on:
+ push:
+ branches: [ "master", "dev" ]
+ pull_request:
+ branches: [ "master", "dev" ]
+
+jobs:
+ build:
+ name: Unit tests
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v6
+ - name: Use Node.js 22.x
+ uses: actions/setup-node@v6
+ with:
+ node-version: 22.x
+ cache: 'npm'
+ - run: npm ci
+ - run: npm run test:unit
diff --git a/.gitignore b/.gitignore
index 777be5811..9b5ca4872 100644
--- a/.gitignore
+++ b/.gitignore
@@ -11,8 +11,21 @@ js/*
dist
test-js
example-test
+.eslintcache
# Playwright
/test-results/
/playwright-report/
/playwright/.cache/
+
+example/astro/.astro/
+e2e/fixtures/react/
+e2e/fixtures/vue/
+e2e/apps/*/node_modules/
+e2e/fixtures/alpine/
+e2e/fixtures/angular/
+e2e/fixtures/astro/
+e2e/fixtures/solid/
+e2e/fixtures/svelte/
+e2e/fixtures/web-component/
+e2e/apps/*/node_modules/
diff --git a/.ncurc.json b/.ncurc.json
index a1db7e7d4..749d106c7 100644
--- a/.ncurc.json
+++ b/.ncurc.json
@@ -1,12 +1,9 @@
{
"reject": [
- "@jest/globals",
- "jest",
- "jest-environment-jsdom",
+ "@angular/core",
"grunt-contrib-quint",
"eslint",
"eslint-plugin-compat",
- "eslint-plugin-jest",
"eslint-plugin-json",
"eslint-plugin-lodash",
"eslint-plugin-markdown",
diff --git a/.vscode/settings.json b/.vscode/settings.json
index 31f8bf041..b428bc6d1 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -1,6 +1,11 @@
{
"cSpell.words": [
+ "alpinejs",
"Automagically",
+ "bodybackground",
+ "bodymargin",
+ "bodypadding",
+ "checkorigin",
"chorizontal",
"ciframe",
"cnone",
@@ -15,11 +20,22 @@
"initialisation",
"Initialised",
"Initialising",
+ "inpagelinks",
"javascripts",
"logcapture",
"Loggable",
+ "networkidle",
+ "offsetsize",
"sarif",
"scanjs",
- "sonarjs"
- ]
+ "sonarjs",
+ "warningtimeout"
+ ],
+ "chat.tools.terminal.autoApprove": {
+ "npm run -s test:unit:cov": true,
+ "npm run -s test:unit": true,
+ "npm run -s test:int": true
+ },
+ "claudeCodeChat.permissions.yoloMode": false,
+ "angular.enable-strict-mode-prompt": false
}
diff --git a/CLAUDE.md b/CLAUDE.md
new file mode 100644
index 000000000..609a35dc0
--- /dev/null
+++ b/CLAUDE.md
@@ -0,0 +1,106 @@
+# CLAUDE.md
+
+This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
+
+## Project Overview
+
+iframe-resizer is a library that automatically resizes iframes to fit their content. It works via a two-part system: a **parent** script on the host page and a **child** script inside the iframe, communicating over `postMessage` with a colon-separated string protocol (prefixed `[iFrameSizer]`).
+
+## Monorepo Structure
+
+This is a manual monorepo (no npm workspaces). Packages under `packages/` do not have their own `package.json` — those are generated at build time into `dist/`.
+
+| Package | Role |
+|---------|------|
+| `common` | Shared constants (`consts.js`), utilities, pub/sub |
+| `core` | Parent-side engine: `connectResizer(options)` → `(iframe) => resizer` |
+| `parent` | Distribution wrappers (ESM/UMD/IIFE) around core's factory |
+| `child` | Child iframe engine: observers, size calculation, sends dimensions to parent |
+| `react` | React component wrapping core |
+| `vue` | Vue 3 SFC + plugin wrapping core |
+| `angular` | Angular standalone directive wrapping core |
+| `jquery` | jQuery plugin wrapping core |
+| `legacy` | v4 backward-compat bundle (parent + child + jquery) |
+| `smoke` | Import smoke tests for all modules |
+
+**Dependency flow:** `common` ← `core` ← `parent`/`react`/`vue`/`angular`/`jquery`; `common` ← `child` (independent of core). Parent and child communicate only via `postMessage`.
+
+## Build System
+
+Despite the filename, `vite.config.js` is a **Rollup** configuration driven programmatically by `vite-build.js`.
+
+```bash
+npm run build:dev # DEBUG=1, builds IIFE bundles to js/ only (fast)
+npm run build:prod # Full production build: eslint + all formats to dist/ and js/
+npm run build:beta # Beta build with sourcemaps
+```
+
+**Output directories:**
+- `dist/` — npm-publishable packages (ESM/CJS/UMD per package)
+- `js/` — Browser IIFE bundles
+- `test-js/` — UMD builds for Karma integration tests
+- `js-dist/` — Static copy of js/ for e2e tests
+
+**Build environment flags:** `DEBUG=1`, `BETA=1`, `TEST=1`, `WATCH=1`
+
+Production builds strip debug logging (`@rollup/plugin-strip`) and test code (markers: `/* TEST CODE START */` / `/* TEST CODE END */`).
+
+## Testing
+
+Three test tiers:
+
+```bash
+npm test # Full suite: eslint + build + e2e + integration + unit
+npm run test:unit # Vitest only (fast, use during development)
+npm run test:int # Karma/Jasmine integration tests (needs test-js/ built)
+npm run test:e2e # Playwright e2e (needs js-dist/ and http-server)
+```
+
+**Unit tests (Vitest):** Co-located as `*.test.js` next to source in `packages/`. Environment: jsdom. Coverage: V8.
+```bash
+npx vitest run packages/core/router.test.js # Run single test file
+npm run test:watch # Watch mode
+```
+
+**Integration tests (Karma + Jasmine):** In `spec/`. Uses RequireJS + ChromeHeadless. Tests real postMessage between parent/child.
+
+**E2E tests (Playwright):** In `e2e/`. Serves `example/html/` pages on localhost:8080.
+
+### Test conventions
+- Use extensionless imports in tests
+- Reset Vitest module state per test when relying on internal singletons
+- Prefer `vi.mock` with factory functions; call `vi.restoreAllMocks()` in `beforeEach`
+
+## Linting
+
+```bash
+npm run eslint:fix # Lint and auto-fix (run before commits)
+npm run eslint # Lint only
+```
+
+ESLint config: `.eslintrc.json` (extends eslint-config-auto). Prettier: no semicolons, single quotes, trailing commas, 2-space indent.
+
+## Code Style
+
+- ES modules (`"type": "module"` in package.json)
+- No semicolons, single quotes, trailing commas
+- Node >= 20 required
+
+## Key Architectural Patterns
+
+- **Curried factory:** `connectResizer(options)` returns `(iframe) => resizer`, allowing shared options across multiple iframes
+- **Shared mutable settings:** Parent stores per-iframe config in a plain object keyed by iframe ID (`core/values/settings.js`)
+- **String protocol:** Core messages use colon-separated strings (not JSON) for backward compatibility. Only user messages and pageInfo use JSON.
+- **Same-origin optimization:** When parent/child share an origin, messages bypass postMessage via `window.iframeChildListener` / `window.iframeParentListener`
+- **Frame-based throttling:** Child's `sendSize()` uses `requestAnimationFrame` to coalesce resize messages
+- **User code isolation:** Callbacks invoked via `setTimeout(fn, 0)` to prevent user errors from crashing the library (except `onBeforeClose`/`onScroll` which need sync returns)
+- **`once()` guard:** Global message listener setup runs exactly once via the `once()` utility
+- **types** are imported from the core package
+
+## Key rules
+- **Always run `npm run eslint:fix` before every commit/check-in.** This is mandatory — do not skip it.
+- `js-dist/` is just for the distribution of the latest published version. It should never be updated, except by running `npm run publish`
+ - `js-dist/` should not be used for testing
+ - `example-test` should never be checked in to git or used with test scripts. It is just for manual testing.
+ - `example` is a public demo and uses `js` it should not be used for tests.
+
\ No newline at end of file
diff --git a/FIXES.md b/FIXES.md
new file mode 100644
index 000000000..a08abec5e
--- /dev/null
+++ b/FIXES.md
@@ -0,0 +1,22 @@
+# Fixes
+
+## Type Fixes
+
+- **`LogOption` type broadened from `-1` to `number`** — allows the new numeric shorthands to be type-safe without requiring an explicit union for every value
+- **`onBeforeResize` signature updated** — now receives `(newSize, event, direction)` instead of only `newSize`, giving callbacks the context needed to act on the event
+- **`logExpand` type safety in Angular directive** — fixed incorrect type inference for the `logExpand` option
+
+## Logic Fixes
+
+- **URL param `?ifrlog` checks made explicit for all log levels** — each log level (`0`/`1`/`2`/`expanded`/`collapsed`) now has an explicit branch in `manual-logging.ts` rather than relying on fall-through to the `else` block; uses `EXPAND`/`COLLAPSE` string constants instead of inline literals
+- **Alpine directive options evaluation** — fixed options not being evaluated correctly and updated event data display
+
+## Refactoring (correctness improvements)
+
+- **Union types derived from consts** — `Direction`, `LogOption`, and `ScrollOption` types in `core/types.ts` are now defined as `typeof CONST` unions rather than duplicating string literals, eliminating the risk of type and runtime value drifting apart
+- **`OMIT` constant extracted** — removed a local `const OMIT = 'omit'` in `core/setup/scrolling.ts` in favour of the shared constant from `common/consts`
+
+## Test Fixes
+
+- **Intermittent race conditions in Jasmine integration tests** — added appropriate delays/guards to prevent flaky test failures
+- **Missing test coverage for `?ifrlog=collapsed`** — added explicit test to ensure the string form of the URL param continues to work alongside the new numeric values
diff --git a/FUNDING.md b/FUNDING.md
deleted file mode 100644
index 79c2ac986..000000000
--- a/FUNDING.md
+++ /dev/null
@@ -1,5 +0,0 @@
-# Donate to Iframe-Resizer
-
-Iframe-resizer is the result of many 100s of hours of work, if you would like to join others in showing support for the development of this project, then please feel free to buy me a coffee.
-
-
diff --git a/LICENSE b/LICENSE
index 9f6eb8dc1..42e3940e7 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,6 +1,8 @@
-Iframe Resizer Version 5
+Iframe Resizer Version 6
-This JavaScript library is Copyright © 2013-2025 David J. Bradshaw and is dual-licensed, either under GPL V3, or a commercial license that is available for purchase upon request.
+This JavaScript library is Copyright © 2013-2026 David J. Bradshaw and is dual-licensed, either under GPL V3 for compliant
+sites (Fully published front and backend source code). Or alternatively it is available under a commercial license for
+sites that do not wish to use the GPL.
For more information on commercial licensing see https://iframe-resizer.com/pricing/
diff --git a/MIGRATION_SUMMARY.md b/MIGRATION_SUMMARY.md
new file mode 100644
index 000000000..bb9a15ed0
--- /dev/null
+++ b/MIGRATION_SUMMARY.md
@@ -0,0 +1,656 @@
+# Rollup-to-Vite Build System Migration - Summary
+
+## Migration Completed Successfully ✅
+
+Date: 2026-02-16
+
+## What Changed
+
+### Build System Architecture
+
+**Before:**
+- Single `vite.config.js` with pure Rollup configurations
+- `vite-build.js` script running Rollup API directly
+- Confusing: files named "vite" but using only Rollup
+
+**After:**
+- Hybrid approach: Vite library mode for simple packages, Rollup configs for complex ones
+- `build-scripts/build-all.js` orchestrator
+- `vite.config/` directory with per-package configs
+- Proper use of Vite's capabilities where appropriate
+
+### File Structure
+
+```
+mono/
+├── vite.config/ # NEW: Per-package configs
+│ ├── core.config.js # Vite library mode
+│ ├── child.config.js # Vite library mode
+│ ├── parent.config.js # Rollup (multiple entries)
+│ ├── react.config.js # Vite library mode
+│ ├── vue.config.js # Vite library mode
+│ ├── vue.post-build.js # Post-build for SFC
+│ ├── angular.config.js # Vite library mode
+│ ├── jquery.config.js # Rollup (multiple entries)
+│ └── shared/ # Migrated from build/
+│ ├── banner.js
+│ ├── output.js
+│ ├── plugins.js
+│ └── pkgJson.js
+├── build-scripts/ # NEW: Build orchestration
+│ ├── build-all.js # Main orchestrator
+│ ├── build-browser.js # js/ IIFE builds
+│ └── build-tests.js # test-js/ UMD builds
+```
+
+### Key Improvements
+
+1. **Vue TypeScript Support** ✅
+ - Vue SFC now uses `
+