├── .gitattributes ├── .github └── workflows │ ├── ci.yml │ ├── github-release.yml │ └── publish.yml ├── .gitignore ├── .husky ├── .gitignore └── pre-commit ├── .prettierignore ├── CHANGELOG.md ├── LICENSE ├── MIGRATION.md ├── README.md ├── client.d.ts ├── client.mjs ├── package.json ├── pnpm-lock.yaml ├── src ├── devBuilder │ ├── devBuilder.ts │ ├── devBuilderManifestV2.ts │ └── devBuilderManifestV3.ts ├── index.ts ├── manifestParser │ ├── manifestParser.ts │ ├── manifestParserFactory.ts │ ├── manifestV2.ts │ └── manifestV3.ts ├── middleware │ └── viteClientModifier.ts └── utils │ ├── addHmrSupportToCsp.ts │ ├── file.ts │ ├── getAdditionalInputAsWebAccessibleResource.ts │ ├── getNormalizedAdditionalInput.ts │ ├── loader.ts │ ├── rollup.ts │ ├── virtualModule.ts │ └── vite.ts ├── test ├── manifest │ ├── __snapshots__ │ │ ├── additionalInputsHtml.v2.test.ts.snap │ │ ├── additionalInputsHtml.v3.test.ts.snap │ │ ├── additionalInputsScriptsChunkedImport.v2.test.ts.snap │ │ ├── additionalInputsScriptsChunkedImport.v3.test.ts.snap │ │ ├── additionalInputsScriptsNoImport.v2.test.ts.snap │ │ ├── additionalInputsScriptsNoImport.v3.test.ts.snap │ │ ├── additionalInputsScriptsTypes.v2.test.ts.snap │ │ ├── additionalInputsScriptsTypes.v3.test.ts.snap │ │ ├── additionalInputsScriptsUnchunkedImport.v2.test.ts.snap │ │ ├── additionalInputsScriptsUnchunkedImport.v3.test.ts.snap │ │ ├── additionalInputsStylesTypes.v2.test.ts.snap │ │ ├── additionalInputsStylesTypes.v3.test.ts.snap │ │ ├── additionalInputsWebAccessible.v2.test.ts.snap │ │ ├── additionalInputsWebAccessible.v3.test.ts.snap │ │ ├── additionalInputsWebAccessibleExcludeEntryFile.v2.test.ts.snap │ │ ├── additionalInputsWebAccessibleExcludeEntryFile.v3.test.ts.snap │ │ ├── backgroundHtml.v2.test.ts.snap │ │ ├── backgroundScript.v2.test.ts.snap │ │ ├── backgroundServiceWorker.v3.test.ts.snap │ │ ├── backgroundServiceWorkerRelative.v3.test.ts.snap │ │ ├── backgroundServiceWorkerRoot.v3.test.ts.snap │ │ ├── chromeUrlOverridesHtmlBookmarks.v2.test.ts.snap │ │ ├── chromeUrlOverridesHtmlBookmarks.v3.test.ts.snap │ │ ├── chromeUrlOverridesHtmlHistory.v2.test.ts.snap │ │ ├── chromeUrlOverridesHtmlHistory.v3.test.ts.snap │ │ ├── chromeUrlOverridesHtmlNewTab.v2.test.ts.snap │ │ ├── chromeUrlOverridesHtmlNewTab.v3.test.ts.snap │ │ ├── chunkCssRewrite.v2.test.ts.snap │ │ ├── chunkCssRewrite.v3.test.ts.snap │ │ ├── contentCss.v2.test.ts.snap │ │ ├── contentCss.v3.test.ts.snap │ │ ├── contentScriptPaths.v2.test.ts.snap │ │ ├── contentScriptPaths.v3.test.ts.snap │ │ ├── contentScriptTypes.v2.test.ts.snap │ │ ├── contentScriptTypes.v3.test.ts.snap │ │ ├── contentWithChunkedImport.v2.test.ts.snap │ │ ├── contentWithChunkedImport.v3.test.ts.snap │ │ ├── contentWithDynamicImport.v2.test.ts.snap │ │ ├── contentWithDynamicImport.v3.test.ts.snap │ │ ├── contentWithNoImports.v2.test.ts.snap │ │ ├── contentWithNoImports.v3.test.ts.snap │ │ ├── contentWithSameScriptName.v2.test.ts.snap │ │ ├── contentWithSameScriptName.v3.test.ts.snap │ │ ├── contentWithUnchunkedImport.v2.test.ts.snap │ │ ├── contentWithUnchunkedImport.v3.test.ts.snap │ │ ├── devtoolsHtml.v2.test.ts.snap │ │ ├── devtoolsHtml.v3.test.ts.snap │ │ ├── fullExtension.v2.test.ts.snap │ │ ├── fullExtension.v3.test.ts.snap │ │ ├── htmlUrlProperties.v2.test.ts.snap │ │ ├── htmlUrlProperties.v3.test.ts.snap │ │ ├── optimizeWebAccessibleResourcesDisabled.v2.test.ts.snap │ │ ├── optimizeWebAccessibleResourcesDisabled.v3.test.ts.snap │ │ ├── optimizeWebAccessibleResourcesEnabled.v2.test.ts.snap │ │ ├── optimizeWebAccessibleResourcesEnabled.v3.test.ts.snap │ │ ├── optionsHtml.v2.test.ts.snap │ │ ├── optionsHtml.v3.test.ts.snap │ │ ├── popupHtml.v2.test.ts.snap │ │ ├── popupHtml.v3.test.ts.snap │ │ ├── sidePanelHtml.v3.test.ts.snap │ │ ├── useDynamicUrlWebAccessibleResourcesDisabled.v3.test.ts.snap │ │ ├── useDynamicUrlWebAccessibleResourcesEnabled.v3.test.ts.snap │ │ └── useDynamicUrlWebAccessibleResourcesUndefined.v3.test.ts.snap │ ├── additionalInputsHtml.v2.test.ts │ ├── additionalInputsHtml.v3.test.ts │ ├── additionalInputsScriptsChunkedImport.v2.test.ts │ ├── additionalInputsScriptsChunkedImport.v3.test.ts │ ├── additionalInputsScriptsNoImport.v2.test.ts │ ├── additionalInputsScriptsNoImport.v3.test.ts │ ├── additionalInputsScriptsTypes.v2.test.ts │ ├── additionalInputsScriptsTypes.v3.test.ts │ ├── additionalInputsScriptsUnchunkedImport.v2.test.ts │ ├── additionalInputsScriptsUnchunkedImport.v3.test.ts │ ├── additionalInputsStylesTypes.v2.test.ts │ ├── additionalInputsStylesTypes.v3.test.ts │ ├── additionalInputsWebAccessible.v2.test.ts │ ├── additionalInputsWebAccessible.v3.test.ts │ ├── additionalInputsWebAccessibleExcludeEntryFile.v2.test.ts │ ├── additionalInputsWebAccessibleExcludeEntryFile.v3.test.ts │ ├── backgroundHtml.v2.test.ts │ ├── backgroundScript.v2.test.ts │ ├── backgroundServiceWorker.v3.test.ts │ ├── backgroundServiceWorkerRelative.v3.test.ts │ ├── backgroundServiceWorkerRoot.v3.test.ts │ ├── chromeUrlOverridesHtmlBookmarks.v2.test.ts │ ├── chromeUrlOverridesHtmlBookmarks.v3.test.ts │ ├── chromeUrlOverridesHtmlHistory.v2.test.ts │ ├── chromeUrlOverridesHtmlHistory.v3.test.ts │ ├── chromeUrlOverridesHtmlNewTab.v2.test.ts │ ├── chromeUrlOverridesHtmlNewTab.v3.test.ts │ ├── chunkCssRewrite.v2.test.ts │ ├── chunkCssRewrite.v3.test.ts │ ├── contentCss.v2.test.ts │ ├── contentCss.v3.test.ts │ ├── contentScriptPaths.v2.test.ts │ ├── contentScriptPaths.v3.test.ts │ ├── contentScriptTypes.v2.test.ts │ ├── contentScriptTypes.v3.test.ts │ ├── contentWithChunkedImport.v2.test.ts │ ├── contentWithChunkedImport.v3.test.ts │ ├── contentWithDynamicImport.v2.test.ts │ ├── contentWithDynamicImport.v3.test.ts │ ├── contentWithNoImports.v2.test.ts │ ├── contentWithNoImports.v3.test.ts │ ├── contentWithSameScriptName.v2.test.ts │ ├── contentWithSameScriptName.v3.test.ts │ ├── contentWithUnchunkedImport.v2.test.ts │ ├── contentWithUnchunkedImport.v3.test.ts │ ├── devtoolsHtml.v2.test.ts │ ├── devtoolsHtml.v3.test.ts │ ├── fullExtension.v2.test.ts │ ├── fullExtension.v3.test.ts │ ├── htmlUrlProperties.v2.test.ts │ ├── htmlUrlProperties.v3.test.ts │ ├── manifestTestUtils.ts │ ├── optimizeWebAccessibleResourcesDisabled.v2.test.ts │ ├── optimizeWebAccessibleResourcesDisabled.v3.test.ts │ ├── optimizeWebAccessibleResourcesEnabled.v2.test.ts │ ├── optimizeWebAccessibleResourcesEnabled.v3.test.ts │ ├── optionsHtml.v2.test.ts │ ├── optionsHtml.v3.test.ts │ ├── popupHtml.v2.test.ts │ ├── popupHtml.v3.test.ts │ ├── resources │ │ ├── additionalInputsHtml │ │ │ ├── html.html │ │ │ ├── script.js │ │ │ └── style.css │ │ ├── additionalInputsScriptsChunkedImport │ │ │ ├── script1.js │ │ │ └── script2.js │ │ ├── additionalInputsScriptsNoImport │ │ │ ├── script1.js │ │ │ └── script2.js │ │ ├── additionalInputsScriptsTypes │ │ │ ├── script1.js │ │ │ └── script2.ts │ │ ├── additionalInputsScriptsUnchunkedImport │ │ │ ├── script1.js │ │ │ └── script2.js │ │ ├── additionalInputsStylesTypes │ │ │ ├── style1.css │ │ │ └── style2.scss │ │ ├── additionalInputsWebAccessible │ │ │ ├── chunkedScript1.js │ │ │ ├── chunkedScript2.js │ │ │ ├── chunkedScript3.js │ │ │ ├── script1.js │ │ │ ├── script2.js │ │ │ ├── script3.js │ │ │ ├── script4.js │ │ │ ├── script5.ts │ │ │ ├── script6.js │ │ │ └── script7.js │ │ ├── backgroundHtml │ │ │ ├── background.html │ │ │ └── background.js │ │ ├── backgroundScript │ │ │ ├── background.html │ │ │ └── background.js │ │ ├── backgroundServiceWorker │ │ │ └── serviceWorker.js │ │ ├── chromeUrlOverridesHtml │ │ │ ├── bookmarks.html │ │ │ ├── chromeUrlOverridesHtml.js │ │ │ ├── devtools.html │ │ │ ├── history.html │ │ │ └── newtab.html │ │ ├── chunkCssRewrite │ │ │ ├── content1.css │ │ │ ├── content1.js │ │ │ ├── content2.css │ │ │ ├── content2.js │ │ │ ├── contentNoCss.js │ │ │ └── contentShared.css │ │ ├── contentCss │ │ │ ├── content.js │ │ │ ├── content1.css │ │ │ └── content2.scss │ │ ├── contentScriptTypes │ │ │ ├── content1.js │ │ │ └── content2.ts │ │ ├── contentWithChunkedImport │ │ │ ├── content1.js │ │ │ └── content2.js │ │ ├── contentWithDynamicImport │ │ │ ├── content1.js │ │ │ └── content2.js │ │ ├── contentWithNoImports │ │ │ └── content.js │ │ ├── contentWithSameScriptName │ │ │ ├── content1 │ │ │ │ └── content.js │ │ │ └── content2 │ │ │ │ └── content.js │ │ ├── contentWithUnchunkedImport │ │ │ └── content.js │ │ ├── devtoolsHtml │ │ │ ├── devtools.html │ │ │ └── devtools.js │ │ ├── fullExtension │ │ │ └── src │ │ │ │ ├── assets │ │ │ │ └── logo.svg │ │ │ │ ├── entries │ │ │ │ ├── background │ │ │ │ │ └── main.js │ │ │ │ ├── contentScript │ │ │ │ │ ├── primary │ │ │ │ │ │ ├── main.js │ │ │ │ │ │ └── style.css │ │ │ │ │ └── renderContent.js │ │ │ │ ├── options │ │ │ │ │ ├── index.html │ │ │ │ │ ├── main.js │ │ │ │ │ └── style.css │ │ │ │ └── popup │ │ │ │ │ ├── index.html │ │ │ │ │ ├── main.js │ │ │ │ │ └── style.css │ │ │ │ └── lib.js │ │ ├── htmlUrlProperties │ │ │ ├── devtools.html │ │ │ ├── devtools.js │ │ │ ├── options.html │ │ │ ├── options.js │ │ │ ├── popup.html │ │ │ └── popup.js │ │ ├── optimizeWebAccessibleResources │ │ │ ├── content1.js │ │ │ ├── content2.js │ │ │ ├── script1.js │ │ │ └── script2.js │ │ ├── optionsHtml │ │ │ ├── options.html │ │ │ └── options.js │ │ ├── popupHtml │ │ │ ├── popup.html │ │ │ └── popup.js │ │ ├── shared │ │ │ └── log.js │ │ ├── sidePanelHtml │ │ │ ├── sidepanel.html │ │ │ └── sidepanel.js │ │ └── useDynamicUrlWebAccessibleResources │ │ │ ├── content1.js │ │ │ ├── content2.js │ │ │ ├── script1.js │ │ │ └── script2.js │ ├── sidePanelHtml.v3.test.ts │ ├── useDynamicUrlWebAccessibleResourcesDisabled.v3.test.ts │ ├── useDynamicUrlWebAccessibleResourcesEnabled.v3.test.ts │ └── useDynamicUrlWebAccessibleResourcesUndefined.v3.test.ts └── utils │ ├── addHmrSupportToCsp.test.ts │ └── rollup.test.ts ├── tsconfig.json └── types └── index.d.ts /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto eol=lf -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: ci 2 | 3 | on: 4 | push: 5 | branches: [main] 6 | pull_request: 7 | branches: [main] 8 | 9 | jobs: 10 | build: 11 | runs-on: ${{ matrix.os }} 12 | 13 | strategy: 14 | matrix: 15 | os: [ubuntu-latest, windows-latest] 16 | 17 | steps: 18 | - name: Checkout 19 | uses: actions/checkout@v3 20 | 21 | - name: Install pnpm 22 | uses: pnpm/action-setup@v4.0.0 23 | 24 | - name: Setup node 25 | uses: actions/setup-node@v4.0.4 26 | with: 27 | node-version: 18.x 28 | registry-url: https://registry.npmjs.org/ 29 | cache: "pnpm" 30 | 31 | - name: Install dependencies 32 | run: pnpm install 33 | 34 | - name: Check formatting 35 | run: pnpm lint:check 36 | 37 | - name: Test 38 | run: pnpm test 39 | 40 | - name: Build 41 | run: pnpm build 42 | -------------------------------------------------------------------------------- /.github/workflows/github-release.yml: -------------------------------------------------------------------------------- 1 | name: Create Github Release 2 | 3 | on: 4 | push: 5 | tags: 6 | - "v*" 7 | 8 | jobs: 9 | release: 10 | runs-on: ubuntu-latest 11 | 12 | steps: 13 | - name: Checkout 14 | uses: actions/checkout@v3 15 | 16 | - name: Extract release notes 17 | id: extract-release-notes 18 | uses: ffurrer2/extract-release-notes@v1 19 | 20 | - name: Create release 21 | run: | 22 | gh release create "${GITHUB_REF#refs/tags/}" -n "$RELEASE_NOTES" 23 | env: 24 | GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} 25 | RELEASE_NOTES: ${{ steps.extract-release-notes.outputs.release_notes }} 26 | -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: Publish Package 2 | 3 | on: 4 | push: 5 | tags: 6 | - "v*" 7 | 8 | jobs: 9 | publish: 10 | runs-on: ubuntu-latest 11 | permissions: 12 | id-token: write 13 | steps: 14 | - name: Checkout 15 | uses: actions/checkout@v3 16 | 17 | - name: Install pnpm 18 | uses: pnpm/action-setup@v4.0.0 19 | 20 | - name: Setup node 21 | uses: actions/setup-node@v4.0.4 22 | with: 23 | node-version: 18.x 24 | registry-url: https://registry.npmjs.org/ 25 | cache: "pnpm" 26 | 27 | - name: Install dependencies 28 | run: pnpm install 29 | 30 | - name: Publish package 31 | run: pnpm publish --access public --no-git-checks 32 | env: 33 | NODE_AUTH_TOKEN: ${{secrets.NODE_AUTH_TOKEN}} 34 | NPM_CONFIG_PROVENANCE: true 35 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | **/node_modules/ 2 | **/dist/ 3 | .DS_Store 4 | -------------------------------------------------------------------------------- /.husky/.gitignore: -------------------------------------------------------------------------------- 1 | _ 2 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | pnpm exec lint-staged 5 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | **/node_modules/ 2 | pnpm-lock.yaml 3 | dist/ 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022-present Ruben Medina 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /MIGRATION.md: -------------------------------------------------------------------------------- 1 | # Migration 2 | 3 | - [Version 4.x.x to 5.0.0](#version-4xx-to-500) 4 | - [Version 3.x.x to 4.0.0](#version-3xx-to-400) 5 | - [Version 2.x.x to 3.0.0](#version-2xx-to-300) 6 | - [Version 0.x.x to 1.0.0](#version-0xx-to-100) 7 | 8 | ## Version 4.x.x to 5.0.0 9 | 10 | - The `devHtmlTransform` plugin option has been removed. Vite's dev HTML transform functionality is now required to support HTML files in dev (HMR) mode. In dev mode, a element with the dev server url for the HTML file is injected into the page. This replaces incomplete custom logic for handling resources in HTML files. 11 | 12 | ## Version 3.x.x to 4.0.0 13 | 14 | - Dev mode HTML transforms are no longer applied by default. Enable via the new devHtmlTransform option if still needed. 15 | - The useDynamicUrlContentScripts option has been renamed to useDynamicUrlWebAccessibleResources 16 | - The webAccessibleScripts option has been removed and replaced by the additionalInputs option. For similar functionality, move scripts to additionalInputs.scripts and html files to additionalInputs.html. Check the README for detailed usage instructions. 17 | 18 | ## Version 2.x.x to 3.0.0 19 | 20 | - Upgrade Vite to 4.0.3 21 | 22 | - Upgrade any Vite framework plugins 23 | 24 | - The build.modulePreload Vite config option is now defaulted to false by the plugin. Prevent using this default by defining the option in your project's Vite config. 25 | 26 | ## Version 0.x.x to 1.0.0 27 | 28 | - Upgrade Vite to 2.9.x 29 | 30 | - Upgrade any Vite framework plugins 31 | 32 | - Replace usages of `import.meta.CURRENT_CONTENT_SCRIPT_CSS_URL` with `import.meta.PLUGIN_WEB_EXT_CHUNK_CSS_PATHS` 33 | 34 | - `import.meta.PLUGIN_WEB_EXT_CHUNK_CSS_PATHS` is replaced with an array of css paths at build time, so update existing code that expects a single string to properly handle an array of strings. 35 | 36 | - Replace usages of `addStyleTarget` from `/@vite/client` with `addViteStyleTarget` from `@samrum/vite-plugin-web-extension/client`: 37 | 38 | ```js 39 | const { addStyleTarget } = await import("/@vite/client"); 40 | 41 | addStyleTarget(shadowRoot); 42 | ``` 43 | 44 | to 45 | 46 | ```js 47 | const { addViteStyleTarget } = await import( 48 | "@samrum/vite-plugin-web-extension/client" 49 | ); 50 | 51 | await addViteStyleTarget(shadowRoot); 52 | ``` 53 | 54 | - If using TypeScript, add plugin client types to your `env.d.ts` file: 55 | ```ts 56 | /// 57 | ``` 58 | -------------------------------------------------------------------------------- /client.d.ts: -------------------------------------------------------------------------------- 1 | interface ImportMeta { 2 | PLUGIN_WEB_EXT_CHUNK_CSS_PATHS: string[]; 3 | } 4 | 5 | declare module "@samrum/vite-plugin-web-extension/client" { 6 | export function addViteStyleTarget(element: Node): Promise; 7 | } 8 | -------------------------------------------------------------------------------- /client.mjs: -------------------------------------------------------------------------------- 1 | export async function addViteStyleTarget(element) { 2 | const { addStyleTarget } = await import("/@vite/client"); 3 | 4 | addStyleTarget(element); 5 | } 6 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@samrum/vite-plugin-web-extension", 3 | "version": "5.1.1", 4 | "description": "A vite plugin for generating cross browser platform, ES module based web extensions", 5 | "main": "./dist/index.cjs", 6 | "module": "./dist/index.mjs", 7 | "types": "./types/index.d.ts", 8 | "type": "module", 9 | "exports": { 10 | ".": { 11 | "types": "./types/index.d.ts", 12 | "import": "./dist/index.mjs", 13 | "require": "./dist/index.cjs" 14 | }, 15 | "./client": { 16 | "types": "./client.d.ts", 17 | "import": "./client.mjs", 18 | "require": "./client.mjs" 19 | } 20 | }, 21 | "engines": { 22 | "node": ">=16.0.0" 23 | }, 24 | "packageManager": "pnpm@8.3.1", 25 | "files": [ 26 | "client.mjs", 27 | "client.d.ts", 28 | "dist", 29 | "README.md", 30 | "types" 31 | ], 32 | "scripts": { 33 | "build": "unbuild", 34 | "dev": "unbuild --stub", 35 | "lint": "prettier --write --loglevel warn .", 36 | "lint:check": "prettier --check .", 37 | "test": "vitest", 38 | "test:run": "vitest run", 39 | "prepare": "husky install", 40 | "prepublishOnly": "pnpm run build", 41 | "release": "standard-version --sign" 42 | }, 43 | "standard-version": { 44 | "scripts": { 45 | "prerelease": "pnpm test:run && pnpm build" 46 | } 47 | }, 48 | "repository": { 49 | "type": "git", 50 | "url": "git+https://github.com/samrum/vite-plugin-web-extension.git" 51 | }, 52 | "keywords": [ 53 | "vite", 54 | "vite-plugin", 55 | "web", 56 | "extension", 57 | "browser", 58 | "chrome", 59 | "firefox", 60 | "edge", 61 | "manifest", 62 | "manifest V2", 63 | "manifest V3" 64 | ], 65 | "author": "Ruben Medina", 66 | "license": "MIT", 67 | "bugs": { 68 | "url": "https://github.com/samrum/vite-plugin-web-extension/issues" 69 | }, 70 | "homepage": "https://github.com/samrum/vite-plugin-web-extension#readme", 71 | "devDependencies": { 72 | "@types/fs-extra": "^11.0.4", 73 | "@types/node": "^20.10.4", 74 | "husky": "^8.0.3", 75 | "lint-staged": "^15.2.0", 76 | "prettier": "2.8.8", 77 | "rollup": "^4.8.0", 78 | "sass": "^1.69.5", 79 | "standard-version": "^9.5.0", 80 | "typescript": "^5.3.3", 81 | "unbuild": "^2.0.0", 82 | "vitest": "^2.1.1" 83 | }, 84 | "peerDependencies": { 85 | "vite": "^4.0.3 || ^5.0.0" 86 | }, 87 | "lint-staged": { 88 | "*": [ 89 | "prettier --write --cache --ignore-unknown" 90 | ] 91 | }, 92 | "dependencies": { 93 | "@types/chrome": "^0.0.233", 94 | "@types/etag": "^1.8.3", 95 | "content-security-policy-parser": "^0.4.1", 96 | "etag": "^1.8.1", 97 | "fs-extra": "^11.2.0", 98 | "magic-string": "^0.30.5", 99 | "vite": "^5.0.7" 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /src/devBuilder/devBuilderManifestV2.ts: -------------------------------------------------------------------------------- 1 | import { createHash } from "node:crypto"; 2 | import { ViteWebExtensionOptions } from "../../types"; 3 | import DevBuilder from "./devBuilder"; 4 | 5 | export default class DevBuilderManifestV2 extends DevBuilder { 6 | protected updateContentSecurityPolicyForHmr(): void { 7 | this.manifest.content_security_policy = 8 | this.getContentSecurityPolicyWithHmrSupport( 9 | this.manifest.content_security_policy 10 | ); 11 | } 12 | 13 | protected parseInlineScriptHashes(content: string) { 14 | const matches = content.matchAll(/([^<]+)<\/script>/gs); 15 | for (const match of matches) { 16 | const shasum = createHash("sha256"); 17 | shasum.update(match[1]); 18 | 19 | this.inlineScriptHashes.add(`'sha256-${shasum.digest("base64")}'`); 20 | } 21 | } 22 | 23 | protected async writeManifestAdditionalInputFiles(): Promise { 24 | if (!this.pluginOptions.additionalInputs) { 25 | return; 26 | } 27 | 28 | for (const [type, inputs] of Object.entries( 29 | this.pluginOptions.additionalInputs 30 | )) { 31 | if (!inputs) { 32 | return; 33 | } 34 | 35 | for (const input of inputs) { 36 | if (!input) { 37 | continue; 38 | } 39 | 40 | await this.writeManifestAdditionalInputFile( 41 | type as keyof NonNullable< 42 | ViteWebExtensionOptions["additionalInputs"] 43 | >, 44 | input 45 | ); 46 | } 47 | } 48 | } 49 | 50 | protected addWebAccessibleResource({ 51 | fileName, 52 | }: { 53 | fileName: string; 54 | webAccessibleResource: { 55 | matches: string[] | undefined; 56 | extension_ids: string[] | undefined; 57 | use_dynamic_url?: boolean; 58 | }; 59 | }): void { 60 | this.manifest.web_accessible_resources ??= []; 61 | this.manifest.web_accessible_resources.push(fileName); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/devBuilder/devBuilderManifestV3.ts: -------------------------------------------------------------------------------- 1 | import { ensureDir } from "fs-extra"; 2 | import { writeFile } from "node:fs/promises"; 3 | import path from "node:path"; 4 | import { ViteWebExtensionOptions } from "../../types"; 5 | import { getServiceWorkerLoaderFile } from "../utils/loader"; 6 | import DevBuilder from "./devBuilder"; 7 | 8 | export default class DevBuilderManifestV3 extends DevBuilder { 9 | async writeBuildFiles(): Promise { 10 | await this.writeManifestServiceWorkerFiles(this.manifest); 11 | } 12 | 13 | updateContentSecurityPolicyForHmr(): void { 14 | this.manifest.content_security_policy ??= {}; 15 | 16 | this.manifest.content_security_policy.extension_pages = 17 | this.getContentSecurityPolicyWithHmrSupport( 18 | this.manifest.content_security_policy.extension_pages 19 | ); 20 | } 21 | 22 | private async writeManifestServiceWorkerFiles( 23 | manifest: chrome.runtime.ManifestV3 24 | ) { 25 | if (!manifest.background?.service_worker) { 26 | return; 27 | } 28 | 29 | const fileName = manifest.background?.service_worker; 30 | 31 | const serviceWorkerLoader = getServiceWorkerLoaderFile([ 32 | this.hmrViteClientUrl, 33 | `${this.hmrServerOrigin}/${fileName}`, 34 | ]); 35 | 36 | manifest.background.service_worker = serviceWorkerLoader.fileName; 37 | 38 | const outFile = `${this.outDir}/${serviceWorkerLoader.fileName}`; 39 | 40 | const outFileDir = path.dirname(outFile); 41 | 42 | await ensureDir(outFileDir); 43 | 44 | await writeFile(outFile, serviceWorkerLoader.source); 45 | } 46 | 47 | protected async writeManifestAdditionalInputFiles(): Promise { 48 | if (!this.pluginOptions.additionalInputs) { 49 | return; 50 | } 51 | 52 | for (const [type, inputs] of Object.entries( 53 | this.pluginOptions.additionalInputs 54 | )) { 55 | if (!inputs) { 56 | return; 57 | } 58 | 59 | for (const input of inputs) { 60 | if (!input) { 61 | continue; 62 | } 63 | 64 | await this.writeManifestAdditionalInputFile( 65 | type as keyof NonNullable< 66 | ViteWebExtensionOptions["additionalInputs"] 67 | >, 68 | input 69 | ); 70 | } 71 | } 72 | } 73 | 74 | protected addWebAccessibleResource({ 75 | fileName, 76 | webAccessibleResource, 77 | }: { 78 | fileName: string; 79 | webAccessibleResource: { 80 | matches: string[] | undefined; 81 | extension_ids: string[] | undefined; 82 | use_dynamic_url?: boolean; 83 | }; 84 | }): void { 85 | this.manifest.web_accessible_resources ??= []; 86 | 87 | if (this.pluginOptions.useDynamicUrlWebAccessibleResources !== true) { 88 | delete webAccessibleResource["use_dynamic_url"]; 89 | } 90 | 91 | // @ts-expect-error - allow additional web_accessible_resources properties 92 | this.manifest.web_accessible_resources.push({ 93 | resources: [fileName], 94 | ...webAccessibleResource, 95 | }); 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import type { EmittedFile, OutputBundle } from "rollup"; 2 | import type { Plugin, ResolvedConfig } from "vite"; 3 | import type { ViteWebExtensionOptions } from "../types"; 4 | import ManifestParser from "./manifestParser/manifestParser"; 5 | import ManifestParserFactory from "./manifestParser/manifestParserFactory"; 6 | import viteClientModifier from "./middleware/viteClientModifier"; 7 | import { addInputScriptsToOptionsInput } from "./utils/rollup"; 8 | import { getVirtualModule } from "./utils/virtualModule"; 9 | import { 10 | transformSelfLocationAssets, 11 | updateConfigForExtensionSupport, 12 | } from "./utils/vite"; 13 | 14 | export default function webExtension( 15 | pluginOptions: ViteWebExtensionOptions 16 | ): Plugin { 17 | if (!pluginOptions.manifest) { 18 | throw new Error("Missing manifest definition"); 19 | } 20 | 21 | let viteConfig: ResolvedConfig; 22 | let emitQueue: EmittedFile[] = []; 23 | let manifestParser: 24 | | ManifestParser 25 | | ManifestParser; 26 | 27 | return { 28 | name: "webExtension", 29 | enforce: "post", // required to revert vite asset self.location transform to import.meta.url 30 | 31 | config(config) { 32 | return updateConfigForExtensionSupport(config, pluginOptions.manifest); 33 | }, 34 | 35 | configResolved(resolvedConfig) { 36 | viteConfig = resolvedConfig; 37 | }, 38 | 39 | configureServer(server) { 40 | server.middlewares.use(viteClientModifier); 41 | 42 | server.httpServer?.once("listening", () => { 43 | manifestParser.setDevServer(server); 44 | manifestParser.writeDevBuild(server.config.server.port!); 45 | }); 46 | }, 47 | 48 | async options(options) { 49 | manifestParser = ManifestParserFactory.getParser( 50 | pluginOptions, 51 | viteConfig 52 | ); 53 | 54 | const { inputScripts, emitFiles } = await manifestParser.parseInput(); 55 | 56 | options.input = addInputScriptsToOptionsInput( 57 | inputScripts, 58 | options.input 59 | ); 60 | 61 | emitQueue = emitQueue.concat(emitFiles); 62 | 63 | return options; 64 | }, 65 | 66 | buildStart() { 67 | emitQueue.forEach((file) => { 68 | this.emitFile(file); 69 | 70 | const fileName = 71 | file.type === "prebuilt-chunk" 72 | ? file.fileName 73 | : file.fileName ?? file.name!; 74 | 75 | this.addWatchFile(fileName); 76 | }); 77 | emitQueue = []; 78 | }, 79 | 80 | resolveId(id) { 81 | return getVirtualModule(id) ? id : null; 82 | }, 83 | 84 | load(id) { 85 | return getVirtualModule(id); 86 | }, 87 | 88 | transform(code) { 89 | return transformSelfLocationAssets(code, viteConfig); 90 | }, 91 | 92 | async generateBundle(_options, bundle) { 93 | const { emitFiles } = await manifestParser.parseOutput( 94 | bundle as OutputBundle 95 | ); 96 | 97 | emitFiles.forEach(this.emitFile); 98 | }, 99 | }; 100 | } 101 | -------------------------------------------------------------------------------- /src/manifestParser/manifestParserFactory.ts: -------------------------------------------------------------------------------- 1 | import type { ResolvedConfig } from "vite"; 2 | import { ViteWebExtensionOptions } from "../../types"; 3 | import ManifestParser from "./manifestParser"; 4 | import ManifestV2 from "./manifestV2"; 5 | import ManifestV3 from "./manifestV3"; 6 | 7 | export default class ManifestParserFactory { 8 | static getParser( 9 | pluginOptions: ViteWebExtensionOptions, 10 | viteConfig: ResolvedConfig 11 | ): 12 | | ManifestParser 13 | | ManifestParser { 14 | switch (pluginOptions.manifest.manifest_version) { 15 | case 2: 16 | return new ManifestV2(pluginOptions, viteConfig); 17 | case 3: 18 | return new ManifestV3(pluginOptions, viteConfig); 19 | default: 20 | throw new Error( 21 | `No parser available for manifest_version ${ 22 | // @ts-expect-error - Allow showing manifest version for invalid usage 23 | manifest.manifest_version ?? 0 24 | }` 25 | ); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/manifestParser/manifestV2.ts: -------------------------------------------------------------------------------- 1 | import type { OutputBundle } from "rollup"; 2 | import { ViteWebExtensionOptions } from "../../types"; 3 | import DevBuilderManifestV2 from "../devBuilder/devBuilderManifestV2"; 4 | import getNormalizedAdditionalInput from "../utils/getNormalizedAdditionalInput"; 5 | import DevBuilder from "./../devBuilder/devBuilder"; 6 | import ManifestParser, { ParseResult } from "./manifestParser"; 7 | 8 | type Manifest = chrome.runtime.ManifestV2; 9 | type ManifestParseResult = ParseResult; 10 | 11 | export default class ManifestV2 extends ManifestParser { 12 | protected createDevBuilder(): DevBuilder { 13 | return new DevBuilderManifestV2( 14 | this.viteConfig, 15 | this.pluginOptions, 16 | this.viteDevServer, 17 | this.inputManifest 18 | ); 19 | } 20 | 21 | protected getHtmlFileNames(manifest: Manifest): string[] { 22 | return [ 23 | manifest.background?.page, 24 | manifest.browser_action?.default_popup, 25 | manifest.options_ui?.page, 26 | manifest.devtools_page, 27 | manifest.chrome_url_overrides?.newtab, 28 | manifest.chrome_url_overrides?.history, 29 | manifest.chrome_url_overrides?.bookmarks, 30 | ] 31 | .filter((fileName): fileName is string => typeof fileName === "string") 32 | .map((fileName) => fileName.split(/[\?\#]/)[0]); 33 | } 34 | 35 | protected getParseInputMethods(): (( 36 | result: ManifestParseResult 37 | ) => ManifestParseResult)[] { 38 | return []; 39 | } 40 | 41 | protected getParseOutputMethods(): (( 42 | result: ManifestParseResult 43 | ) => Promise)[] { 44 | return []; 45 | } 46 | 47 | protected async parseOutputContentScripts( 48 | result: ManifestParseResult, 49 | bundle: OutputBundle 50 | ): Promise { 51 | const webAccessibleResources = new Set( 52 | result.manifest.web_accessible_resources ?? [] 53 | ); 54 | 55 | result.manifest.content_scripts?.forEach((script) => { 56 | script.js?.forEach((scriptFileName, index) => { 57 | const parsedContentScript = this.parseOutputContentScript( 58 | scriptFileName, 59 | result, 60 | bundle 61 | ); 62 | 63 | script.js![index] = parsedContentScript.fileName; 64 | 65 | parsedContentScript.webAccessibleFiles.forEach( 66 | webAccessibleResources.add, 67 | webAccessibleResources 68 | ); 69 | }); 70 | 71 | script.css?.forEach((cssFileName, index) => { 72 | const parsedContentCss = this.parseOutputContentCss( 73 | cssFileName, 74 | bundle 75 | ); 76 | 77 | script.css![index] = parsedContentCss.cssFileName; 78 | }); 79 | }); 80 | 81 | if (webAccessibleResources.size > 0) { 82 | result.manifest.web_accessible_resources = Array.from( 83 | webAccessibleResources 84 | ); 85 | } 86 | 87 | return result; 88 | } 89 | 90 | protected async parseOutputAdditionalInputs( 91 | result: ManifestParseResult, 92 | bundle: OutputBundle 93 | ): Promise { 94 | if (!this.pluginOptions.additionalInputs) { 95 | return result; 96 | } 97 | 98 | for (const [type, inputs] of Object.entries( 99 | this.pluginOptions.additionalInputs 100 | )) { 101 | for (const input of inputs) { 102 | const additionalInput = getNormalizedAdditionalInput(input); 103 | 104 | const parsedFile = this.parseOutputAdditionalInput( 105 | type as keyof NonNullable< 106 | ViteWebExtensionOptions["additionalInputs"] 107 | >, 108 | additionalInput, 109 | result, 110 | bundle 111 | ); 112 | 113 | if (parsedFile.webAccessibleFiles.size) { 114 | result.manifest.web_accessible_resources = [ 115 | ...(result.manifest.web_accessible_resources ?? []), 116 | ...parsedFile.webAccessibleFiles, 117 | ]; 118 | } 119 | } 120 | } 121 | 122 | return result; 123 | } 124 | 125 | protected optimizeWebAccessibleResources( 126 | result: ParseResult 127 | ): ParseResult { 128 | if (!result.manifest.web_accessible_resources) { 129 | return result; 130 | } 131 | 132 | result.manifest.web_accessible_resources = 133 | result.manifest.web_accessible_resources.sort(); 134 | 135 | return result; 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /src/middleware/viteClientModifier.ts: -------------------------------------------------------------------------------- 1 | import getEtag from "etag"; 2 | import type { Connect } from "vite"; 3 | 4 | // Modifies the vite HMR client to support various web extension features including: 5 | // Exporting a function to add HMR style injection targets 6 | // Tweaks to support running in a service worker context 7 | const viteClientModifier: Connect.NextHandleFunction = (req, res, next) => { 8 | const _originalEnd = res.end; 9 | 10 | // @ts-ignore 11 | res.end = function end(chunk, ...otherArgs) { 12 | if (req.url === "/@vite/client" && typeof chunk === "string") { 13 | chunk = addCustomStyleFunctionality(chunk); 14 | chunk = addServiceWorkerSupport(chunk); 15 | 16 | res.setHeader("Etag", getEtag(chunk, { weak: true })); 17 | } 18 | 19 | // @ts-ignore 20 | return _originalEnd.call(this, chunk, ...otherArgs); 21 | }; 22 | 23 | next(); 24 | }; 25 | 26 | function addCustomStyleFunctionality(source: string): string { 27 | if ( 28 | !/const sheetsMap/.test(source) || 29 | !/document\.head\.appendChild\(style\)/.test(source) || 30 | !/document\.head\.removeChild\(style\)/.test(source) || 31 | (!/style\.textContent = content/.test(source) && 32 | !/style\.innerHTML = content/.test(source)) 33 | ) { 34 | console.error( 35 | "Web extension HMR style support disabled -- failed to update vite client" 36 | ); 37 | 38 | return source; 39 | } 40 | 41 | source = source.replace( 42 | "const sheetsMap", 43 | "const styleTargets = new Set(); const styleTargetsStyleMap = new Map(); const sheetsMap" 44 | ); 45 | source = source.replace("export {", "export { addStyleTarget, "); 46 | source = source.replace( 47 | "document.head.appendChild(style)", 48 | "styleTargets.size ? styleTargets.forEach(target => addStyleToTarget(style, target)) : document.head.appendChild(style)" 49 | ); 50 | source = source.replace( 51 | "document.head.removeChild(style)", 52 | "styleTargetsStyleMap.get(style) ? styleTargetsStyleMap.get(style).forEach(style => style.parentNode.removeChild(style)) : document.head.removeChild(style)" 53 | ); 54 | 55 | const styleProperty = /style\.textContent = content/.test(source) 56 | ? "style.textContent" 57 | : "style.innerHTML"; 58 | 59 | const lastStyleInnerHtml = source.lastIndexOf(`${styleProperty} = content`); 60 | 61 | source = 62 | source.slice(0, lastStyleInnerHtml) + 63 | source 64 | .slice(lastStyleInnerHtml) 65 | .replace( 66 | `${styleProperty} = content`, 67 | `${styleProperty} = content; styleTargetsStyleMap.get(style)?.forEach(style => ${styleProperty} = content)` 68 | ); 69 | 70 | source += ` 71 | function addStyleTarget(newStyleTarget) { 72 | for (const [, style] of sheetsMap.entries()) { 73 | addStyleToTarget(style, newStyleTarget, styleTargets.size !== 0); 74 | } 75 | 76 | styleTargets.add(newStyleTarget); 77 | } 78 | 79 | function addStyleToTarget(style, target, cloneStyle = true) { 80 | const addedStyle = cloneStyle ? style.cloneNode(true) : style; 81 | target.appendChild(addedStyle); 82 | 83 | styleTargetsStyleMap.set(style, [...(styleTargetsStyleMap.get(style) ?? []), addedStyle]); 84 | } 85 | `; 86 | 87 | return source; 88 | } 89 | 90 | function guardDocumentUsageWithDefault( 91 | source: string, 92 | documentUsage: string, 93 | defaultValue: string 94 | ): string { 95 | return source.replace( 96 | documentUsage, 97 | `('document' in globalThis ? ${documentUsage} : ${defaultValue})` 98 | ); 99 | } 100 | 101 | function addServiceWorkerSupport(source: string): string { 102 | // update location.reload usages 103 | source = source.replaceAll( 104 | /(window\.)?location.reload\(\)/g, 105 | "(location.reload?.() ?? (typeof chrome !== 'undefined' ? chrome.runtime?.reload?.() : ''))" 106 | ); 107 | 108 | // add document guards 109 | source = guardDocumentUsageWithDefault( 110 | source, 111 | "document.querySelectorAll(overlayId).length", 112 | "false" 113 | ); 114 | 115 | source = guardDocumentUsageWithDefault( 116 | source, 117 | "document.visibilityState", 118 | `"visible"` 119 | ); 120 | 121 | source = guardDocumentUsageWithDefault( 122 | source, 123 | `document.querySelectorAll('link')`, 124 | "[]" 125 | ); 126 | 127 | source = source.replace( 128 | "const enableOverlay =", 129 | `const enableOverlay = ('document' in globalThis) &&` 130 | ); 131 | 132 | return source; 133 | } 134 | 135 | export default viteClientModifier; 136 | -------------------------------------------------------------------------------- /src/utils/addHmrSupportToCsp.ts: -------------------------------------------------------------------------------- 1 | import parse from "content-security-policy-parser"; 2 | 3 | export const addHmrSupportToCsp = ( 4 | hmrServerOrigin: string, 5 | inlineScriptHashes: Set, 6 | contentSecurityPolicyStr?: string | undefined 7 | ): string => { 8 | const inlineScriptHashesArr = Array.from(inlineScriptHashes); 9 | const scriptSrcs = ["'self'", hmrServerOrigin].concat( 10 | inlineScriptHashesArr || [] 11 | ); 12 | 13 | const contentSecurityPolicy = parse(contentSecurityPolicyStr || ""); 14 | contentSecurityPolicy["script-src"] = scriptSrcs.concat( 15 | contentSecurityPolicy["script-src"] 16 | ); 17 | contentSecurityPolicy["object-src"] = ["'self'"].concat( 18 | contentSecurityPolicy["object-src"] 19 | ); 20 | 21 | return Object.keys(contentSecurityPolicy) 22 | .map((key) => { 23 | return ( 24 | `${key} ` + 25 | contentSecurityPolicy[key] 26 | .filter((c, idx) => contentSecurityPolicy[key].indexOf(c) === idx) // Dedupe 27 | .join(" ") 28 | ); 29 | }) 30 | .join("; "); 31 | }; 32 | -------------------------------------------------------------------------------- /src/utils/file.ts: -------------------------------------------------------------------------------- 1 | import path from "node:path"; 2 | import { normalizePath } from "vite"; 3 | 4 | export function getNormalizedFileName( 5 | fileName: string, 6 | includeExt = true 7 | ): string { 8 | let { dir, name, ext } = path.parse(normalizePath(path.normalize(fileName))); 9 | 10 | if (!dir) { 11 | return `${name}${includeExt ? ext : ""}`; 12 | } 13 | 14 | dir = dir.startsWith("/") ? dir.slice(1) : dir; 15 | 16 | return `${dir}/${name}${includeExt ? ext : ""}`; 17 | } 18 | 19 | export function getInputFileName(inputFileName: string, root: string): string { 20 | return `${root}/${getNormalizedFileName(inputFileName, true)}`; 21 | } 22 | 23 | export function getOutputFileName(inputFileName: string): string { 24 | return getNormalizedFileName(inputFileName, false); 25 | } 26 | -------------------------------------------------------------------------------- /src/utils/getAdditionalInputAsWebAccessibleResource.ts: -------------------------------------------------------------------------------- 1 | import { NormalizedAdditionalInput } from "../../types"; 2 | 3 | export default function getAdditionalInputAsWebAccessibleResource( 4 | input: NormalizedAdditionalInput 5 | ): { 6 | matches: string[] | undefined; 7 | extension_ids: string[] | undefined; 8 | use_dynamic_url?: boolean; 9 | } | null { 10 | if (!input.webAccessible) { 11 | return null; 12 | } 13 | 14 | return { 15 | matches: input.webAccessible.matches, 16 | extension_ids: input.webAccessible.extensionIds, 17 | use_dynamic_url: true, 18 | }; 19 | } 20 | -------------------------------------------------------------------------------- /src/utils/getNormalizedAdditionalInput.ts: -------------------------------------------------------------------------------- 1 | import { AdditionalInput, NormalizedAdditionalInput } from "../../types"; 2 | 3 | export default function getNormalizedAdditionalInput( 4 | input: AdditionalInput 5 | ): NormalizedAdditionalInput { 6 | const webAccessibleDefaults = { 7 | matches: [""], 8 | excludeEntryFile: false, 9 | }; 10 | 11 | if (typeof input === "string") { 12 | return { 13 | fileName: input, 14 | webAccessible: webAccessibleDefaults, 15 | }; 16 | } 17 | 18 | if (typeof input.webAccessible === "boolean") { 19 | return { 20 | ...input, 21 | webAccessible: input.webAccessible ? webAccessibleDefaults : null, 22 | }; 23 | } 24 | 25 | return { 26 | ...input, 27 | webAccessible: { 28 | excludeEntryFile: webAccessibleDefaults.excludeEntryFile, 29 | ...input.webAccessible, 30 | }, 31 | }; 32 | } 33 | -------------------------------------------------------------------------------- /src/utils/loader.ts: -------------------------------------------------------------------------------- 1 | import type { OutputChunk } from "rollup"; 2 | import { getOutputFileName } from "./file"; 3 | 4 | export function getScriptHtmlLoaderFile(name: string, scriptSrcs: string[]) { 5 | const scriptsHtml = scriptSrcs 6 | .map((scriptSrc) => { 7 | return ``; 8 | }) 9 | .join(""); 10 | 11 | return { 12 | fileName: `${name}.html`, 13 | source: `${scriptsHtml}`, 14 | }; 15 | } 16 | 17 | export function getScriptLoaderFile( 18 | scriptFileName: string, 19 | inputFileNames: string[] 20 | ): { 21 | fileName: string; 22 | source: string; 23 | } { 24 | const outputFile = getOutputFileName(scriptFileName); 25 | 26 | const importStatements = inputFileNames 27 | .filter((fileName) => Boolean(fileName)) 28 | .map((fileName) => { 29 | return fileName.startsWith("http") 30 | ? `"${fileName}"` 31 | : `chrome.runtime.getURL("${fileName}")`; 32 | }) 33 | .map((importPath) => `await import(${importPath})`) 34 | .join(";"); 35 | 36 | return { 37 | fileName: `${outputFile}.js`, 38 | source: `(async()=>{${importStatements}})();`, 39 | }; 40 | } 41 | 42 | export function getServiceWorkerLoaderFile(inputFileNames: string[]) { 43 | const importStatements = inputFileNames 44 | .filter((fileName) => Boolean(fileName)) 45 | .map((fileName) => { 46 | return fileName.startsWith("http") ? fileName : `/${fileName}`; 47 | }) 48 | .map((importPath) => `import "${importPath}";`) 49 | .join("\n"); 50 | 51 | return { 52 | fileName: `serviceWorker.js`, 53 | source: importStatements, 54 | }; 55 | } 56 | 57 | export function getScriptLoaderForOutputChunk( 58 | contentScriptFileName: string, 59 | chunk: OutputChunk 60 | ): { fileName: string; source: string } | null { 61 | if (!chunk.imports.length && !chunk.dynamicImports.length) { 62 | return null; 63 | } 64 | 65 | return getScriptLoaderFile(contentScriptFileName, [chunk.fileName]); 66 | } 67 | -------------------------------------------------------------------------------- /src/utils/rollup.ts: -------------------------------------------------------------------------------- 1 | import type { 2 | InputOptions, 3 | OutputAsset, 4 | OutputBundle, 5 | OutputChunk, 6 | } from "rollup"; 7 | import { ViteWebExtensionOptions } from "../../types"; 8 | import { getNormalizedFileName } from "./file"; 9 | 10 | export function addInputScriptsToOptionsInput( 11 | inputScripts: [string, string][], 12 | optionsInput: InputOptions["input"] 13 | ): { [entryAlias: string]: string } { 14 | const optionsInputObject = getOptionsInputAsObject(optionsInput); 15 | 16 | inputScripts.forEach(([output, input]) => { 17 | input = input.trim(); 18 | 19 | if ( 20 | optionsInputObject[output] && 21 | optionsInputObject[output].trim() !== input 22 | ) { 23 | throw new Error( 24 | `Inputs (${optionsInputObject[output]}) and (${input}) share an output identifier of (${output}). Rename one of the inputs to prevent output resolution issues.` 25 | ); 26 | } 27 | 28 | optionsInputObject[output] = input; 29 | }); 30 | 31 | return optionsInputObject; 32 | } 33 | 34 | function getOptionsInputAsObject(input: InputOptions["input"]): { 35 | [entryAlias: string]: string; 36 | } { 37 | if (typeof input === "string") { 38 | if (!input.trim()) { 39 | return {}; 40 | } 41 | 42 | return { 43 | [input]: input, 44 | }; 45 | } else if (input instanceof Array) { 46 | if (!input.length) { 47 | return {}; 48 | } 49 | 50 | const inputObject: { [entryAlias: string]: string } = {}; 51 | 52 | input.forEach((input) => (inputObject[input] = input)); 53 | 54 | return inputObject; 55 | } 56 | 57 | return input ?? {}; 58 | } 59 | 60 | export function getChunkInfoFromBundle( 61 | bundle: OutputBundle, 62 | chunkId: string 63 | ): OutputChunk | undefined { 64 | const normalizedId = getNormalizedFileName(chunkId); 65 | 66 | return Object.values(bundle).find((chunk) => { 67 | if (chunk.type === "asset") { 68 | return false; 69 | } 70 | 71 | return ( 72 | chunk.facadeModuleId?.endsWith(normalizedId) || 73 | chunk.fileName.endsWith(normalizedId) 74 | ); 75 | }) as OutputChunk | undefined; 76 | } 77 | 78 | function findMatchingOutputAsset( 79 | bundle: OutputBundle, 80 | normalizedInputId: string 81 | ): OutputAsset | undefined { 82 | return Object.values(bundle).find((chunk) => { 83 | if (chunk.type === "chunk") { 84 | return; 85 | } 86 | 87 | if (chunk.name) { 88 | return normalizedInputId.endsWith(chunk.name); 89 | } 90 | 91 | return chunk.fileName.endsWith(normalizedInputId); 92 | }) as OutputAsset | undefined; 93 | } 94 | 95 | export function getOutputInfoFromBundle( 96 | type: keyof NonNullable, 97 | bundle: OutputBundle, 98 | inputId: string 99 | ): OutputAsset | OutputChunk | undefined { 100 | switch (type) { 101 | case "styles": 102 | return getCssAssetInfoFromBundle(bundle, inputId); 103 | case "scripts": 104 | return getChunkInfoFromBundle(bundle, inputId); 105 | case "html": 106 | return findMatchingOutputAsset(bundle, inputId); 107 | default: 108 | throw new Error(`Invalid additionalInput type of ${type}`); 109 | } 110 | } 111 | 112 | export function getCssAssetInfoFromBundle( 113 | bundle: OutputBundle, 114 | assetFileName: string 115 | ): OutputAsset | undefined { 116 | const normalizedInputId = getNormalizedFileName(assetFileName, false); 117 | 118 | return findMatchingOutputAsset(bundle, `${normalizedInputId}.css`); 119 | } 120 | -------------------------------------------------------------------------------- /src/utils/virtualModule.ts: -------------------------------------------------------------------------------- 1 | const virtualModules = new Map(); 2 | 3 | export function setVirtualModule(id: string, source: string) { 4 | virtualModules.set(id, source); 5 | } 6 | 7 | export function getVirtualModule(id: string): string | null { 8 | return virtualModules.get(id) ?? null; 9 | } 10 | -------------------------------------------------------------------------------- /src/utils/vite.ts: -------------------------------------------------------------------------------- 1 | import MagicString from "magic-string"; 2 | import type { Manifest, ManifestChunk, ResolvedConfig, UserConfig } from "vite"; 3 | import { getNormalizedFileName } from "./file"; 4 | 5 | // Update vite user config with settings necessary for the plugin to work 6 | export function updateConfigForExtensionSupport( 7 | config: UserConfig, 8 | manifest: chrome.runtime.Manifest 9 | ): UserConfig { 10 | config.build ??= {}; 11 | 12 | if (!config.build.target) { 13 | switch (manifest.manifest_version) { 14 | case 2: 15 | config.build.target = ["chrome64", "firefox89"]; // minimum browsers with import.meta.url and content script dynamic import 16 | break; 17 | case 3: 18 | config.build.target = ["chrome91"]; 19 | break; 20 | } 21 | } 22 | 23 | config.build.modulePreload ??= false; 24 | 25 | config.build.rollupOptions ??= {}; 26 | config.build.rollupOptions.input ??= {}; 27 | 28 | config.optimizeDeps ??= {}; 29 | config.optimizeDeps.exclude = [ 30 | ...(config.optimizeDeps.exclude ?? []), 31 | "/@vite/client", 32 | ]; 33 | 34 | config.server ??= {}; 35 | 36 | if (config.server.hmr === true || !config.server.hmr) { 37 | config.server.hmr = {}; 38 | } 39 | 40 | config.server.hmr.protocol = "ws"; // required for content script hmr to work on https 41 | config.server.hmr.host = "localhost"; 42 | 43 | return config; 44 | } 45 | 46 | // Vite asset helper rewrites usages of import.meta.url to self.location for broader 47 | // browser support, but content scripts need to reference assets via import.meta.url 48 | // This transform rewrites self.location back to import.meta.url 49 | export function transformSelfLocationAssets( 50 | code: string, 51 | resolvedViteConfig: ResolvedConfig 52 | ) { 53 | if (code.includes("new URL") && code.includes(`self.location`)) { 54 | let updatedCode: MagicString | null = null; 55 | const selfLocationUrlPattern = 56 | /\bnew\s+URL\s*\(\s*('[^']+'|"[^"]+"|`[^`]+`)\s*,\s*self\.location\s*\)/g; 57 | 58 | let match: RegExpExecArray | null; 59 | while ((match = selfLocationUrlPattern.exec(code))) { 60 | const { 0: exp, index } = match; 61 | 62 | if (!updatedCode) updatedCode = new MagicString(code); 63 | 64 | updatedCode.overwrite( 65 | index, 66 | index + exp.length, 67 | exp.replace("self.location", "import.meta.url") 68 | ); 69 | } 70 | 71 | if (updatedCode) { 72 | return { 73 | code: updatedCode.toString(), 74 | map: resolvedViteConfig.build.sourcemap 75 | ? updatedCode.generateMap({ hires: true }) 76 | : null, 77 | }; 78 | } 79 | } 80 | 81 | return null; 82 | } 83 | 84 | export function findChunkInManifestByFileName( 85 | manifest: Manifest, 86 | fileName: string 87 | ): ManifestChunk | undefined { 88 | return manifest[getNormalizedFileName(fileName)]; 89 | } 90 | -------------------------------------------------------------------------------- /test/manifest/__snapshots__/additionalInputsHtml.v2.test.ts.snap: -------------------------------------------------------------------------------- 1 | // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html 2 | 3 | exports[`additionalInputsHtml - Manifest V2 1`] = ` 4 | [ 5 | { 6 | "fileName": "assets/html.css", 7 | "name": "html.css", 8 | "source": "body { 9 | color: red; 10 | } 11 | ", 12 | "type": "asset", 13 | }, 14 | { 15 | "code": "function log(message) { 16 | console.log(message); 17 | } 18 | log("webAccessible"); 19 | ", 20 | "dynamicImports": [], 21 | "exports": [], 22 | "facadeModuleId": "vite-plugin-web-extension/test/manifest/resources/additionalInputsHtml/html.html", 23 | "fileName": "assets/test/manifest/resources/additionalInputsHtml/html.js", 24 | "implicitlyLoadedBefore": [], 25 | "importedBindings": {}, 26 | "imports": [], 27 | "isDynamicEntry": false, 28 | "isEntry": true, 29 | "isImplicitEntry": false, 30 | "map": null, 31 | "modules": { 32 | "vite-plugin-web-extension/test/manifest/resources/additionalInputsHtml/html.html": { 33 | "code": "", 34 | "originalLength": 290, 35 | "removedExports": [], 36 | "renderedExports": [], 37 | "renderedLength": 0, 38 | }, 39 | "vite-plugin-web-extension/test/manifest/resources/additionalInputsHtml/script.js": { 40 | "code": "log("webAccessible");", 41 | "originalLength": 58, 42 | "removedExports": [], 43 | "renderedExports": [], 44 | "renderedLength": 21, 45 | }, 46 | "vite-plugin-web-extension/test/manifest/resources/additionalInputsHtml/style.css": { 47 | "code": "", 48 | "originalLength": 23, 49 | "removedExports": [], 50 | "renderedExports": [], 51 | "renderedLength": 0, 52 | }, 53 | "vite-plugin-web-extension/test/manifest/resources/shared/log.js": { 54 | "code": "function log(message) { 55 | console.log(message); 56 | }", 57 | "originalLength": 65, 58 | "removedExports": [], 59 | "renderedExports": [ 60 | "default", 61 | ], 62 | "renderedLength": 49, 63 | }, 64 | }, 65 | "name": "test/manifest/resources/additionalInputsHtml/html", 66 | "referencedFiles": [], 67 | "type": "chunk", 68 | "viteMetadata": { 69 | "importedAssets": Set {}, 70 | "importedCss": Set { 71 | "assets/html.css", 72 | }, 73 | }, 74 | }, 75 | { 76 | "fileName": "manifest.json", 77 | "name": undefined, 78 | "source": "{ 79 | "version": "1.0.0", 80 | "name": "Manifest Name", 81 | "manifest_version": 2, 82 | "web_accessible_resources": [ 83 | "test/manifest/resources/additionalInputsHtml/html.html" 84 | ] 85 | }", 86 | "type": "asset", 87 | }, 88 | { 89 | "fileName": "test/manifest/resources/additionalInputsHtml/html.html", 90 | "name": undefined, 91 | "source": " 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | ", 102 | "type": "asset", 103 | }, 104 | ] 105 | `; 106 | -------------------------------------------------------------------------------- /test/manifest/__snapshots__/additionalInputsHtml.v3.test.ts.snap: -------------------------------------------------------------------------------- 1 | // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html 2 | 3 | exports[`additionalInputsHtml - Manifest V3 1`] = ` 4 | [ 5 | { 6 | "fileName": "assets/html.css", 7 | "name": "html.css", 8 | "source": "body { 9 | color: red; 10 | } 11 | ", 12 | "type": "asset", 13 | }, 14 | { 15 | "code": "function log(message) { 16 | console.log(message); 17 | } 18 | log("webAccessible"); 19 | ", 20 | "dynamicImports": [], 21 | "exports": [], 22 | "facadeModuleId": "vite-plugin-web-extension/test/manifest/resources/additionalInputsHtml/html.html", 23 | "fileName": "assets/test/manifest/resources/additionalInputsHtml/html.js", 24 | "implicitlyLoadedBefore": [], 25 | "importedBindings": {}, 26 | "imports": [], 27 | "isDynamicEntry": false, 28 | "isEntry": true, 29 | "isImplicitEntry": false, 30 | "map": null, 31 | "modules": { 32 | "vite-plugin-web-extension/test/manifest/resources/additionalInputsHtml/html.html": { 33 | "code": "", 34 | "originalLength": 290, 35 | "removedExports": [], 36 | "renderedExports": [], 37 | "renderedLength": 0, 38 | }, 39 | "vite-plugin-web-extension/test/manifest/resources/additionalInputsHtml/script.js": { 40 | "code": "log("webAccessible");", 41 | "originalLength": 58, 42 | "removedExports": [], 43 | "renderedExports": [], 44 | "renderedLength": 21, 45 | }, 46 | "vite-plugin-web-extension/test/manifest/resources/additionalInputsHtml/style.css": { 47 | "code": "", 48 | "originalLength": 23, 49 | "removedExports": [], 50 | "renderedExports": [], 51 | "renderedLength": 0, 52 | }, 53 | "vite-plugin-web-extension/test/manifest/resources/shared/log.js": { 54 | "code": "function log(message) { 55 | console.log(message); 56 | }", 57 | "originalLength": 65, 58 | "removedExports": [], 59 | "renderedExports": [ 60 | "default", 61 | ], 62 | "renderedLength": 49, 63 | }, 64 | }, 65 | "name": "test/manifest/resources/additionalInputsHtml/html", 66 | "referencedFiles": [], 67 | "type": "chunk", 68 | "viteMetadata": { 69 | "importedAssets": Set {}, 70 | "importedCss": Set { 71 | "assets/html.css", 72 | }, 73 | }, 74 | }, 75 | { 76 | "fileName": "manifest.json", 77 | "name": undefined, 78 | "source": "{ 79 | "version": "1.0.0", 80 | "name": "Manifest Name", 81 | "manifest_version": 3, 82 | "web_accessible_resources": [ 83 | { 84 | "resources": [ 85 | "test/manifest/resources/additionalInputsHtml/html.html" 86 | ], 87 | "matches": [ 88 | "" 89 | ] 90 | } 91 | ] 92 | }", 93 | "type": "asset", 94 | }, 95 | { 96 | "fileName": "test/manifest/resources/additionalInputsHtml/html.html", 97 | "name": undefined, 98 | "source": " 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | ", 109 | "type": "asset", 110 | }, 111 | ] 112 | `; 113 | -------------------------------------------------------------------------------- /test/manifest/__snapshots__/additionalInputsScriptsChunkedImport.v2.test.ts.snap: -------------------------------------------------------------------------------- 1 | // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html 2 | 3 | exports[`additionalInputsScriptsChunkedImport - Manifest V2 1`] = ` 4 | [ 5 | { 6 | "code": "function log(message) { 7 | console.log(message); 8 | } 9 | export { 10 | log as l 11 | }; 12 | ", 13 | "dynamicImports": [], 14 | "exports": [ 15 | "l", 16 | ], 17 | "facadeModuleId": null, 18 | "fileName": "assets/log.js", 19 | "implicitlyLoadedBefore": [], 20 | "importedBindings": {}, 21 | "imports": [], 22 | "isDynamicEntry": false, 23 | "isEntry": false, 24 | "isImplicitEntry": false, 25 | "map": null, 26 | "modules": { 27 | "vite-plugin-web-extension/test/manifest/resources/shared/log.js": { 28 | "code": "function log(message) { 29 | console.log(message); 30 | }", 31 | "originalLength": 65, 32 | "removedExports": [], 33 | "renderedExports": [ 34 | "default", 35 | ], 36 | "renderedLength": 49, 37 | }, 38 | }, 39 | "name": "log", 40 | "referencedFiles": [], 41 | "type": "chunk", 42 | "viteMetadata": { 43 | "importedAssets": Set {}, 44 | "importedCss": Set {}, 45 | }, 46 | }, 47 | { 48 | "code": "import { l as log } from "../../../../log.js"; 49 | log("script1"); 50 | ", 51 | "dynamicImports": [], 52 | "exports": [], 53 | "facadeModuleId": "vite-plugin-web-extension/test/manifest/resources/additionalInputsScriptsChunkedImport/script1.js", 54 | "fileName": "assets/test/manifest/resources/additionalInputsScriptsChunkedImport/script1.js", 55 | "implicitlyLoadedBefore": [], 56 | "importedBindings": { 57 | "assets/log.js": [ 58 | "l", 59 | ], 60 | }, 61 | "imports": [ 62 | "assets/log.js", 63 | ], 64 | "isDynamicEntry": false, 65 | "isEntry": true, 66 | "isImplicitEntry": false, 67 | "map": null, 68 | "modules": { 69 | "vite-plugin-web-extension/test/manifest/resources/additionalInputsScriptsChunkedImport/script1.js": { 70 | "code": "log("script1");", 71 | "originalLength": 50, 72 | "removedExports": [], 73 | "renderedExports": [], 74 | "renderedLength": 15, 75 | }, 76 | }, 77 | "name": "test/manifest/resources/additionalInputsScriptsChunkedImport/script1", 78 | "referencedFiles": [], 79 | "type": "chunk", 80 | "viteMetadata": { 81 | "importedAssets": Set {}, 82 | "importedCss": Set {}, 83 | }, 84 | }, 85 | { 86 | "code": "import { l as log } from "../../../../log.js"; 87 | log("script2"); 88 | ", 89 | "dynamicImports": [], 90 | "exports": [], 91 | "facadeModuleId": "vite-plugin-web-extension/test/manifest/resources/additionalInputsScriptsChunkedImport/script2.js", 92 | "fileName": "assets/test/manifest/resources/additionalInputsScriptsChunkedImport/script2.js", 93 | "implicitlyLoadedBefore": [], 94 | "importedBindings": { 95 | "assets/log.js": [ 96 | "l", 97 | ], 98 | }, 99 | "imports": [ 100 | "assets/log.js", 101 | ], 102 | "isDynamicEntry": false, 103 | "isEntry": true, 104 | "isImplicitEntry": false, 105 | "map": null, 106 | "modules": { 107 | "vite-plugin-web-extension/test/manifest/resources/additionalInputsScriptsChunkedImport/script2.js": { 108 | "code": "log("script2");", 109 | "originalLength": 50, 110 | "removedExports": [], 111 | "renderedExports": [], 112 | "renderedLength": 15, 113 | }, 114 | }, 115 | "name": "test/manifest/resources/additionalInputsScriptsChunkedImport/script2", 116 | "referencedFiles": [], 117 | "type": "chunk", 118 | "viteMetadata": { 119 | "importedAssets": Set {}, 120 | "importedCss": Set {}, 121 | }, 122 | }, 123 | { 124 | "fileName": "manifest.json", 125 | "name": undefined, 126 | "source": "{ 127 | "version": "1.0.0", 128 | "name": "Manifest Name", 129 | "manifest_version": 2, 130 | "web_accessible_resources": [ 131 | "assets/log.js", 132 | "assets/test/manifest/resources/additionalInputsScriptsChunkedImport/script1.js", 133 | "assets/test/manifest/resources/additionalInputsScriptsChunkedImport/script2.js", 134 | "test/manifest/resources/additionalInputsScriptsChunkedImport/script1.js", 135 | "test/manifest/resources/additionalInputsScriptsChunkedImport/script2.js" 136 | ] 137 | }", 138 | "type": "asset", 139 | }, 140 | { 141 | "fileName": "test/manifest/resources/additionalInputsScriptsChunkedImport/script1.js", 142 | "name": undefined, 143 | "source": "(async()=>{await import(chrome.runtime.getURL("assets/test/manifest/resources/additionalInputsScriptsChunkedImport/script1.js"))})();", 144 | "type": "asset", 145 | }, 146 | { 147 | "fileName": "test/manifest/resources/additionalInputsScriptsChunkedImport/script2.js", 148 | "name": undefined, 149 | "source": "(async()=>{await import(chrome.runtime.getURL("assets/test/manifest/resources/additionalInputsScriptsChunkedImport/script2.js"))})();", 150 | "type": "asset", 151 | }, 152 | ] 153 | `; 154 | -------------------------------------------------------------------------------- /test/manifest/__snapshots__/additionalInputsScriptsNoImport.v2.test.ts.snap: -------------------------------------------------------------------------------- 1 | // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html 2 | 3 | exports[`additionalInputsScriptsNoImport - Manifest V2 1`] = ` 4 | [ 5 | { 6 | "fileName": "manifest.json", 7 | "name": undefined, 8 | "source": "{ 9 | "version": "1.0.0", 10 | "name": "Manifest Name", 11 | "manifest_version": 2, 12 | "web_accessible_resources": [ 13 | "test/manifest/resources/additionalInputsScriptsNoImport/script1.js", 14 | "test/manifest/resources/additionalInputsScriptsNoImport/script2.js" 15 | ] 16 | }", 17 | "type": "asset", 18 | }, 19 | { 20 | "fileName": "test/manifest/resources/additionalInputsScriptsNoImport/script1.js", 21 | "name": undefined, 22 | "source": "console.log("script1"); 23 | ", 24 | "type": "asset", 25 | }, 26 | { 27 | "fileName": "test/manifest/resources/additionalInputsScriptsNoImport/script2.js", 28 | "name": undefined, 29 | "source": "console.log("script2"); 30 | ", 31 | "type": "asset", 32 | }, 33 | ] 34 | `; 35 | -------------------------------------------------------------------------------- /test/manifest/__snapshots__/additionalInputsScriptsNoImport.v3.test.ts.snap: -------------------------------------------------------------------------------- 1 | // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html 2 | 3 | exports[`additionalInputsScriptsNoImport - Manifest V3 1`] = ` 4 | [ 5 | { 6 | "fileName": "manifest.json", 7 | "name": undefined, 8 | "source": "{ 9 | "version": "1.0.0", 10 | "name": "Manifest Name", 11 | "manifest_version": 3, 12 | "web_accessible_resources": [ 13 | { 14 | "resources": [ 15 | "test/manifest/resources/additionalInputsScriptsNoImport/script1.js", 16 | "test/manifest/resources/additionalInputsScriptsNoImport/script2.js" 17 | ], 18 | "matches": [ 19 | "" 20 | ] 21 | } 22 | ] 23 | }", 24 | "type": "asset", 25 | }, 26 | { 27 | "fileName": "test/manifest/resources/additionalInputsScriptsNoImport/script1.js", 28 | "name": undefined, 29 | "source": "console.log("script1"); 30 | ", 31 | "type": "asset", 32 | }, 33 | { 34 | "fileName": "test/manifest/resources/additionalInputsScriptsNoImport/script2.js", 35 | "name": undefined, 36 | "source": "console.log("script2"); 37 | ", 38 | "type": "asset", 39 | }, 40 | ] 41 | `; 42 | -------------------------------------------------------------------------------- /test/manifest/__snapshots__/additionalInputsScriptsTypes.v2.test.ts.snap: -------------------------------------------------------------------------------- 1 | // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html 2 | 3 | exports[`additionalInputsScriptsTypes - Manifest V2 1`] = ` 4 | [ 5 | { 6 | "fileName": "manifest.json", 7 | "name": undefined, 8 | "source": "{ 9 | "version": "1.0.0", 10 | "name": "Manifest Name", 11 | "manifest_version": 2, 12 | "web_accessible_resources": [ 13 | "test/manifest/resources/additionalInputsScriptsTypes/script1.js", 14 | "test/manifest/resources/additionalInputsScriptsTypes/script2.js" 15 | ] 16 | }", 17 | "type": "asset", 18 | }, 19 | { 20 | "fileName": "test/manifest/resources/additionalInputsScriptsTypes/script1.js", 21 | "name": undefined, 22 | "source": "console.log("script1"); 23 | ", 24 | "type": "asset", 25 | }, 26 | { 27 | "fileName": "test/manifest/resources/additionalInputsScriptsTypes/script2.js", 28 | "name": undefined, 29 | "source": "console.log("script2"); 30 | ", 31 | "type": "asset", 32 | }, 33 | ] 34 | `; 35 | -------------------------------------------------------------------------------- /test/manifest/__snapshots__/additionalInputsScriptsTypes.v3.test.ts.snap: -------------------------------------------------------------------------------- 1 | // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html 2 | 3 | exports[`additionalInputsScriptsTypes - Manifest V3 1`] = ` 4 | [ 5 | { 6 | "fileName": "manifest.json", 7 | "name": undefined, 8 | "source": "{ 9 | "version": "1.0.0", 10 | "name": "Manifest Name", 11 | "manifest_version": 3, 12 | "web_accessible_resources": [ 13 | { 14 | "resources": [ 15 | "test/manifest/resources/additionalInputsScriptsTypes/script1.js", 16 | "test/manifest/resources/additionalInputsScriptsTypes/script2.js" 17 | ], 18 | "matches": [ 19 | "" 20 | ] 21 | } 22 | ] 23 | }", 24 | "type": "asset", 25 | }, 26 | { 27 | "fileName": "test/manifest/resources/additionalInputsScriptsTypes/script1.js", 28 | "name": undefined, 29 | "source": "console.log("script1"); 30 | ", 31 | "type": "asset", 32 | }, 33 | { 34 | "fileName": "test/manifest/resources/additionalInputsScriptsTypes/script2.js", 35 | "name": undefined, 36 | "source": "console.log("script2"); 37 | ", 38 | "type": "asset", 39 | }, 40 | ] 41 | `; 42 | -------------------------------------------------------------------------------- /test/manifest/__snapshots__/additionalInputsScriptsUnchunkedImport.v2.test.ts.snap: -------------------------------------------------------------------------------- 1 | // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html 2 | 3 | exports[`additionalInputsScriptsUnchunkedImport - Manifest V2 1`] = ` 4 | [ 5 | { 6 | "fileName": "manifest.json", 7 | "name": undefined, 8 | "source": "{ 9 | "version": "1.0.0", 10 | "name": "Manifest Name", 11 | "manifest_version": 2, 12 | "web_accessible_resources": [ 13 | "test/manifest/resources/additionalInputsScriptsUnchunkedImport/script1.js", 14 | "test/manifest/resources/additionalInputsScriptsUnchunkedImport/script2.js" 15 | ] 16 | }", 17 | "type": "asset", 18 | }, 19 | { 20 | "fileName": "test/manifest/resources/additionalInputsScriptsUnchunkedImport/script1.js", 21 | "name": undefined, 22 | "source": "function log(message) { 23 | console.log(message); 24 | } 25 | log("script1"); 26 | ", 27 | "type": "asset", 28 | }, 29 | { 30 | "fileName": "test/manifest/resources/additionalInputsScriptsUnchunkedImport/script2.js", 31 | "name": undefined, 32 | "source": "console.log("script2"); 33 | ", 34 | "type": "asset", 35 | }, 36 | ] 37 | `; 38 | -------------------------------------------------------------------------------- /test/manifest/__snapshots__/additionalInputsScriptsUnchunkedImport.v3.test.ts.snap: -------------------------------------------------------------------------------- 1 | // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html 2 | 3 | exports[`additionalInputsScriptsUnchunkedImport - Manifest V3 1`] = ` 4 | [ 5 | { 6 | "fileName": "manifest.json", 7 | "name": undefined, 8 | "source": "{ 9 | "version": "1.0.0", 10 | "name": "Manifest Name", 11 | "manifest_version": 3, 12 | "web_accessible_resources": [ 13 | { 14 | "resources": [ 15 | "test/manifest/resources/additionalInputsScriptsUnchunkedImport/script1.js", 16 | "test/manifest/resources/additionalInputsScriptsUnchunkedImport/script2.js" 17 | ], 18 | "matches": [ 19 | "" 20 | ] 21 | } 22 | ] 23 | }", 24 | "type": "asset", 25 | }, 26 | { 27 | "fileName": "test/manifest/resources/additionalInputsScriptsUnchunkedImport/script1.js", 28 | "name": undefined, 29 | "source": "function log(message) { 30 | console.log(message); 31 | } 32 | log("script1"); 33 | ", 34 | "type": "asset", 35 | }, 36 | { 37 | "fileName": "test/manifest/resources/additionalInputsScriptsUnchunkedImport/script2.js", 38 | "name": undefined, 39 | "source": "console.log("script2"); 40 | ", 41 | "type": "asset", 42 | }, 43 | ] 44 | `; 45 | -------------------------------------------------------------------------------- /test/manifest/__snapshots__/additionalInputsStylesTypes.v2.test.ts.snap: -------------------------------------------------------------------------------- 1 | // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html 2 | 3 | exports[`additionalInputsStylesTypes - Manifest V2 1`] = ` 4 | [ 5 | { 6 | "fileName": "manifest.json", 7 | "name": undefined, 8 | "source": "{ 9 | "version": "1.0.0", 10 | "name": "Manifest Name", 11 | "manifest_version": 2, 12 | "web_accessible_resources": [ 13 | "test/manifest/resources/additionalInputsStylesTypes/style1.css", 14 | "test/manifest/resources/additionalInputsStylesTypes/style2.css" 15 | ] 16 | }", 17 | "type": "asset", 18 | }, 19 | { 20 | "fileName": "test/manifest/resources/additionalInputsStylesTypes/style1.css", 21 | "name": undefined, 22 | "source": "body { 23 | color: red; 24 | } 25 | ", 26 | "type": "asset", 27 | }, 28 | { 29 | "fileName": "test/manifest/resources/additionalInputsStylesTypes/style2.css", 30 | "name": undefined, 31 | "source": "body { 32 | color: green; 33 | }", 34 | "type": "asset", 35 | }, 36 | ] 37 | `; 38 | -------------------------------------------------------------------------------- /test/manifest/__snapshots__/additionalInputsStylesTypes.v3.test.ts.snap: -------------------------------------------------------------------------------- 1 | // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html 2 | 3 | exports[`additionalInputsStylesTypes - Manifest V3 1`] = ` 4 | [ 5 | { 6 | "fileName": "manifest.json", 7 | "name": undefined, 8 | "source": "{ 9 | "version": "1.0.0", 10 | "name": "Manifest Name", 11 | "manifest_version": 3, 12 | "web_accessible_resources": [ 13 | { 14 | "resources": [ 15 | "test/manifest/resources/additionalInputsStylesTypes/style1.css", 16 | "test/manifest/resources/additionalInputsStylesTypes/style2.css" 17 | ], 18 | "matches": [ 19 | "" 20 | ] 21 | } 22 | ] 23 | }", 24 | "type": "asset", 25 | }, 26 | { 27 | "fileName": "test/manifest/resources/additionalInputsStylesTypes/style1.css", 28 | "name": undefined, 29 | "source": "body { 30 | color: red; 31 | } 32 | ", 33 | "type": "asset", 34 | }, 35 | { 36 | "fileName": "test/manifest/resources/additionalInputsStylesTypes/style2.css", 37 | "name": undefined, 38 | "source": "body { 39 | color: green; 40 | }", 41 | "type": "asset", 42 | }, 43 | ] 44 | `; 45 | -------------------------------------------------------------------------------- /test/manifest/__snapshots__/backgroundHtml.v2.test.ts.snap: -------------------------------------------------------------------------------- 1 | // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html 2 | 3 | exports[`backgroundHtml - Manifest V2 1`] = ` 4 | [ 5 | { 6 | "code": "function log(message) { 7 | console.log(message); 8 | } 9 | log("background"); 10 | ", 11 | "dynamicImports": [], 12 | "exports": [], 13 | "facadeModuleId": "vite-plugin-web-extension/test/manifest/resources/backgroundHtml/background.html", 14 | "fileName": "assets/test/manifest/resources/backgroundHtml/background.js", 15 | "implicitlyLoadedBefore": [], 16 | "importedBindings": {}, 17 | "imports": [], 18 | "isDynamicEntry": false, 19 | "isEntry": true, 20 | "isImplicitEntry": false, 21 | "map": null, 22 | "modules": { 23 | "vite-plugin-web-extension/test/manifest/resources/backgroundHtml/background.html": { 24 | "code": "", 25 | "originalLength": 229, 26 | "removedExports": [], 27 | "renderedExports": [], 28 | "renderedLength": 0, 29 | }, 30 | "vite-plugin-web-extension/test/manifest/resources/backgroundHtml/background.js": { 31 | "code": "log("background");", 32 | "originalLength": 55, 33 | "removedExports": [], 34 | "renderedExports": [], 35 | "renderedLength": 18, 36 | }, 37 | "vite-plugin-web-extension/test/manifest/resources/shared/log.js": { 38 | "code": "function log(message) { 39 | console.log(message); 40 | }", 41 | "originalLength": 65, 42 | "removedExports": [], 43 | "renderedExports": [ 44 | "default", 45 | ], 46 | "renderedLength": 49, 47 | }, 48 | }, 49 | "name": "test/manifest/resources/backgroundHtml/background", 50 | "referencedFiles": [], 51 | "type": "chunk", 52 | "viteMetadata": { 53 | "importedAssets": Set {}, 54 | "importedCss": Set {}, 55 | }, 56 | }, 57 | { 58 | "fileName": "manifest.json", 59 | "name": undefined, 60 | "source": "{ 61 | "version": "1.0.0", 62 | "name": "Manifest Name", 63 | "manifest_version": 2, 64 | "background": { 65 | "page": "test/manifest/resources/backgroundHtml/background.html", 66 | "persistent": false 67 | } 68 | }", 69 | "type": "asset", 70 | }, 71 | { 72 | "fileName": "test/manifest/resources/backgroundHtml/background.html", 73 | "name": undefined, 74 | "source": " 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | ", 84 | "type": "asset", 85 | }, 86 | ] 87 | `; 88 | -------------------------------------------------------------------------------- /test/manifest/__snapshots__/backgroundScript.v2.test.ts.snap: -------------------------------------------------------------------------------- 1 | // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html 2 | 3 | exports[`backgroundScript - Manifest V2 1`] = ` 4 | [ 5 | { 6 | "code": "function log(message) { 7 | console.log(message); 8 | } 9 | log("background"); 10 | ", 11 | "dynamicImports": [], 12 | "exports": [], 13 | "facadeModuleId": "vite-plugin-web-extension/background.html", 14 | "fileName": "assets/background.js", 15 | "implicitlyLoadedBefore": [], 16 | "importedBindings": {}, 17 | "imports": [], 18 | "isDynamicEntry": false, 19 | "isEntry": true, 20 | "isImplicitEntry": false, 21 | "map": null, 22 | "modules": { 23 | "vite-plugin-web-extension/background.html": { 24 | "code": "", 25 | "originalLength": 168, 26 | "removedExports": [], 27 | "renderedExports": [], 28 | "renderedLength": 0, 29 | }, 30 | "vite-plugin-web-extension/test/manifest/resources/backgroundScript/background.js": { 31 | "code": "log("background");", 32 | "originalLength": 55, 33 | "removedExports": [], 34 | "renderedExports": [], 35 | "renderedLength": 18, 36 | }, 37 | "vite-plugin-web-extension/test/manifest/resources/shared/log.js": { 38 | "code": "function log(message) { 39 | console.log(message); 40 | }", 41 | "originalLength": 65, 42 | "removedExports": [], 43 | "renderedExports": [ 44 | "default", 45 | ], 46 | "renderedLength": 49, 47 | }, 48 | }, 49 | "name": "background", 50 | "referencedFiles": [], 51 | "type": "chunk", 52 | "viteMetadata": { 53 | "importedAssets": Set {}, 54 | "importedCss": Set {}, 55 | }, 56 | }, 57 | { 58 | "fileName": "background.html", 59 | "name": undefined, 60 | "source": " 61 | ", 62 | "type": "asset", 63 | }, 64 | { 65 | "fileName": "manifest.json", 66 | "name": undefined, 67 | "source": "{ 68 | "version": "1.0.0", 69 | "name": "Manifest Name", 70 | "manifest_version": 2, 71 | "background": { 72 | "persistent": false, 73 | "page": "background.html" 74 | } 75 | }", 76 | "type": "asset", 77 | }, 78 | ] 79 | `; 80 | -------------------------------------------------------------------------------- /test/manifest/__snapshots__/backgroundServiceWorker.v3.test.ts.snap: -------------------------------------------------------------------------------- 1 | // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html 2 | 3 | exports[`backgroundServiceWorker - Manifest V3 1`] = ` 4 | [ 5 | { 6 | "code": "console.log("serviceWorker"); 7 | ", 8 | "dynamicImports": [], 9 | "exports": [], 10 | "facadeModuleId": "vite-plugin-web-extension/test/manifest/resources/backgroundServiceWorker/serviceWorker.js", 11 | "fileName": "assets/test/manifest/resources/backgroundServiceWorker/serviceWorker.js", 12 | "implicitlyLoadedBefore": [], 13 | "importedBindings": {}, 14 | "imports": [], 15 | "isDynamicEntry": false, 16 | "isEntry": true, 17 | "isImplicitEntry": false, 18 | "map": null, 19 | "modules": { 20 | "vite-plugin-web-extension/test/manifest/resources/backgroundServiceWorker/serviceWorker.js": { 21 | "code": "console.log("serviceWorker");", 22 | "originalLength": 30, 23 | "removedExports": [], 24 | "renderedExports": [], 25 | "renderedLength": 29, 26 | }, 27 | }, 28 | "name": "test/manifest/resources/backgroundServiceWorker/serviceWorker", 29 | "referencedFiles": [], 30 | "type": "chunk", 31 | "viteMetadata": { 32 | "importedAssets": Set {}, 33 | "importedCss": Set {}, 34 | }, 35 | }, 36 | { 37 | "fileName": "manifest.json", 38 | "name": undefined, 39 | "source": "{ 40 | "version": "1.0.0", 41 | "name": "Manifest Name", 42 | "manifest_version": 3, 43 | "background": { 44 | "service_worker": "serviceWorker.js", 45 | "type": "module" 46 | } 47 | }", 48 | "type": "asset", 49 | }, 50 | { 51 | "fileName": "serviceWorker.js", 52 | "name": undefined, 53 | "source": "import "/assets/test/manifest/resources/backgroundServiceWorker/serviceWorker.js";", 54 | "type": "asset", 55 | }, 56 | ] 57 | `; 58 | -------------------------------------------------------------------------------- /test/manifest/__snapshots__/backgroundServiceWorkerRelative.v3.test.ts.snap: -------------------------------------------------------------------------------- 1 | // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html 2 | 3 | exports[`backgroundServiceWorker - Manifest V3 1`] = ` 4 | [ 5 | { 6 | "code": "console.log("serviceWorker"); 7 | ", 8 | "dynamicImports": [], 9 | "exports": [], 10 | "facadeModuleId": "vite-plugin-web-extension/test/manifest/resources/backgroundServiceWorker/serviceWorker.js", 11 | "fileName": "assets/test/manifest/resources/backgroundServiceWorker/serviceWorker.js", 12 | "implicitlyLoadedBefore": [], 13 | "importedBindings": {}, 14 | "imports": [], 15 | "isDynamicEntry": false, 16 | "isEntry": true, 17 | "isImplicitEntry": false, 18 | "map": null, 19 | "modules": { 20 | "vite-plugin-web-extension/test/manifest/resources/backgroundServiceWorker/serviceWorker.js": { 21 | "code": "console.log("serviceWorker");", 22 | "originalLength": 30, 23 | "removedExports": [], 24 | "renderedExports": [], 25 | "renderedLength": 29, 26 | }, 27 | }, 28 | "name": "test/manifest/resources/backgroundServiceWorker/serviceWorker", 29 | "referencedFiles": [], 30 | "type": "chunk", 31 | "viteMetadata": { 32 | "importedAssets": Set {}, 33 | "importedCss": Set {}, 34 | }, 35 | }, 36 | { 37 | "fileName": "manifest.json", 38 | "name": undefined, 39 | "source": "{ 40 | "version": "1.0.0", 41 | "name": "Manifest Name", 42 | "manifest_version": 3, 43 | "background": { 44 | "service_worker": "serviceWorker.js", 45 | "type": "module" 46 | } 47 | }", 48 | "type": "asset", 49 | }, 50 | { 51 | "fileName": "serviceWorker.js", 52 | "name": undefined, 53 | "source": "import "/assets/test/manifest/resources/backgroundServiceWorker/serviceWorker.js";", 54 | "type": "asset", 55 | }, 56 | ] 57 | `; 58 | -------------------------------------------------------------------------------- /test/manifest/__snapshots__/backgroundServiceWorkerRoot.v3.test.ts.snap: -------------------------------------------------------------------------------- 1 | // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html 2 | 3 | exports[`backgroundServiceWorker - Manifest V3 1`] = ` 4 | [ 5 | { 6 | "code": "console.log("serviceWorker"); 7 | ", 8 | "dynamicImports": [], 9 | "exports": [], 10 | "facadeModuleId": "vite-plugin-web-extension/test/manifest/resources/backgroundServiceWorker/serviceWorker.js", 11 | "fileName": "assets/test/manifest/resources/backgroundServiceWorker/serviceWorker.js", 12 | "implicitlyLoadedBefore": [], 13 | "importedBindings": {}, 14 | "imports": [], 15 | "isDynamicEntry": false, 16 | "isEntry": true, 17 | "isImplicitEntry": false, 18 | "map": null, 19 | "modules": { 20 | "vite-plugin-web-extension/test/manifest/resources/backgroundServiceWorker/serviceWorker.js": { 21 | "code": "console.log("serviceWorker");", 22 | "originalLength": 30, 23 | "removedExports": [], 24 | "renderedExports": [], 25 | "renderedLength": 29, 26 | }, 27 | }, 28 | "name": "test/manifest/resources/backgroundServiceWorker/serviceWorker", 29 | "referencedFiles": [], 30 | "type": "chunk", 31 | "viteMetadata": { 32 | "importedAssets": Set {}, 33 | "importedCss": Set {}, 34 | }, 35 | }, 36 | { 37 | "fileName": "manifest.json", 38 | "name": undefined, 39 | "source": "{ 40 | "version": "1.0.0", 41 | "name": "Manifest Name", 42 | "manifest_version": 3, 43 | "background": { 44 | "service_worker": "serviceWorker.js", 45 | "type": "module" 46 | } 47 | }", 48 | "type": "asset", 49 | }, 50 | { 51 | "fileName": "serviceWorker.js", 52 | "name": undefined, 53 | "source": "import "/assets/test/manifest/resources/backgroundServiceWorker/serviceWorker.js";", 54 | "type": "asset", 55 | }, 56 | ] 57 | `; 58 | -------------------------------------------------------------------------------- /test/manifest/__snapshots__/chromeUrlOverridesHtmlBookmarks.v2.test.ts.snap: -------------------------------------------------------------------------------- 1 | // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html 2 | 3 | exports[`chromeUrlOverridesHtmlBookmarks - Manifest V2 1`] = ` 4 | [ 5 | { 6 | "code": "function log(message) { 7 | console.log(message); 8 | } 9 | log("chromeUrlOverridesHtml"); 10 | ", 11 | "dynamicImports": [], 12 | "exports": [], 13 | "facadeModuleId": "vite-plugin-web-extension/test/manifest/resources/chromeUrlOverridesHtml/bookmarks.html", 14 | "fileName": "assets/test/manifest/resources/chromeUrlOverridesHtml/bookmarks.js", 15 | "implicitlyLoadedBefore": [], 16 | "importedBindings": {}, 17 | "imports": [], 18 | "isDynamicEntry": false, 19 | "isEntry": true, 20 | "isImplicitEntry": false, 21 | "map": null, 22 | "modules": { 23 | "vite-plugin-web-extension/test/manifest/resources/chromeUrlOverridesHtml/bookmarks.html": { 24 | "code": "", 25 | "originalLength": 241, 26 | "removedExports": [], 27 | "renderedExports": [], 28 | "renderedLength": 0, 29 | }, 30 | "vite-plugin-web-extension/test/manifest/resources/chromeUrlOverridesHtml/chromeUrlOverridesHtml.js": { 31 | "code": "log("chromeUrlOverridesHtml");", 32 | "originalLength": 67, 33 | "removedExports": [], 34 | "renderedExports": [], 35 | "renderedLength": 30, 36 | }, 37 | "vite-plugin-web-extension/test/manifest/resources/shared/log.js": { 38 | "code": "function log(message) { 39 | console.log(message); 40 | }", 41 | "originalLength": 65, 42 | "removedExports": [], 43 | "renderedExports": [ 44 | "default", 45 | ], 46 | "renderedLength": 49, 47 | }, 48 | }, 49 | "name": "test/manifest/resources/chromeUrlOverridesHtml/bookmarks", 50 | "referencedFiles": [], 51 | "type": "chunk", 52 | "viteMetadata": { 53 | "importedAssets": Set {}, 54 | "importedCss": Set {}, 55 | }, 56 | }, 57 | { 58 | "fileName": "manifest.json", 59 | "name": undefined, 60 | "source": "{ 61 | "version": "1.0.0", 62 | "name": "Manifest Name", 63 | "manifest_version": 2, 64 | "chrome_url_overrides": { 65 | "bookmarks": "test/manifest/resources/chromeUrlOverridesHtml/bookmarks.html" 66 | } 67 | }", 68 | "type": "asset", 69 | }, 70 | { 71 | "fileName": "test/manifest/resources/chromeUrlOverridesHtml/bookmarks.html", 72 | "name": undefined, 73 | "source": " 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | ", 83 | "type": "asset", 84 | }, 85 | ] 86 | `; 87 | -------------------------------------------------------------------------------- /test/manifest/__snapshots__/chromeUrlOverridesHtmlBookmarks.v3.test.ts.snap: -------------------------------------------------------------------------------- 1 | // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html 2 | 3 | exports[`chromeUrlOverridesHtmlBookmarks - Manifest V3 1`] = ` 4 | [ 5 | { 6 | "code": "function log(message) { 7 | console.log(message); 8 | } 9 | log("chromeUrlOverridesHtml"); 10 | ", 11 | "dynamicImports": [], 12 | "exports": [], 13 | "facadeModuleId": "vite-plugin-web-extension/test/manifest/resources/chromeUrlOverridesHtml/bookmarks.html", 14 | "fileName": "assets/test/manifest/resources/chromeUrlOverridesHtml/bookmarks.js", 15 | "implicitlyLoadedBefore": [], 16 | "importedBindings": {}, 17 | "imports": [], 18 | "isDynamicEntry": false, 19 | "isEntry": true, 20 | "isImplicitEntry": false, 21 | "map": null, 22 | "modules": { 23 | "vite-plugin-web-extension/test/manifest/resources/chromeUrlOverridesHtml/bookmarks.html": { 24 | "code": "", 25 | "originalLength": 241, 26 | "removedExports": [], 27 | "renderedExports": [], 28 | "renderedLength": 0, 29 | }, 30 | "vite-plugin-web-extension/test/manifest/resources/chromeUrlOverridesHtml/chromeUrlOverridesHtml.js": { 31 | "code": "log("chromeUrlOverridesHtml");", 32 | "originalLength": 67, 33 | "removedExports": [], 34 | "renderedExports": [], 35 | "renderedLength": 30, 36 | }, 37 | "vite-plugin-web-extension/test/manifest/resources/shared/log.js": { 38 | "code": "function log(message) { 39 | console.log(message); 40 | }", 41 | "originalLength": 65, 42 | "removedExports": [], 43 | "renderedExports": [ 44 | "default", 45 | ], 46 | "renderedLength": 49, 47 | }, 48 | }, 49 | "name": "test/manifest/resources/chromeUrlOverridesHtml/bookmarks", 50 | "referencedFiles": [], 51 | "type": "chunk", 52 | "viteMetadata": { 53 | "importedAssets": Set {}, 54 | "importedCss": Set {}, 55 | }, 56 | }, 57 | { 58 | "fileName": "manifest.json", 59 | "name": undefined, 60 | "source": "{ 61 | "version": "1.0.0", 62 | "name": "Manifest Name", 63 | "manifest_version": 3, 64 | "chrome_url_overrides": { 65 | "bookmarks": "test/manifest/resources/chromeUrlOverridesHtml/bookmarks.html" 66 | } 67 | }", 68 | "type": "asset", 69 | }, 70 | { 71 | "fileName": "test/manifest/resources/chromeUrlOverridesHtml/bookmarks.html", 72 | "name": undefined, 73 | "source": " 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | ", 83 | "type": "asset", 84 | }, 85 | ] 86 | `; 87 | -------------------------------------------------------------------------------- /test/manifest/__snapshots__/chromeUrlOverridesHtmlHistory.v2.test.ts.snap: -------------------------------------------------------------------------------- 1 | // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html 2 | 3 | exports[`chromeUrlOverridesHtmlHistory - Manifest V2 1`] = ` 4 | [ 5 | { 6 | "code": "function log(message) { 7 | console.log(message); 8 | } 9 | log("chromeUrlOverridesHtml"); 10 | ", 11 | "dynamicImports": [], 12 | "exports": [], 13 | "facadeModuleId": "vite-plugin-web-extension/test/manifest/resources/chromeUrlOverridesHtml/history.html", 14 | "fileName": "assets/test/manifest/resources/chromeUrlOverridesHtml/history.js", 15 | "implicitlyLoadedBefore": [], 16 | "importedBindings": {}, 17 | "imports": [], 18 | "isDynamicEntry": false, 19 | "isEntry": true, 20 | "isImplicitEntry": false, 21 | "map": null, 22 | "modules": { 23 | "vite-plugin-web-extension/test/manifest/resources/chromeUrlOverridesHtml/chromeUrlOverridesHtml.js": { 24 | "code": "log("chromeUrlOverridesHtml");", 25 | "originalLength": 67, 26 | "removedExports": [], 27 | "renderedExports": [], 28 | "renderedLength": 30, 29 | }, 30 | "vite-plugin-web-extension/test/manifest/resources/chromeUrlOverridesHtml/history.html": { 31 | "code": "", 32 | "originalLength": 241, 33 | "removedExports": [], 34 | "renderedExports": [], 35 | "renderedLength": 0, 36 | }, 37 | "vite-plugin-web-extension/test/manifest/resources/shared/log.js": { 38 | "code": "function log(message) { 39 | console.log(message); 40 | }", 41 | "originalLength": 65, 42 | "removedExports": [], 43 | "renderedExports": [ 44 | "default", 45 | ], 46 | "renderedLength": 49, 47 | }, 48 | }, 49 | "name": "test/manifest/resources/chromeUrlOverridesHtml/history", 50 | "referencedFiles": [], 51 | "type": "chunk", 52 | "viteMetadata": { 53 | "importedAssets": Set {}, 54 | "importedCss": Set {}, 55 | }, 56 | }, 57 | { 58 | "fileName": "manifest.json", 59 | "name": undefined, 60 | "source": "{ 61 | "version": "1.0.0", 62 | "name": "Manifest Name", 63 | "manifest_version": 2, 64 | "chrome_url_overrides": { 65 | "history": "test/manifest/resources/chromeUrlOverridesHtml/history.html" 66 | } 67 | }", 68 | "type": "asset", 69 | }, 70 | { 71 | "fileName": "test/manifest/resources/chromeUrlOverridesHtml/history.html", 72 | "name": undefined, 73 | "source": " 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | ", 83 | "type": "asset", 84 | }, 85 | ] 86 | `; 87 | -------------------------------------------------------------------------------- /test/manifest/__snapshots__/chromeUrlOverridesHtmlHistory.v3.test.ts.snap: -------------------------------------------------------------------------------- 1 | // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html 2 | 3 | exports[`chromeUrlOverridesHtmlHistory - Manifest V3 1`] = ` 4 | [ 5 | { 6 | "code": "function log(message) { 7 | console.log(message); 8 | } 9 | log("chromeUrlOverridesHtml"); 10 | ", 11 | "dynamicImports": [], 12 | "exports": [], 13 | "facadeModuleId": "vite-plugin-web-extension/test/manifest/resources/chromeUrlOverridesHtml/history.html", 14 | "fileName": "assets/test/manifest/resources/chromeUrlOverridesHtml/history.js", 15 | "implicitlyLoadedBefore": [], 16 | "importedBindings": {}, 17 | "imports": [], 18 | "isDynamicEntry": false, 19 | "isEntry": true, 20 | "isImplicitEntry": false, 21 | "map": null, 22 | "modules": { 23 | "vite-plugin-web-extension/test/manifest/resources/chromeUrlOverridesHtml/chromeUrlOverridesHtml.js": { 24 | "code": "log("chromeUrlOverridesHtml");", 25 | "originalLength": 67, 26 | "removedExports": [], 27 | "renderedExports": [], 28 | "renderedLength": 30, 29 | }, 30 | "vite-plugin-web-extension/test/manifest/resources/chromeUrlOverridesHtml/history.html": { 31 | "code": "", 32 | "originalLength": 241, 33 | "removedExports": [], 34 | "renderedExports": [], 35 | "renderedLength": 0, 36 | }, 37 | "vite-plugin-web-extension/test/manifest/resources/shared/log.js": { 38 | "code": "function log(message) { 39 | console.log(message); 40 | }", 41 | "originalLength": 65, 42 | "removedExports": [], 43 | "renderedExports": [ 44 | "default", 45 | ], 46 | "renderedLength": 49, 47 | }, 48 | }, 49 | "name": "test/manifest/resources/chromeUrlOverridesHtml/history", 50 | "referencedFiles": [], 51 | "type": "chunk", 52 | "viteMetadata": { 53 | "importedAssets": Set {}, 54 | "importedCss": Set {}, 55 | }, 56 | }, 57 | { 58 | "fileName": "manifest.json", 59 | "name": undefined, 60 | "source": "{ 61 | "version": "1.0.0", 62 | "name": "Manifest Name", 63 | "manifest_version": 3, 64 | "chrome_url_overrides": { 65 | "history": "test/manifest/resources/chromeUrlOverridesHtml/history.html" 66 | } 67 | }", 68 | "type": "asset", 69 | }, 70 | { 71 | "fileName": "test/manifest/resources/chromeUrlOverridesHtml/history.html", 72 | "name": undefined, 73 | "source": " 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | ", 83 | "type": "asset", 84 | }, 85 | ] 86 | `; 87 | -------------------------------------------------------------------------------- /test/manifest/__snapshots__/chromeUrlOverridesHtmlNewTab.v2.test.ts.snap: -------------------------------------------------------------------------------- 1 | // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html 2 | 3 | exports[`chromeUrlOverridesHtmlNewTab - Manifest V2 1`] = ` 4 | [ 5 | { 6 | "code": "function log(message) { 7 | console.log(message); 8 | } 9 | log("chromeUrlOverridesHtml"); 10 | ", 11 | "dynamicImports": [], 12 | "exports": [], 13 | "facadeModuleId": "vite-plugin-web-extension/test/manifest/resources/chromeUrlOverridesHtml/newtab.html", 14 | "fileName": "assets/test/manifest/resources/chromeUrlOverridesHtml/newtab.js", 15 | "implicitlyLoadedBefore": [], 16 | "importedBindings": {}, 17 | "imports": [], 18 | "isDynamicEntry": false, 19 | "isEntry": true, 20 | "isImplicitEntry": false, 21 | "map": null, 22 | "modules": { 23 | "vite-plugin-web-extension/test/manifest/resources/chromeUrlOverridesHtml/chromeUrlOverridesHtml.js": { 24 | "code": "log("chromeUrlOverridesHtml");", 25 | "originalLength": 67, 26 | "removedExports": [], 27 | "renderedExports": [], 28 | "renderedLength": 30, 29 | }, 30 | "vite-plugin-web-extension/test/manifest/resources/chromeUrlOverridesHtml/newtab.html": { 31 | "code": "", 32 | "originalLength": 241, 33 | "removedExports": [], 34 | "renderedExports": [], 35 | "renderedLength": 0, 36 | }, 37 | "vite-plugin-web-extension/test/manifest/resources/shared/log.js": { 38 | "code": "function log(message) { 39 | console.log(message); 40 | }", 41 | "originalLength": 65, 42 | "removedExports": [], 43 | "renderedExports": [ 44 | "default", 45 | ], 46 | "renderedLength": 49, 47 | }, 48 | }, 49 | "name": "test/manifest/resources/chromeUrlOverridesHtml/newtab", 50 | "referencedFiles": [], 51 | "type": "chunk", 52 | "viteMetadata": { 53 | "importedAssets": Set {}, 54 | "importedCss": Set {}, 55 | }, 56 | }, 57 | { 58 | "fileName": "manifest.json", 59 | "name": undefined, 60 | "source": "{ 61 | "version": "1.0.0", 62 | "name": "Manifest Name", 63 | "manifest_version": 2, 64 | "chrome_url_overrides": { 65 | "newtab": "test/manifest/resources/chromeUrlOverridesHtml/newtab.html" 66 | } 67 | }", 68 | "type": "asset", 69 | }, 70 | { 71 | "fileName": "test/manifest/resources/chromeUrlOverridesHtml/newtab.html", 72 | "name": undefined, 73 | "source": " 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | ", 83 | "type": "asset", 84 | }, 85 | ] 86 | `; 87 | -------------------------------------------------------------------------------- /test/manifest/__snapshots__/chromeUrlOverridesHtmlNewTab.v3.test.ts.snap: -------------------------------------------------------------------------------- 1 | // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html 2 | 3 | exports[`chromeUrlOverridesHtmlNewTab - Manifest V3 1`] = ` 4 | [ 5 | { 6 | "code": "function log(message) { 7 | console.log(message); 8 | } 9 | log("chromeUrlOverridesHtml"); 10 | ", 11 | "dynamicImports": [], 12 | "exports": [], 13 | "facadeModuleId": "vite-plugin-web-extension/test/manifest/resources/chromeUrlOverridesHtml/newtab.html", 14 | "fileName": "assets/test/manifest/resources/chromeUrlOverridesHtml/newtab.js", 15 | "implicitlyLoadedBefore": [], 16 | "importedBindings": {}, 17 | "imports": [], 18 | "isDynamicEntry": false, 19 | "isEntry": true, 20 | "isImplicitEntry": false, 21 | "map": null, 22 | "modules": { 23 | "vite-plugin-web-extension/test/manifest/resources/chromeUrlOverridesHtml/chromeUrlOverridesHtml.js": { 24 | "code": "log("chromeUrlOverridesHtml");", 25 | "originalLength": 67, 26 | "removedExports": [], 27 | "renderedExports": [], 28 | "renderedLength": 30, 29 | }, 30 | "vite-plugin-web-extension/test/manifest/resources/chromeUrlOverridesHtml/newtab.html": { 31 | "code": "", 32 | "originalLength": 241, 33 | "removedExports": [], 34 | "renderedExports": [], 35 | "renderedLength": 0, 36 | }, 37 | "vite-plugin-web-extension/test/manifest/resources/shared/log.js": { 38 | "code": "function log(message) { 39 | console.log(message); 40 | }", 41 | "originalLength": 65, 42 | "removedExports": [], 43 | "renderedExports": [ 44 | "default", 45 | ], 46 | "renderedLength": 49, 47 | }, 48 | }, 49 | "name": "test/manifest/resources/chromeUrlOverridesHtml/newtab", 50 | "referencedFiles": [], 51 | "type": "chunk", 52 | "viteMetadata": { 53 | "importedAssets": Set {}, 54 | "importedCss": Set {}, 55 | }, 56 | }, 57 | { 58 | "fileName": "manifest.json", 59 | "name": undefined, 60 | "source": "{ 61 | "version": "1.0.0", 62 | "name": "Manifest Name", 63 | "manifest_version": 3, 64 | "chrome_url_overrides": { 65 | "newtab": "test/manifest/resources/chromeUrlOverridesHtml/newtab.html" 66 | } 67 | }", 68 | "type": "asset", 69 | }, 70 | { 71 | "fileName": "test/manifest/resources/chromeUrlOverridesHtml/newtab.html", 72 | "name": undefined, 73 | "source": " 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | ", 83 | "type": "asset", 84 | }, 85 | ] 86 | `; 87 | -------------------------------------------------------------------------------- /test/manifest/__snapshots__/chunkCssRewrite.v2.test.ts.snap: -------------------------------------------------------------------------------- 1 | // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html 2 | 3 | exports[`chunkCssRewrite - Manifest V2 1`] = ` 4 | [ 5 | { 6 | "fileName": "assets/content1.css", 7 | "name": "content1.css", 8 | "source": "#content1 { 9 | display: flex; 10 | } 11 | ", 12 | "type": "asset", 13 | }, 14 | { 15 | "fileName": "assets/content2.css", 16 | "name": "content2.css", 17 | "source": "#content2 { 18 | display: flex; 19 | } 20 | ", 21 | "type": "asset", 22 | }, 23 | { 24 | "fileName": "assets/contentShared.css", 25 | "name": "contentShared.css", 26 | "source": "#contentShared { 27 | display: flex; 28 | } 29 | ", 30 | "type": "asset", 31 | }, 32 | { 33 | "fileName": "manifest.json", 34 | "name": undefined, 35 | "source": "{ 36 | "version": "1.0.0", 37 | "name": "Manifest Name", 38 | "manifest_version": 2, 39 | "content_scripts": [ 40 | { 41 | "js": [ 42 | "test/manifest/resources/chunkCssRewrite/content1.js" 43 | ], 44 | "matches": [ 45 | "https://*/*", 46 | "http://*/*" 47 | ] 48 | }, 49 | { 50 | "js": [ 51 | "test/manifest/resources/chunkCssRewrite/content2.js" 52 | ], 53 | "matches": [ 54 | "https://*/*", 55 | "http://*/*" 56 | ] 57 | }, 58 | { 59 | "js": [ 60 | "test/manifest/resources/chunkCssRewrite/contentNoCss.js" 61 | ], 62 | "matches": [ 63 | "https://*/*", 64 | "http://*/*" 65 | ] 66 | } 67 | ], 68 | "web_accessible_resources": [ 69 | "assets/content1.css", 70 | "assets/content2.css", 71 | "assets/contentShared.css" 72 | ] 73 | }", 74 | "type": "asset", 75 | }, 76 | { 77 | "fileName": "test/manifest/resources/chunkCssRewrite/content1.js", 78 | "name": undefined, 79 | "source": "/* empty css */ 80 | console.log(["assets/content1.css","assets/contentShared.css"]); 81 | ", 82 | "type": "asset", 83 | }, 84 | { 85 | "fileName": "test/manifest/resources/chunkCssRewrite/content2.js", 86 | "name": undefined, 87 | "source": "/* empty css */ 88 | console.log(["assets/content2.css","assets/contentShared.css"]); 89 | ", 90 | "type": "asset", 91 | }, 92 | { 93 | "fileName": "test/manifest/resources/chunkCssRewrite/contentNoCss.js", 94 | "name": undefined, 95 | "source": "console.log([]); 96 | ", 97 | "type": "asset", 98 | }, 99 | ] 100 | `; 101 | -------------------------------------------------------------------------------- /test/manifest/__snapshots__/chunkCssRewrite.v3.test.ts.snap: -------------------------------------------------------------------------------- 1 | // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html 2 | 3 | exports[`chunkCssRewrite - Manifest V3 1`] = ` 4 | [ 5 | { 6 | "fileName": "assets/content1.css", 7 | "name": "content1.css", 8 | "source": "#content1 { 9 | display: flex; 10 | } 11 | ", 12 | "type": "asset", 13 | }, 14 | { 15 | "fileName": "assets/content2.css", 16 | "name": "content2.css", 17 | "source": "#content2 { 18 | display: flex; 19 | } 20 | ", 21 | "type": "asset", 22 | }, 23 | { 24 | "fileName": "assets/contentShared.css", 25 | "name": "contentShared.css", 26 | "source": "#contentShared { 27 | display: flex; 28 | } 29 | ", 30 | "type": "asset", 31 | }, 32 | { 33 | "fileName": "manifest.json", 34 | "name": undefined, 35 | "source": "{ 36 | "version": "1.0.0", 37 | "name": "Manifest Name", 38 | "manifest_version": 3, 39 | "content_scripts": [ 40 | { 41 | "js": [ 42 | "test/manifest/resources/chunkCssRewrite/content1.js" 43 | ], 44 | "matches": [ 45 | "https://*/*", 46 | "http://*/*" 47 | ] 48 | }, 49 | { 50 | "js": [ 51 | "test/manifest/resources/chunkCssRewrite/content2.js" 52 | ], 53 | "matches": [ 54 | "https://*/*", 55 | "http://*/*" 56 | ] 57 | }, 58 | { 59 | "js": [ 60 | "test/manifest/resources/chunkCssRewrite/contentNoCss.js" 61 | ], 62 | "matches": [ 63 | "https://*/*", 64 | "http://*/*" 65 | ] 66 | } 67 | ], 68 | "web_accessible_resources": [ 69 | { 70 | "resources": [ 71 | "assets/content1.css", 72 | "assets/content2.css", 73 | "assets/contentShared.css" 74 | ], 75 | "matches": [ 76 | "https://*/*", 77 | "http://*/*" 78 | ] 79 | } 80 | ] 81 | }", 82 | "type": "asset", 83 | }, 84 | { 85 | "fileName": "test/manifest/resources/chunkCssRewrite/content1.js", 86 | "name": undefined, 87 | "source": "/* empty css */ 88 | console.log(["assets/content1.css","assets/contentShared.css"]); 89 | ", 90 | "type": "asset", 91 | }, 92 | { 93 | "fileName": "test/manifest/resources/chunkCssRewrite/content2.js", 94 | "name": undefined, 95 | "source": "/* empty css */ 96 | console.log(["assets/content2.css","assets/contentShared.css"]); 97 | ", 98 | "type": "asset", 99 | }, 100 | { 101 | "fileName": "test/manifest/resources/chunkCssRewrite/contentNoCss.js", 102 | "name": undefined, 103 | "source": "console.log([]); 104 | ", 105 | "type": "asset", 106 | }, 107 | ] 108 | `; 109 | -------------------------------------------------------------------------------- /test/manifest/__snapshots__/contentCss.v2.test.ts.snap: -------------------------------------------------------------------------------- 1 | // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html 2 | 3 | exports[`contentCss - Manifest V2 1`] = ` 4 | [ 5 | { 6 | "fileName": "assets/test/manifest/resources/contentCss/content1.css", 7 | "name": "test/manifest/resources/contentCss/content1.css", 8 | "source": ".css { 9 | color: red; 10 | } 11 | ", 12 | "type": "asset", 13 | }, 14 | { 15 | "fileName": "assets/test/manifest/resources/contentCss/content2.css", 16 | "name": "test/manifest/resources/contentCss/content2.css", 17 | "source": ".css { 18 | color: green; 19 | }", 20 | "type": "asset", 21 | }, 22 | { 23 | "fileName": "manifest.json", 24 | "name": undefined, 25 | "source": "{ 26 | "version": "1.0.0", 27 | "name": "Manifest Name", 28 | "manifest_version": 2, 29 | "content_scripts": [ 30 | { 31 | "js": [ 32 | "test/manifest/resources/contentCss/content.js" 33 | ], 34 | "css": [ 35 | "assets/test/manifest/resources/contentCss/content1.css", 36 | "assets/test/manifest/resources/contentCss/content2.css" 37 | ], 38 | "matches": [ 39 | "https://*/*", 40 | "http://*/*" 41 | ] 42 | } 43 | ] 44 | }", 45 | "type": "asset", 46 | }, 47 | { 48 | "fileName": "test/manifest/resources/contentCss/content.js", 49 | "name": undefined, 50 | "source": "console.log("content"); 51 | ", 52 | "type": "asset", 53 | }, 54 | ] 55 | `; 56 | -------------------------------------------------------------------------------- /test/manifest/__snapshots__/contentCss.v3.test.ts.snap: -------------------------------------------------------------------------------- 1 | // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html 2 | 3 | exports[`contentCss - Manifest V3 1`] = ` 4 | [ 5 | { 6 | "fileName": "assets/test/manifest/resources/contentCss/content1.css", 7 | "name": "test/manifest/resources/contentCss/content1.css", 8 | "source": ".css { 9 | color: red; 10 | } 11 | ", 12 | "type": "asset", 13 | }, 14 | { 15 | "fileName": "assets/test/manifest/resources/contentCss/content2.css", 16 | "name": "test/manifest/resources/contentCss/content2.css", 17 | "source": ".css { 18 | color: green; 19 | }", 20 | "type": "asset", 21 | }, 22 | { 23 | "fileName": "manifest.json", 24 | "name": undefined, 25 | "source": "{ 26 | "version": "1.0.0", 27 | "name": "Manifest Name", 28 | "manifest_version": 3, 29 | "content_scripts": [ 30 | { 31 | "js": [ 32 | "test/manifest/resources/contentCss/content.js" 33 | ], 34 | "css": [ 35 | "assets/test/manifest/resources/contentCss/content1.css", 36 | "assets/test/manifest/resources/contentCss/content2.css" 37 | ], 38 | "matches": [ 39 | "https://*/*", 40 | "http://*/*" 41 | ] 42 | } 43 | ] 44 | }", 45 | "type": "asset", 46 | }, 47 | { 48 | "fileName": "test/manifest/resources/contentCss/content.js", 49 | "name": undefined, 50 | "source": "console.log("content"); 51 | ", 52 | "type": "asset", 53 | }, 54 | ] 55 | `; 56 | -------------------------------------------------------------------------------- /test/manifest/__snapshots__/contentScriptPaths.v2.test.ts.snap: -------------------------------------------------------------------------------- 1 | // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html 2 | 3 | exports[`contentScriptPaths - Manifest V2 1`] = ` 4 | [ 5 | { 6 | "code": "function log(message) { 7 | console.log(message); 8 | } 9 | export { 10 | log as l 11 | }; 12 | ", 13 | "dynamicImports": [], 14 | "exports": [ 15 | "l", 16 | ], 17 | "facadeModuleId": null, 18 | "fileName": "assets/log.js", 19 | "implicitlyLoadedBefore": [], 20 | "importedBindings": {}, 21 | "imports": [], 22 | "isDynamicEntry": false, 23 | "isEntry": false, 24 | "isImplicitEntry": false, 25 | "map": null, 26 | "modules": { 27 | "vite-plugin-web-extension/test/manifest/resources/shared/log.js": { 28 | "code": "function log(message) { 29 | console.log(message); 30 | }", 31 | "originalLength": 65, 32 | "removedExports": [], 33 | "renderedExports": [ 34 | "default", 35 | ], 36 | "renderedLength": 49, 37 | }, 38 | }, 39 | "name": "log", 40 | "referencedFiles": [], 41 | "type": "chunk", 42 | "viteMetadata": { 43 | "importedAssets": Set {}, 44 | "importedCss": Set {}, 45 | }, 46 | }, 47 | { 48 | "code": "import { l as log } from "../../../../log.js"; 49 | log("content"); 50 | ", 51 | "dynamicImports": [], 52 | "exports": [], 53 | "facadeModuleId": "vite-plugin-web-extension/test/manifest/resources/contentWithChunkedImport/content1.js", 54 | "fileName": "assets/test/manifest/resources/contentWithChunkedImport/content1.js", 55 | "implicitlyLoadedBefore": [], 56 | "importedBindings": { 57 | "assets/log.js": [ 58 | "l", 59 | ], 60 | }, 61 | "imports": [ 62 | "assets/log.js", 63 | ], 64 | "isDynamicEntry": false, 65 | "isEntry": true, 66 | "isImplicitEntry": false, 67 | "map": null, 68 | "modules": { 69 | "vite-plugin-web-extension/test/manifest/resources/contentWithChunkedImport/content1.js": { 70 | "code": "log("content");", 71 | "originalLength": 52, 72 | "removedExports": [], 73 | "renderedExports": [], 74 | "renderedLength": 15, 75 | }, 76 | }, 77 | "name": "test/manifest/resources/contentWithChunkedImport/content1", 78 | "referencedFiles": [], 79 | "type": "chunk", 80 | "viteMetadata": { 81 | "importedAssets": Set {}, 82 | "importedCss": Set {}, 83 | }, 84 | }, 85 | { 86 | "code": "import { l as log } from "../../../../log.js"; 87 | log("content2"); 88 | ", 89 | "dynamicImports": [], 90 | "exports": [], 91 | "facadeModuleId": "vite-plugin-web-extension/test/manifest/resources/contentWithChunkedImport/content2.js", 92 | "fileName": "assets/test/manifest/resources/contentWithChunkedImport/content2.js", 93 | "implicitlyLoadedBefore": [], 94 | "importedBindings": { 95 | "assets/log.js": [ 96 | "l", 97 | ], 98 | }, 99 | "imports": [ 100 | "assets/log.js", 101 | ], 102 | "isDynamicEntry": false, 103 | "isEntry": true, 104 | "isImplicitEntry": false, 105 | "map": null, 106 | "modules": { 107 | "vite-plugin-web-extension/test/manifest/resources/contentWithChunkedImport/content2.js": { 108 | "code": "log("content2");", 109 | "originalLength": 53, 110 | "removedExports": [], 111 | "renderedExports": [], 112 | "renderedLength": 16, 113 | }, 114 | }, 115 | "name": "test/manifest/resources/contentWithChunkedImport/content2", 116 | "referencedFiles": [], 117 | "type": "chunk", 118 | "viteMetadata": { 119 | "importedAssets": Set {}, 120 | "importedCss": Set {}, 121 | }, 122 | }, 123 | { 124 | "fileName": "manifest.json", 125 | "name": undefined, 126 | "source": "{ 127 | "version": "1.0.0", 128 | "name": "Manifest Name", 129 | "manifest_version": 2, 130 | "content_scripts": [ 131 | { 132 | "js": [ 133 | "test/manifest/resources/contentWithChunkedImport/content1.js" 134 | ], 135 | "matches": [ 136 | "https://*/*", 137 | "http://*/*" 138 | ] 139 | }, 140 | { 141 | "js": [ 142 | "test/manifest/resources/contentWithChunkedImport/content2.js" 143 | ], 144 | "matches": [ 145 | "https://*/*", 146 | "http://*/*" 147 | ] 148 | } 149 | ], 150 | "web_accessible_resources": [ 151 | "assets/log.js", 152 | "assets/test/manifest/resources/contentWithChunkedImport/content1.js", 153 | "assets/test/manifest/resources/contentWithChunkedImport/content2.js" 154 | ] 155 | }", 156 | "type": "asset", 157 | }, 158 | { 159 | "fileName": "test/manifest/resources/contentWithChunkedImport/content1.js", 160 | "name": undefined, 161 | "source": "(async()=>{await import(chrome.runtime.getURL("assets/test/manifest/resources/contentWithChunkedImport/content1.js"))})();", 162 | "type": "asset", 163 | }, 164 | { 165 | "fileName": "test/manifest/resources/contentWithChunkedImport/content2.js", 166 | "name": undefined, 167 | "source": "(async()=>{await import(chrome.runtime.getURL("assets/test/manifest/resources/contentWithChunkedImport/content2.js"))})();", 168 | "type": "asset", 169 | }, 170 | ] 171 | `; 172 | -------------------------------------------------------------------------------- /test/manifest/__snapshots__/contentScriptTypes.v2.test.ts.snap: -------------------------------------------------------------------------------- 1 | // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html 2 | 3 | exports[`contentScriptTypes - Manifest V2 1`] = ` 4 | [ 5 | { 6 | "fileName": "manifest.json", 7 | "name": undefined, 8 | "source": "{ 9 | "version": "1.0.0", 10 | "name": "Manifest Name", 11 | "manifest_version": 2, 12 | "content_scripts": [ 13 | { 14 | "js": [ 15 | "test/manifest/resources/contentScriptTypes/content1.js" 16 | ], 17 | "matches": [ 18 | "https://example.com/" 19 | ] 20 | }, 21 | { 22 | "js": [ 23 | "test/manifest/resources/contentScriptTypes/content2.js" 24 | ], 25 | "matches": [ 26 | "https://example.com/" 27 | ] 28 | } 29 | ] 30 | }", 31 | "type": "asset", 32 | }, 33 | { 34 | "fileName": "test/manifest/resources/contentScriptTypes/content1.js", 35 | "name": undefined, 36 | "source": "console.log("content1"); 37 | ", 38 | "type": "asset", 39 | }, 40 | { 41 | "fileName": "test/manifest/resources/contentScriptTypes/content2.js", 42 | "name": undefined, 43 | "source": "console.log("content2"); 44 | ", 45 | "type": "asset", 46 | }, 47 | ] 48 | `; 49 | -------------------------------------------------------------------------------- /test/manifest/__snapshots__/contentScriptTypes.v3.test.ts.snap: -------------------------------------------------------------------------------- 1 | // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html 2 | 3 | exports[`contentScriptTypes - Manifest V3 1`] = ` 4 | [ 5 | { 6 | "fileName": "manifest.json", 7 | "name": undefined, 8 | "source": "{ 9 | "version": "1.0.0", 10 | "name": "Manifest Name", 11 | "manifest_version": 3, 12 | "content_scripts": [ 13 | { 14 | "js": [ 15 | "test/manifest/resources/contentScriptTypes/content1.js" 16 | ], 17 | "matches": [ 18 | "https://example.com/" 19 | ] 20 | }, 21 | { 22 | "js": [ 23 | "test/manifest/resources/contentScriptTypes/content2.js" 24 | ], 25 | "matches": [ 26 | "https://example.com/" 27 | ] 28 | } 29 | ] 30 | }", 31 | "type": "asset", 32 | }, 33 | { 34 | "fileName": "test/manifest/resources/contentScriptTypes/content1.js", 35 | "name": undefined, 36 | "source": "console.log("content1"); 37 | ", 38 | "type": "asset", 39 | }, 40 | { 41 | "fileName": "test/manifest/resources/contentScriptTypes/content2.js", 42 | "name": undefined, 43 | "source": "console.log("content2"); 44 | ", 45 | "type": "asset", 46 | }, 47 | ] 48 | `; 49 | -------------------------------------------------------------------------------- /test/manifest/__snapshots__/contentWithNoImports.v2.test.ts.snap: -------------------------------------------------------------------------------- 1 | // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html 2 | 3 | exports[`contentWithNoImports - Manifest V2 1`] = ` 4 | [ 5 | { 6 | "fileName": "manifest.json", 7 | "name": undefined, 8 | "source": "{ 9 | "version": "1.0.0", 10 | "name": "Manifest Name", 11 | "manifest_version": 2, 12 | "content_scripts": [ 13 | { 14 | "js": [ 15 | "test/manifest/resources/contentWithNoImports/content.js" 16 | ], 17 | "matches": [ 18 | "https://*/*", 19 | "http://*/*" 20 | ] 21 | } 22 | ] 23 | }", 24 | "type": "asset", 25 | }, 26 | { 27 | "fileName": "test/manifest/resources/contentWithNoImports/content.js", 28 | "name": undefined, 29 | "source": "console.log("content"); 30 | ", 31 | "type": "asset", 32 | }, 33 | ] 34 | `; 35 | -------------------------------------------------------------------------------- /test/manifest/__snapshots__/contentWithNoImports.v3.test.ts.snap: -------------------------------------------------------------------------------- 1 | // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html 2 | 3 | exports[`contentWithNoImports - Manifest V3 1`] = ` 4 | [ 5 | { 6 | "fileName": "manifest.json", 7 | "name": undefined, 8 | "source": "{ 9 | "version": "1.0.0", 10 | "name": "Manifest Name", 11 | "manifest_version": 3, 12 | "content_scripts": [ 13 | { 14 | "js": [ 15 | "test/manifest/resources/contentWithNoImports/content.js" 16 | ], 17 | "matches": [ 18 | "*://*/*", 19 | "https://*/*", 20 | "*://example.com/", 21 | "https://example.com/", 22 | "*://example.com/subpath/*", 23 | "https://example.com/subpath/*" 24 | ] 25 | } 26 | ] 27 | }", 28 | "type": "asset", 29 | }, 30 | { 31 | "fileName": "test/manifest/resources/contentWithNoImports/content.js", 32 | "name": undefined, 33 | "source": "console.log("content"); 34 | ", 35 | "type": "asset", 36 | }, 37 | ] 38 | `; 39 | -------------------------------------------------------------------------------- /test/manifest/__snapshots__/contentWithSameScriptName.v2.test.ts.snap: -------------------------------------------------------------------------------- 1 | // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html 2 | 3 | exports[`contentWithSameScriptName - Manifest V2 1`] = ` 4 | [ 5 | { 6 | "fileName": "manifest.json", 7 | "name": undefined, 8 | "source": "{ 9 | "version": "1.0.0", 10 | "name": "Manifest Name", 11 | "manifest_version": 2, 12 | "content_scripts": [ 13 | { 14 | "js": [ 15 | "test/manifest/resources/contentWithSameScriptName/content1/content.js" 16 | ], 17 | "matches": [ 18 | "https://*/*", 19 | "http://*/*" 20 | ] 21 | }, 22 | { 23 | "js": [ 24 | "test/manifest/resources/contentWithSameScriptName/content2/content.js" 25 | ], 26 | "matches": [ 27 | "https://*/*", 28 | "http://*/*" 29 | ] 30 | } 31 | ] 32 | }", 33 | "type": "asset", 34 | }, 35 | { 36 | "fileName": "test/manifest/resources/contentWithSameScriptName/content1/content.js", 37 | "name": undefined, 38 | "source": "console.log("content1"); 39 | ", 40 | "type": "asset", 41 | }, 42 | { 43 | "fileName": "test/manifest/resources/contentWithSameScriptName/content2/content.js", 44 | "name": undefined, 45 | "source": "console.log("content2"); 46 | ", 47 | "type": "asset", 48 | }, 49 | ] 50 | `; 51 | -------------------------------------------------------------------------------- /test/manifest/__snapshots__/contentWithSameScriptName.v3.test.ts.snap: -------------------------------------------------------------------------------- 1 | // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html 2 | 3 | exports[`contentWithSameScriptName - Manifest V3 1`] = ` 4 | [ 5 | { 6 | "fileName": "manifest.json", 7 | "name": undefined, 8 | "source": "{ 9 | "version": "1.0.0", 10 | "name": "Manifest Name", 11 | "manifest_version": 3, 12 | "content_scripts": [ 13 | { 14 | "js": [ 15 | "test/manifest/resources/contentWithSameScriptName/content1/content.js" 16 | ], 17 | "matches": [ 18 | "*://*/*", 19 | "https://*/*", 20 | "*://example.com/", 21 | "https://example.com/", 22 | "*://example.com/subpath/*", 23 | "https://example.com/subpath/*" 24 | ] 25 | }, 26 | { 27 | "js": [ 28 | "test/manifest/resources/contentWithSameScriptName/content2/content.js" 29 | ], 30 | "matches": [ 31 | "*://*/*", 32 | "https://*/*", 33 | "*://example.com/", 34 | "https://example.com/", 35 | "*://example.com/subpath/*", 36 | "https://example.com/subpath/*" 37 | ] 38 | } 39 | ] 40 | }", 41 | "type": "asset", 42 | }, 43 | { 44 | "fileName": "test/manifest/resources/contentWithSameScriptName/content1/content.js", 45 | "name": undefined, 46 | "source": "console.log("content1"); 47 | ", 48 | "type": "asset", 49 | }, 50 | { 51 | "fileName": "test/manifest/resources/contentWithSameScriptName/content2/content.js", 52 | "name": undefined, 53 | "source": "console.log("content2"); 54 | ", 55 | "type": "asset", 56 | }, 57 | ] 58 | `; 59 | -------------------------------------------------------------------------------- /test/manifest/__snapshots__/contentWithUnchunkedImport.v2.test.ts.snap: -------------------------------------------------------------------------------- 1 | // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html 2 | 3 | exports[`contentWithUnchunkedImport - Manifest V2 1`] = ` 4 | [ 5 | { 6 | "fileName": "manifest.json", 7 | "name": undefined, 8 | "source": "{ 9 | "version": "1.0.0", 10 | "name": "Manifest Name", 11 | "manifest_version": 2, 12 | "content_scripts": [ 13 | { 14 | "js": [ 15 | "test/manifest/resources/contentWithUnchunkedImport/content.js" 16 | ], 17 | "matches": [ 18 | "https://*/*", 19 | "http://*/*" 20 | ] 21 | } 22 | ] 23 | }", 24 | "type": "asset", 25 | }, 26 | { 27 | "fileName": "test/manifest/resources/contentWithUnchunkedImport/content.js", 28 | "name": undefined, 29 | "source": "function log(message) { 30 | console.log(message); 31 | } 32 | log("content"); 33 | ", 34 | "type": "asset", 35 | }, 36 | ] 37 | `; 38 | -------------------------------------------------------------------------------- /test/manifest/__snapshots__/contentWithUnchunkedImport.v3.test.ts.snap: -------------------------------------------------------------------------------- 1 | // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html 2 | 3 | exports[`contentWithUnchunkedImport - Manifest V3 1`] = ` 4 | [ 5 | { 6 | "fileName": "manifest.json", 7 | "name": undefined, 8 | "source": "{ 9 | "version": "1.0.0", 10 | "name": "Manifest Name", 11 | "manifest_version": 3, 12 | "content_scripts": [ 13 | { 14 | "js": [ 15 | "test/manifest/resources/contentWithUnchunkedImport/content.js" 16 | ], 17 | "matches": [ 18 | "*://*/*", 19 | "https://*/*", 20 | "*://example.com/", 21 | "https://example.com/", 22 | "*://example.com/subpath/*", 23 | "https://example.com/subpath/*" 24 | ] 25 | } 26 | ] 27 | }", 28 | "type": "asset", 29 | }, 30 | { 31 | "fileName": "test/manifest/resources/contentWithUnchunkedImport/content.js", 32 | "name": undefined, 33 | "source": "function log(message) { 34 | console.log(message); 35 | } 36 | log("content"); 37 | ", 38 | "type": "asset", 39 | }, 40 | ] 41 | `; 42 | -------------------------------------------------------------------------------- /test/manifest/__snapshots__/devtoolsHtml.v2.test.ts.snap: -------------------------------------------------------------------------------- 1 | // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html 2 | 3 | exports[`devtoolsHtml - Manifest V2 1`] = ` 4 | [ 5 | { 6 | "code": "function log(message) { 7 | console.log(message); 8 | } 9 | log("devtools"); 10 | ", 11 | "dynamicImports": [], 12 | "exports": [], 13 | "facadeModuleId": "vite-plugin-web-extension/test/manifest/resources/devtoolsHtml/devtools.html", 14 | "fileName": "assets/test/manifest/resources/devtoolsHtml/devtools.js", 15 | "implicitlyLoadedBefore": [], 16 | "importedBindings": {}, 17 | "imports": [], 18 | "isDynamicEntry": false, 19 | "isEntry": true, 20 | "isImplicitEntry": false, 21 | "map": null, 22 | "modules": { 23 | "vite-plugin-web-extension/test/manifest/resources/devtoolsHtml/devtools.html": { 24 | "code": "", 25 | "originalLength": 227, 26 | "removedExports": [], 27 | "renderedExports": [], 28 | "renderedLength": 0, 29 | }, 30 | "vite-plugin-web-extension/test/manifest/resources/devtoolsHtml/devtools.js": { 31 | "code": "log("devtools");", 32 | "originalLength": 53, 33 | "removedExports": [], 34 | "renderedExports": [], 35 | "renderedLength": 16, 36 | }, 37 | "vite-plugin-web-extension/test/manifest/resources/shared/log.js": { 38 | "code": "function log(message) { 39 | console.log(message); 40 | }", 41 | "originalLength": 65, 42 | "removedExports": [], 43 | "renderedExports": [ 44 | "default", 45 | ], 46 | "renderedLength": 49, 47 | }, 48 | }, 49 | "name": "test/manifest/resources/devtoolsHtml/devtools", 50 | "referencedFiles": [], 51 | "type": "chunk", 52 | "viteMetadata": { 53 | "importedAssets": Set {}, 54 | "importedCss": Set {}, 55 | }, 56 | }, 57 | { 58 | "fileName": "manifest.json", 59 | "name": undefined, 60 | "source": "{ 61 | "version": "1.0.0", 62 | "name": "Manifest Name", 63 | "manifest_version": 2, 64 | "devtools_page": "test/manifest/resources/devtoolsHtml/devtools.html" 65 | }", 66 | "type": "asset", 67 | }, 68 | { 69 | "fileName": "test/manifest/resources/devtoolsHtml/devtools.html", 70 | "name": undefined, 71 | "source": " 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | ", 81 | "type": "asset", 82 | }, 83 | ] 84 | `; 85 | -------------------------------------------------------------------------------- /test/manifest/__snapshots__/devtoolsHtml.v3.test.ts.snap: -------------------------------------------------------------------------------- 1 | // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html 2 | 3 | exports[`devtoolsHtml - Manifest V3 1`] = ` 4 | [ 5 | { 6 | "code": "function log(message) { 7 | console.log(message); 8 | } 9 | log("devtools"); 10 | ", 11 | "dynamicImports": [], 12 | "exports": [], 13 | "facadeModuleId": "vite-plugin-web-extension/test/manifest/resources/devtoolsHtml/devtools.html", 14 | "fileName": "assets/test/manifest/resources/devtoolsHtml/devtools.js", 15 | "implicitlyLoadedBefore": [], 16 | "importedBindings": {}, 17 | "imports": [], 18 | "isDynamicEntry": false, 19 | "isEntry": true, 20 | "isImplicitEntry": false, 21 | "map": null, 22 | "modules": { 23 | "vite-plugin-web-extension/test/manifest/resources/devtoolsHtml/devtools.html": { 24 | "code": "", 25 | "originalLength": 227, 26 | "removedExports": [], 27 | "renderedExports": [], 28 | "renderedLength": 0, 29 | }, 30 | "vite-plugin-web-extension/test/manifest/resources/devtoolsHtml/devtools.js": { 31 | "code": "log("devtools");", 32 | "originalLength": 53, 33 | "removedExports": [], 34 | "renderedExports": [], 35 | "renderedLength": 16, 36 | }, 37 | "vite-plugin-web-extension/test/manifest/resources/shared/log.js": { 38 | "code": "function log(message) { 39 | console.log(message); 40 | }", 41 | "originalLength": 65, 42 | "removedExports": [], 43 | "renderedExports": [ 44 | "default", 45 | ], 46 | "renderedLength": 49, 47 | }, 48 | }, 49 | "name": "test/manifest/resources/devtoolsHtml/devtools", 50 | "referencedFiles": [], 51 | "type": "chunk", 52 | "viteMetadata": { 53 | "importedAssets": Set {}, 54 | "importedCss": Set {}, 55 | }, 56 | }, 57 | { 58 | "fileName": "manifest.json", 59 | "name": undefined, 60 | "source": "{ 61 | "version": "1.0.0", 62 | "name": "Manifest Name", 63 | "manifest_version": 3, 64 | "devtools_page": "test/manifest/resources/devtoolsHtml/devtools.html" 65 | }", 66 | "type": "asset", 67 | }, 68 | { 69 | "fileName": "test/manifest/resources/devtoolsHtml/devtools.html", 70 | "name": undefined, 71 | "source": " 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | ", 81 | "type": "asset", 82 | }, 83 | ] 84 | `; 85 | -------------------------------------------------------------------------------- /test/manifest/__snapshots__/optionsHtml.v2.test.ts.snap: -------------------------------------------------------------------------------- 1 | // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html 2 | 3 | exports[`optionsHtml - Manifest V2 1`] = ` 4 | [ 5 | { 6 | "code": "function log(message) { 7 | console.log(message); 8 | } 9 | log("options"); 10 | ", 11 | "dynamicImports": [], 12 | "exports": [], 13 | "facadeModuleId": "vite-plugin-web-extension/test/manifest/resources/optionsHtml/options.html", 14 | "fileName": "assets/test/manifest/resources/optionsHtml/options.js", 15 | "implicitlyLoadedBefore": [], 16 | "importedBindings": {}, 17 | "imports": [], 18 | "isDynamicEntry": false, 19 | "isEntry": true, 20 | "isImplicitEntry": false, 21 | "map": null, 22 | "modules": { 23 | "vite-plugin-web-extension/test/manifest/resources/optionsHtml/options.html": { 24 | "code": "", 25 | "originalLength": 226, 26 | "removedExports": [], 27 | "renderedExports": [], 28 | "renderedLength": 0, 29 | }, 30 | "vite-plugin-web-extension/test/manifest/resources/optionsHtml/options.js": { 31 | "code": "log("options");", 32 | "originalLength": 52, 33 | "removedExports": [], 34 | "renderedExports": [], 35 | "renderedLength": 15, 36 | }, 37 | "vite-plugin-web-extension/test/manifest/resources/shared/log.js": { 38 | "code": "function log(message) { 39 | console.log(message); 40 | }", 41 | "originalLength": 65, 42 | "removedExports": [], 43 | "renderedExports": [ 44 | "default", 45 | ], 46 | "renderedLength": 49, 47 | }, 48 | }, 49 | "name": "test/manifest/resources/optionsHtml/options", 50 | "referencedFiles": [], 51 | "type": "chunk", 52 | "viteMetadata": { 53 | "importedAssets": Set {}, 54 | "importedCss": Set {}, 55 | }, 56 | }, 57 | { 58 | "fileName": "manifest.json", 59 | "name": undefined, 60 | "source": "{ 61 | "version": "1.0.0", 62 | "name": "Manifest Name", 63 | "manifest_version": 2, 64 | "options_ui": { 65 | "page": "test/manifest/resources/optionsHtml/options.html" 66 | } 67 | }", 68 | "type": "asset", 69 | }, 70 | { 71 | "fileName": "test/manifest/resources/optionsHtml/options.html", 72 | "name": undefined, 73 | "source": " 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | ", 83 | "type": "asset", 84 | }, 85 | ] 86 | `; 87 | -------------------------------------------------------------------------------- /test/manifest/__snapshots__/optionsHtml.v3.test.ts.snap: -------------------------------------------------------------------------------- 1 | // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html 2 | 3 | exports[`optionsHtml - Manifest V3 1`] = ` 4 | [ 5 | { 6 | "code": "function log(message) { 7 | console.log(message); 8 | } 9 | log("options"); 10 | ", 11 | "dynamicImports": [], 12 | "exports": [], 13 | "facadeModuleId": "vite-plugin-web-extension/test/manifest/resources/optionsHtml/options.html", 14 | "fileName": "assets/test/manifest/resources/optionsHtml/options.js", 15 | "implicitlyLoadedBefore": [], 16 | "importedBindings": {}, 17 | "imports": [], 18 | "isDynamicEntry": false, 19 | "isEntry": true, 20 | "isImplicitEntry": false, 21 | "map": null, 22 | "modules": { 23 | "vite-plugin-web-extension/test/manifest/resources/optionsHtml/options.html": { 24 | "code": "", 25 | "originalLength": 226, 26 | "removedExports": [], 27 | "renderedExports": [], 28 | "renderedLength": 0, 29 | }, 30 | "vite-plugin-web-extension/test/manifest/resources/optionsHtml/options.js": { 31 | "code": "log("options");", 32 | "originalLength": 52, 33 | "removedExports": [], 34 | "renderedExports": [], 35 | "renderedLength": 15, 36 | }, 37 | "vite-plugin-web-extension/test/manifest/resources/shared/log.js": { 38 | "code": "function log(message) { 39 | console.log(message); 40 | }", 41 | "originalLength": 65, 42 | "removedExports": [], 43 | "renderedExports": [ 44 | "default", 45 | ], 46 | "renderedLength": 49, 47 | }, 48 | }, 49 | "name": "test/manifest/resources/optionsHtml/options", 50 | "referencedFiles": [], 51 | "type": "chunk", 52 | "viteMetadata": { 53 | "importedAssets": Set {}, 54 | "importedCss": Set {}, 55 | }, 56 | }, 57 | { 58 | "fileName": "manifest.json", 59 | "name": undefined, 60 | "source": "{ 61 | "version": "1.0.0", 62 | "name": "Manifest Name", 63 | "manifest_version": 3, 64 | "options_ui": { 65 | "page": "test/manifest/resources/optionsHtml/options.html" 66 | } 67 | }", 68 | "type": "asset", 69 | }, 70 | { 71 | "fileName": "test/manifest/resources/optionsHtml/options.html", 72 | "name": undefined, 73 | "source": " 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | ", 83 | "type": "asset", 84 | }, 85 | ] 86 | `; 87 | -------------------------------------------------------------------------------- /test/manifest/__snapshots__/popupHtml.v2.test.ts.snap: -------------------------------------------------------------------------------- 1 | // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html 2 | 3 | exports[`popupHtml - Manifest V2 1`] = ` 4 | [ 5 | { 6 | "code": "function log(message) { 7 | console.log(message); 8 | } 9 | log("popup"); 10 | ", 11 | "dynamicImports": [], 12 | "exports": [], 13 | "facadeModuleId": "vite-plugin-web-extension/test/manifest/resources/popupHtml/popup.html", 14 | "fileName": "assets/test/manifest/resources/popupHtml/popup.js", 15 | "implicitlyLoadedBefore": [], 16 | "importedBindings": {}, 17 | "imports": [], 18 | "isDynamicEntry": false, 19 | "isEntry": true, 20 | "isImplicitEntry": false, 21 | "map": null, 22 | "modules": { 23 | "vite-plugin-web-extension/test/manifest/resources/popupHtml/popup.html": { 24 | "code": "", 25 | "originalLength": 224, 26 | "removedExports": [], 27 | "renderedExports": [], 28 | "renderedLength": 0, 29 | }, 30 | "vite-plugin-web-extension/test/manifest/resources/popupHtml/popup.js": { 31 | "code": "log("popup");", 32 | "originalLength": 50, 33 | "removedExports": [], 34 | "renderedExports": [], 35 | "renderedLength": 13, 36 | }, 37 | "vite-plugin-web-extension/test/manifest/resources/shared/log.js": { 38 | "code": "function log(message) { 39 | console.log(message); 40 | }", 41 | "originalLength": 65, 42 | "removedExports": [], 43 | "renderedExports": [ 44 | "default", 45 | ], 46 | "renderedLength": 49, 47 | }, 48 | }, 49 | "name": "test/manifest/resources/popupHtml/popup", 50 | "referencedFiles": [], 51 | "type": "chunk", 52 | "viteMetadata": { 53 | "importedAssets": Set {}, 54 | "importedCss": Set {}, 55 | }, 56 | }, 57 | { 58 | "fileName": "manifest.json", 59 | "name": undefined, 60 | "source": "{ 61 | "version": "1.0.0", 62 | "name": "Manifest Name", 63 | "manifest_version": 2, 64 | "browser_action": { 65 | "default_popup": "test/manifest/resources/popupHtml/popup.html" 66 | } 67 | }", 68 | "type": "asset", 69 | }, 70 | { 71 | "fileName": "test/manifest/resources/popupHtml/popup.html", 72 | "name": undefined, 73 | "source": " 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | ", 83 | "type": "asset", 84 | }, 85 | ] 86 | `; 87 | -------------------------------------------------------------------------------- /test/manifest/__snapshots__/popupHtml.v3.test.ts.snap: -------------------------------------------------------------------------------- 1 | // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html 2 | 3 | exports[`popupHtml - Manifest V3 1`] = ` 4 | [ 5 | { 6 | "code": "function log(message) { 7 | console.log(message); 8 | } 9 | log("popup"); 10 | ", 11 | "dynamicImports": [], 12 | "exports": [], 13 | "facadeModuleId": "vite-plugin-web-extension/test/manifest/resources/popupHtml/popup.html", 14 | "fileName": "assets/test/manifest/resources/popupHtml/popup.js", 15 | "implicitlyLoadedBefore": [], 16 | "importedBindings": {}, 17 | "imports": [], 18 | "isDynamicEntry": false, 19 | "isEntry": true, 20 | "isImplicitEntry": false, 21 | "map": null, 22 | "modules": { 23 | "vite-plugin-web-extension/test/manifest/resources/popupHtml/popup.html": { 24 | "code": "", 25 | "originalLength": 224, 26 | "removedExports": [], 27 | "renderedExports": [], 28 | "renderedLength": 0, 29 | }, 30 | "vite-plugin-web-extension/test/manifest/resources/popupHtml/popup.js": { 31 | "code": "log("popup");", 32 | "originalLength": 50, 33 | "removedExports": [], 34 | "renderedExports": [], 35 | "renderedLength": 13, 36 | }, 37 | "vite-plugin-web-extension/test/manifest/resources/shared/log.js": { 38 | "code": "function log(message) { 39 | console.log(message); 40 | }", 41 | "originalLength": 65, 42 | "removedExports": [], 43 | "renderedExports": [ 44 | "default", 45 | ], 46 | "renderedLength": 49, 47 | }, 48 | }, 49 | "name": "test/manifest/resources/popupHtml/popup", 50 | "referencedFiles": [], 51 | "type": "chunk", 52 | "viteMetadata": { 53 | "importedAssets": Set {}, 54 | "importedCss": Set {}, 55 | }, 56 | }, 57 | { 58 | "fileName": "manifest.json", 59 | "name": undefined, 60 | "source": "{ 61 | "version": "1.0.0", 62 | "name": "Manifest Name", 63 | "manifest_version": 3, 64 | "action": { 65 | "default_popup": "test/manifest/resources/popupHtml/popup.html" 66 | } 67 | }", 68 | "type": "asset", 69 | }, 70 | { 71 | "fileName": "test/manifest/resources/popupHtml/popup.html", 72 | "name": undefined, 73 | "source": " 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | ", 83 | "type": "asset", 84 | }, 85 | ] 86 | `; 87 | -------------------------------------------------------------------------------- /test/manifest/__snapshots__/sidePanelHtml.v3.test.ts.snap: -------------------------------------------------------------------------------- 1 | // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html 2 | 3 | exports[`sidePanelHtml - Manifest V3 1`] = ` 4 | [ 5 | { 6 | "code": "function log(message) { 7 | console.log(message); 8 | } 9 | log("sidepanel"); 10 | ", 11 | "dynamicImports": [], 12 | "exports": [], 13 | "facadeModuleId": "vite-plugin-web-extension/test/manifest/resources/sidePanelHtml/sidepanel.html", 14 | "fileName": "assets/test/manifest/resources/sidePanelHtml/sidepanel.js", 15 | "implicitlyLoadedBefore": [], 16 | "importedBindings": {}, 17 | "imports": [], 18 | "isDynamicEntry": false, 19 | "isEntry": true, 20 | "isImplicitEntry": false, 21 | "map": null, 22 | "modules": { 23 | "vite-plugin-web-extension/test/manifest/resources/shared/log.js": { 24 | "code": "function log(message) { 25 | console.log(message); 26 | }", 27 | "originalLength": 65, 28 | "removedExports": [], 29 | "renderedExports": [ 30 | "default", 31 | ], 32 | "renderedLength": 49, 33 | }, 34 | "vite-plugin-web-extension/test/manifest/resources/sidePanelHtml/sidepanel.html": { 35 | "code": "", 36 | "originalLength": 228, 37 | "removedExports": [], 38 | "renderedExports": [], 39 | "renderedLength": 0, 40 | }, 41 | "vite-plugin-web-extension/test/manifest/resources/sidePanelHtml/sidepanel.js": { 42 | "code": "log("sidepanel");", 43 | "originalLength": 54, 44 | "removedExports": [], 45 | "renderedExports": [], 46 | "renderedLength": 17, 47 | }, 48 | }, 49 | "name": "test/manifest/resources/sidePanelHtml/sidepanel", 50 | "referencedFiles": [], 51 | "type": "chunk", 52 | "viteMetadata": { 53 | "importedAssets": Set {}, 54 | "importedCss": Set {}, 55 | }, 56 | }, 57 | { 58 | "fileName": "manifest.json", 59 | "name": undefined, 60 | "source": "{ 61 | "version": "1.0.0", 62 | "name": "Manifest Name", 63 | "manifest_version": 3, 64 | "side_panel": { 65 | "default_path": "test/manifest/resources/sidePanelHtml/sidepanel.html" 66 | } 67 | }", 68 | "type": "asset", 69 | }, 70 | { 71 | "fileName": "test/manifest/resources/sidePanelHtml/sidepanel.html", 72 | "name": undefined, 73 | "source": " 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | ", 83 | "type": "asset", 84 | }, 85 | ] 86 | `; 87 | -------------------------------------------------------------------------------- /test/manifest/additionalInputsHtml.v2.test.ts: -------------------------------------------------------------------------------- 1 | import { getResourceDir, runManifestV2Test } from "./manifestTestUtils"; 2 | 3 | const resourceDir = getResourceDir("additionalInputsHtml"); 4 | 5 | runManifestV2Test("additionalInputsHtml", () => ({}), { 6 | additionalInputs: { 7 | html: [`${resourceDir}/html.html`], 8 | }, 9 | }); 10 | -------------------------------------------------------------------------------- /test/manifest/additionalInputsHtml.v3.test.ts: -------------------------------------------------------------------------------- 1 | import { getResourceDir, runManifestV3Test } from "./manifestTestUtils"; 2 | 3 | const resourceDir = getResourceDir("additionalInputsHtml"); 4 | 5 | runManifestV3Test("additionalInputsHtml", () => ({}), { 6 | additionalInputs: { 7 | html: [`${resourceDir}/html.html`], 8 | }, 9 | }); 10 | -------------------------------------------------------------------------------- /test/manifest/additionalInputsScriptsChunkedImport.v2.test.ts: -------------------------------------------------------------------------------- 1 | import { getResourceDir, runManifestV2Test } from "./manifestTestUtils"; 2 | 3 | const resourceDir = getResourceDir("additionalInputsScriptsChunkedImport"); 4 | 5 | runManifestV2Test("additionalInputsScriptsChunkedImport", () => ({}), { 6 | additionalInputs: { 7 | scripts: [`${resourceDir}/script1.js`, `${resourceDir}/script2.js`], 8 | }, 9 | }); 10 | -------------------------------------------------------------------------------- /test/manifest/additionalInputsScriptsChunkedImport.v3.test.ts: -------------------------------------------------------------------------------- 1 | import { getResourceDir, runManifestV3Test } from "./manifestTestUtils"; 2 | 3 | const resourceDir = getResourceDir("additionalInputsScriptsChunkedImport"); 4 | 5 | runManifestV3Test("additionalInputsScriptsChunkedImport", () => ({}), { 6 | additionalInputs: { 7 | scripts: [`${resourceDir}/script1.js`, `${resourceDir}/script2.js`], 8 | }, 9 | }); 10 | -------------------------------------------------------------------------------- /test/manifest/additionalInputsScriptsNoImport.v2.test.ts: -------------------------------------------------------------------------------- 1 | import { getResourceDir, runManifestV2Test } from "./manifestTestUtils"; 2 | 3 | const resourceDir = getResourceDir("additionalInputsScriptsNoImport"); 4 | 5 | runManifestV2Test("additionalInputsScriptsNoImport", () => ({}), { 6 | additionalInputs: { 7 | scripts: [`${resourceDir}/script1.js`, `${resourceDir}/script2.js`], 8 | }, 9 | }); 10 | -------------------------------------------------------------------------------- /test/manifest/additionalInputsScriptsNoImport.v3.test.ts: -------------------------------------------------------------------------------- 1 | import { getResourceDir, runManifestV3Test } from "./manifestTestUtils"; 2 | 3 | const resourceDir = getResourceDir("additionalInputsScriptsNoImport"); 4 | 5 | runManifestV3Test("additionalInputsScriptsNoImport", () => ({}), { 6 | additionalInputs: { 7 | scripts: [`${resourceDir}/script1.js`, `${resourceDir}/script2.js`], 8 | }, 9 | }); 10 | -------------------------------------------------------------------------------- /test/manifest/additionalInputsScriptsTypes.v2.test.ts: -------------------------------------------------------------------------------- 1 | import { getResourceDir, runManifestV2Test } from "./manifestTestUtils"; 2 | 3 | const resourceDir = getResourceDir("additionalInputsScriptsTypes"); 4 | 5 | runManifestV2Test("additionalInputsScriptsTypes", () => ({}), { 6 | additionalInputs: { 7 | scripts: [`${resourceDir}/script1.js`, `${resourceDir}/script2.ts`], 8 | }, 9 | }); 10 | -------------------------------------------------------------------------------- /test/manifest/additionalInputsScriptsTypes.v3.test.ts: -------------------------------------------------------------------------------- 1 | import { getResourceDir, runManifestV3Test } from "./manifestTestUtils"; 2 | 3 | const resourceDir = getResourceDir("additionalInputsScriptsTypes"); 4 | 5 | runManifestV3Test("additionalInputsScriptsTypes", () => ({}), { 6 | additionalInputs: { 7 | scripts: [`${resourceDir}/script1.js`, `${resourceDir}/script2.ts`], 8 | }, 9 | }); 10 | -------------------------------------------------------------------------------- /test/manifest/additionalInputsScriptsUnchunkedImport.v2.test.ts: -------------------------------------------------------------------------------- 1 | import { getResourceDir, runManifestV2Test } from "./manifestTestUtils"; 2 | 3 | const resourceDir = getResourceDir("additionalInputsScriptsUnchunkedImport"); 4 | 5 | runManifestV2Test("additionalInputsScriptsUnchunkedImport", () => ({}), { 6 | additionalInputs: { 7 | scripts: [`${resourceDir}/script1.js`, `${resourceDir}/script2.js`], 8 | }, 9 | }); 10 | -------------------------------------------------------------------------------- /test/manifest/additionalInputsScriptsUnchunkedImport.v3.test.ts: -------------------------------------------------------------------------------- 1 | import { getResourceDir, runManifestV3Test } from "./manifestTestUtils"; 2 | 3 | const resourceDir = getResourceDir("additionalInputsScriptsUnchunkedImport"); 4 | 5 | runManifestV3Test("additionalInputsScriptsUnchunkedImport", () => ({}), { 6 | additionalInputs: { 7 | scripts: [`${resourceDir}/script1.js`, `${resourceDir}/script2.js`], 8 | }, 9 | }); 10 | -------------------------------------------------------------------------------- /test/manifest/additionalInputsStylesTypes.v2.test.ts: -------------------------------------------------------------------------------- 1 | import { getResourceDir, runManifestV2Test } from "./manifestTestUtils"; 2 | 3 | const resourceDir = getResourceDir("additionalInputsStylesTypes"); 4 | 5 | runManifestV2Test("additionalInputsStylesTypes", () => ({}), { 6 | additionalInputs: { 7 | styles: [`${resourceDir}/style1.css`, `${resourceDir}/style2.scss`], 8 | }, 9 | }); 10 | -------------------------------------------------------------------------------- /test/manifest/additionalInputsStylesTypes.v3.test.ts: -------------------------------------------------------------------------------- 1 | import { getResourceDir, runManifestV3Test } from "./manifestTestUtils"; 2 | 3 | const resourceDir = getResourceDir("additionalInputsStylesTypes"); 4 | 5 | runManifestV3Test("additionalInputsStylesTypes", () => ({}), { 6 | additionalInputs: { 7 | styles: [`${resourceDir}/style1.css`, `${resourceDir}/style2.scss`], 8 | }, 9 | }); 10 | -------------------------------------------------------------------------------- /test/manifest/additionalInputsWebAccessible.v2.test.ts: -------------------------------------------------------------------------------- 1 | import { getResourceDir, runManifestV2Test } from "./manifestTestUtils"; 2 | 3 | const resourceDir = getResourceDir("additionalInputsWebAccessible"); 4 | 5 | runManifestV2Test("additionalInputsWebAccessible", () => ({}), { 6 | additionalInputs: { 7 | scripts: [ 8 | `${resourceDir}/script1.js`, 9 | { 10 | fileName: `${resourceDir}/script2.js`, 11 | webAccessible: false, 12 | }, 13 | { 14 | fileName: `${resourceDir}/script3.js`, 15 | webAccessible: true, 16 | }, 17 | { 18 | fileName: `${resourceDir}/script4.js`, 19 | webAccessible: { 20 | matches: ["https://example.com/"], 21 | }, 22 | }, 23 | { 24 | fileName: `${resourceDir}/script5.ts`, 25 | webAccessible: { 26 | extensionIds: ["oilkjaldkfjlasdf"], 27 | }, 28 | }, 29 | { 30 | fileName: `${resourceDir}/chunkedScript1.js`, 31 | webAccessible: { 32 | matches: ["https://example.com/"], 33 | }, 34 | }, 35 | { 36 | fileName: `${resourceDir}/chunkedScript2.js`, 37 | webAccessible: { 38 | matches: ["https://example.com/"], 39 | }, 40 | }, 41 | { 42 | fileName: `${resourceDir}/chunkedScript3.js`, 43 | webAccessible: { 44 | extensionIds: ["oilkjaldkfjlasdf"], 45 | }, 46 | }, 47 | ], 48 | }, 49 | }); 50 | -------------------------------------------------------------------------------- /test/manifest/additionalInputsWebAccessible.v3.test.ts: -------------------------------------------------------------------------------- 1 | import { getResourceDir, runManifestV3Test } from "./manifestTestUtils"; 2 | 3 | const resourceDir = getResourceDir("additionalInputsWebAccessible"); 4 | 5 | runManifestV3Test("additionalInputsWebAccessible", () => ({}), { 6 | additionalInputs: { 7 | scripts: [ 8 | `${resourceDir}/script1.js`, 9 | { 10 | fileName: `${resourceDir}/script2.js`, 11 | webAccessible: false, 12 | }, 13 | { 14 | fileName: `${resourceDir}/script3.js`, 15 | webAccessible: true, 16 | }, 17 | { 18 | fileName: `${resourceDir}/script4.js`, 19 | webAccessible: { 20 | matches: ["https://example.com/"], 21 | }, 22 | }, 23 | { 24 | fileName: `${resourceDir}/script5.ts`, 25 | webAccessible: { 26 | extensionIds: ["oilkjaldkfjlasdf"], 27 | }, 28 | }, 29 | { 30 | fileName: `${resourceDir}/chunkedScript1.js`, 31 | webAccessible: { 32 | matches: ["https://example.com/"], 33 | }, 34 | }, 35 | { 36 | fileName: `${resourceDir}/chunkedScript2.js`, 37 | webAccessible: { 38 | matches: ["https://example.com/"], 39 | }, 40 | }, 41 | { 42 | fileName: `${resourceDir}/chunkedScript3.js`, 43 | webAccessible: { 44 | extensionIds: ["oilkjaldkfjlasdf"], 45 | }, 46 | }, 47 | ], 48 | }, 49 | }); 50 | -------------------------------------------------------------------------------- /test/manifest/additionalInputsWebAccessibleExcludeEntryFile.v2.test.ts: -------------------------------------------------------------------------------- 1 | import { getResourceDir, runManifestV2Test } from "./manifestTestUtils"; 2 | 3 | const resourceDir = getResourceDir("additionalInputsWebAccessible"); 4 | 5 | runManifestV2Test("additionalInputsWebAccessible", () => ({}), { 6 | additionalInputs: { 7 | scripts: [ 8 | `${resourceDir}/script1.js`, 9 | { 10 | fileName: `${resourceDir}/script2.js`, 11 | webAccessible: { 12 | matches: ["https://example.com/"], 13 | }, 14 | }, 15 | { 16 | fileName: `${resourceDir}/script3.js`, 17 | webAccessible: { 18 | matches: ["https://example.com/"], 19 | excludeEntryFile: false, 20 | }, 21 | }, 22 | { 23 | fileName: `${resourceDir}/script4.js`, 24 | webAccessible: { 25 | matches: ["https://example.com/"], 26 | excludeEntryFile: true, 27 | }, 28 | }, 29 | { 30 | fileName: `${resourceDir}/script5.ts`, 31 | webAccessible: { 32 | extensionIds: ["oilkjaldkfjlasdf"], 33 | }, 34 | }, 35 | { 36 | fileName: `${resourceDir}/script6.js`, 37 | webAccessible: { 38 | extensionIds: ["oilkjaldkfjlasdf"], 39 | excludeEntryFile: false, 40 | }, 41 | }, 42 | { 43 | fileName: `${resourceDir}/script7.js`, 44 | webAccessible: { 45 | extensionIds: ["oilkjaldkfjlasdf"], 46 | excludeEntryFile: true, 47 | }, 48 | }, 49 | { 50 | fileName: `${resourceDir}/chunkedScript1.js`, 51 | webAccessible: { 52 | matches: ["https://example.com/"], 53 | }, 54 | }, 55 | { 56 | fileName: `${resourceDir}/chunkedScript2.js`, 57 | webAccessible: { 58 | matches: ["https://example.com/"], 59 | excludeEntryFile: false, 60 | }, 61 | }, 62 | { 63 | fileName: `${resourceDir}/chunkedScript3.js`, 64 | webAccessible: { 65 | matches: ["https://example.com/"], 66 | excludeEntryFile: true, 67 | }, 68 | }, 69 | ], 70 | }, 71 | }); 72 | -------------------------------------------------------------------------------- /test/manifest/additionalInputsWebAccessibleExcludeEntryFile.v3.test.ts: -------------------------------------------------------------------------------- 1 | import { getResourceDir, runManifestV3Test } from "./manifestTestUtils"; 2 | 3 | const resourceDir = getResourceDir("additionalInputsWebAccessible"); 4 | 5 | runManifestV3Test("additionalInputsWebAccessible", () => ({}), { 6 | additionalInputs: { 7 | scripts: [ 8 | `${resourceDir}/script1.js`, 9 | { 10 | fileName: `${resourceDir}/script2.js`, 11 | webAccessible: { 12 | matches: ["https://example.com/"], 13 | }, 14 | }, 15 | { 16 | fileName: `${resourceDir}/script3.js`, 17 | webAccessible: { 18 | matches: ["https://example.com/"], 19 | excludeEntryFile: false, 20 | }, 21 | }, 22 | { 23 | fileName: `${resourceDir}/script4.js`, 24 | webAccessible: { 25 | matches: ["https://example.com/"], 26 | excludeEntryFile: true, 27 | }, 28 | }, 29 | { 30 | fileName: `${resourceDir}/script5.ts`, 31 | webAccessible: { 32 | extensionIds: ["oilkjaldkfjlasdf"], 33 | }, 34 | }, 35 | { 36 | fileName: `${resourceDir}/script6.js`, 37 | webAccessible: { 38 | extensionIds: ["oilkjaldkfjlasdf"], 39 | excludeEntryFile: false, 40 | }, 41 | }, 42 | { 43 | fileName: `${resourceDir}/script7.js`, 44 | webAccessible: { 45 | extensionIds: ["oilkjaldkfjlasdf"], 46 | excludeEntryFile: true, 47 | }, 48 | }, 49 | { 50 | fileName: `${resourceDir}/chunkedScript1.js`, 51 | webAccessible: { 52 | matches: ["https://example.com/"], 53 | }, 54 | }, 55 | { 56 | fileName: `${resourceDir}/chunkedScript2.js`, 57 | webAccessible: { 58 | matches: ["https://example.com/"], 59 | excludeEntryFile: false, 60 | }, 61 | }, 62 | { 63 | fileName: `${resourceDir}/chunkedScript3.js`, 64 | webAccessible: { 65 | matches: ["https://example.com/"], 66 | excludeEntryFile: true, 67 | }, 68 | }, 69 | ], 70 | }, 71 | }); 72 | -------------------------------------------------------------------------------- /test/manifest/backgroundHtml.v2.test.ts: -------------------------------------------------------------------------------- 1 | import { getResourceDir, runManifestV2Test } from "./manifestTestUtils"; 2 | 3 | const resourceDir = getResourceDir("backgroundHtml"); 4 | 5 | runManifestV2Test("backgroundHtml", () => ({ 6 | background: { 7 | page: `${resourceDir}/background.html`, 8 | persistent: false, 9 | }, 10 | })); 11 | -------------------------------------------------------------------------------- /test/manifest/backgroundScript.v2.test.ts: -------------------------------------------------------------------------------- 1 | import { getResourceDir, runManifestV2Test } from "./manifestTestUtils"; 2 | 3 | const resourceDir = getResourceDir("backgroundScript"); 4 | 5 | runManifestV2Test("backgroundScript", () => ({ 6 | background: { 7 | scripts: [`/${resourceDir}/background.js`], 8 | persistent: false, 9 | }, 10 | })); 11 | -------------------------------------------------------------------------------- /test/manifest/backgroundServiceWorker.v3.test.ts: -------------------------------------------------------------------------------- 1 | import { getResourceDir, runManifestV3Test } from "./manifestTestUtils"; 2 | 3 | const resourceDir = getResourceDir("backgroundServiceWorker"); 4 | 5 | runManifestV3Test("backgroundServiceWorker", () => ({ 6 | background: { 7 | service_worker: `${resourceDir}/serviceWorker.js`, 8 | }, 9 | })); 10 | -------------------------------------------------------------------------------- /test/manifest/backgroundServiceWorkerRelative.v3.test.ts: -------------------------------------------------------------------------------- 1 | import { getResourceDir, runManifestV3Test } from "./manifestTestUtils"; 2 | 3 | const resourceDir = getResourceDir("backgroundServiceWorker"); 4 | const resourceDirRelative = `./${resourceDir}`; 5 | 6 | runManifestV3Test("backgroundServiceWorker", () => ({ 7 | background: { 8 | service_worker: `${resourceDirRelative}/serviceWorker.js`, 9 | }, 10 | })); 11 | -------------------------------------------------------------------------------- /test/manifest/backgroundServiceWorkerRoot.v3.test.ts: -------------------------------------------------------------------------------- 1 | import { getResourceDir, runManifestV3Test } from "./manifestTestUtils"; 2 | 3 | const resourceDir = getResourceDir("backgroundServiceWorker"); 4 | const resourceDirRoot = `/${resourceDir}`; 5 | 6 | runManifestV3Test("backgroundServiceWorker", () => ({ 7 | background: { 8 | service_worker: `${resourceDirRoot}/serviceWorker.js`, 9 | }, 10 | })); 11 | -------------------------------------------------------------------------------- /test/manifest/chromeUrlOverridesHtmlBookmarks.v2.test.ts: -------------------------------------------------------------------------------- 1 | import { getResourceDir, runManifestV2Test } from "./manifestTestUtils"; 2 | 3 | const resourceDir = getResourceDir("chromeUrlOverridesHtml"); 4 | 5 | runManifestV2Test("chromeUrlOverridesHtmlBookmarks", () => ({ 6 | chrome_url_overrides: { 7 | bookmarks: `${resourceDir}/bookmarks.html`, 8 | }, 9 | })); 10 | -------------------------------------------------------------------------------- /test/manifest/chromeUrlOverridesHtmlBookmarks.v3.test.ts: -------------------------------------------------------------------------------- 1 | import { getResourceDir, runManifestV3Test } from "./manifestTestUtils"; 2 | 3 | const resourceDir = getResourceDir("chromeUrlOverridesHtml"); 4 | 5 | runManifestV3Test("chromeUrlOverridesHtmlBookmarks", () => ({ 6 | chrome_url_overrides: { 7 | bookmarks: `${resourceDir}/bookmarks.html`, 8 | }, 9 | })); 10 | -------------------------------------------------------------------------------- /test/manifest/chromeUrlOverridesHtmlHistory.v2.test.ts: -------------------------------------------------------------------------------- 1 | import { getResourceDir, runManifestV2Test } from "./manifestTestUtils"; 2 | 3 | const resourceDir = getResourceDir("chromeUrlOverridesHtml"); 4 | 5 | runManifestV2Test("chromeUrlOverridesHtmlHistory", () => ({ 6 | chrome_url_overrides: { 7 | history: `${resourceDir}/history.html`, 8 | }, 9 | })); 10 | -------------------------------------------------------------------------------- /test/manifest/chromeUrlOverridesHtmlHistory.v3.test.ts: -------------------------------------------------------------------------------- 1 | import { getResourceDir, runManifestV3Test } from "./manifestTestUtils"; 2 | 3 | const resourceDir = getResourceDir("chromeUrlOverridesHtml"); 4 | 5 | runManifestV3Test("chromeUrlOverridesHtmlHistory", () => ({ 6 | chrome_url_overrides: { 7 | history: `${resourceDir}/history.html`, 8 | }, 9 | })); 10 | -------------------------------------------------------------------------------- /test/manifest/chromeUrlOverridesHtmlNewTab.v2.test.ts: -------------------------------------------------------------------------------- 1 | import { getResourceDir, runManifestV2Test } from "./manifestTestUtils"; 2 | 3 | const resourceDir = getResourceDir("chromeUrlOverridesHtml"); 4 | 5 | runManifestV2Test("chromeUrlOverridesHtmlNewTab", () => ({ 6 | chrome_url_overrides: { 7 | newtab: `${resourceDir}/newtab.html`, 8 | }, 9 | })); 10 | -------------------------------------------------------------------------------- /test/manifest/chromeUrlOverridesHtmlNewTab.v3.test.ts: -------------------------------------------------------------------------------- 1 | import { getResourceDir, runManifestV3Test } from "./manifestTestUtils"; 2 | 3 | const resourceDir = getResourceDir("chromeUrlOverridesHtml"); 4 | 5 | runManifestV3Test("chromeUrlOverridesHtmlNewTab", () => ({ 6 | chrome_url_overrides: { 7 | newtab: `${resourceDir}/newtab.html`, 8 | }, 9 | })); 10 | -------------------------------------------------------------------------------- /test/manifest/chunkCssRewrite.v2.test.ts: -------------------------------------------------------------------------------- 1 | import { getResourceDir, runManifestV2Test } from "./manifestTestUtils"; 2 | 3 | const resourceDir = getResourceDir("chunkCssRewrite"); 4 | 5 | runManifestV2Test("chunkCssRewrite", () => ({ 6 | content_scripts: [ 7 | { 8 | js: [`${resourceDir}/content1.js`], 9 | matches: ["https://*/*", "http://*/*"], 10 | }, 11 | { 12 | js: [`${resourceDir}/content2.js`], 13 | matches: ["https://*/*", "http://*/*"], 14 | }, 15 | { 16 | js: [`${resourceDir}/contentNoCss.js`], 17 | matches: ["https://*/*", "http://*/*"], 18 | }, 19 | ], 20 | })); 21 | -------------------------------------------------------------------------------- /test/manifest/chunkCssRewrite.v3.test.ts: -------------------------------------------------------------------------------- 1 | import { getResourceDir, runManifestV3Test } from "./manifestTestUtils"; 2 | 3 | const resourceDir = getResourceDir("chunkCssRewrite"); 4 | 5 | runManifestV3Test("chunkCssRewrite", () => ({ 6 | content_scripts: [ 7 | { 8 | js: [`${resourceDir}/content1.js`], 9 | matches: ["https://*/*", "http://*/*"], 10 | }, 11 | { 12 | js: [`${resourceDir}/content2.js`], 13 | matches: ["https://*/*", "http://*/*"], 14 | }, 15 | { 16 | js: [`${resourceDir}/contentNoCss.js`], 17 | matches: ["https://*/*", "http://*/*"], 18 | }, 19 | ], 20 | })); 21 | -------------------------------------------------------------------------------- /test/manifest/contentCss.v2.test.ts: -------------------------------------------------------------------------------- 1 | import { getResourceDir, runManifestV2Test } from "./manifestTestUtils"; 2 | 3 | const resourceDir = getResourceDir("contentCss"); 4 | 5 | runManifestV2Test("contentCss", () => ({ 6 | content_scripts: [ 7 | { 8 | js: [`${resourceDir}/content.js`], 9 | css: [`${resourceDir}/content1.css`, `${resourceDir}/content2.scss`], 10 | matches: ["https://*/*", "http://*/*"], 11 | }, 12 | ], 13 | })); 14 | -------------------------------------------------------------------------------- /test/manifest/contentCss.v3.test.ts: -------------------------------------------------------------------------------- 1 | import { getResourceDir, runManifestV3Test } from "./manifestTestUtils"; 2 | 3 | const resourceDir = getResourceDir("contentCss"); 4 | 5 | runManifestV3Test("contentCss", () => ({ 6 | content_scripts: [ 7 | { 8 | js: [`${resourceDir}/content.js`], 9 | css: [`${resourceDir}/content1.css`, `${resourceDir}/content2.scss`], 10 | matches: ["https://*/*", "http://*/*"], 11 | }, 12 | ], 13 | })); 14 | -------------------------------------------------------------------------------- /test/manifest/contentScriptPaths.v2.test.ts: -------------------------------------------------------------------------------- 1 | import { getResourceDir, runManifestV2Test } from "./manifestTestUtils"; 2 | 3 | const resourceDir = getResourceDir("contentWithChunkedImport"); 4 | const resourceDirRoot = `/${resourceDir}`; 5 | const resourceDirRelative = `./${resourceDir}`; 6 | 7 | runManifestV2Test("contentScriptPaths", () => ({ 8 | content_scripts: [ 9 | { 10 | js: [`${resourceDirRoot}/content1.js`], 11 | matches: ["https://*/*", "http://*/*"], 12 | }, 13 | { 14 | js: [`${resourceDirRelative}/content2.js`], 15 | matches: ["https://*/*", "http://*/*"], 16 | }, 17 | ], 18 | })); 19 | -------------------------------------------------------------------------------- /test/manifest/contentScriptPaths.v3.test.ts: -------------------------------------------------------------------------------- 1 | import { getResourceDir, runManifestV3Test } from "./manifestTestUtils"; 2 | 3 | const resourceDir = getResourceDir("contentWithChunkedImport"); 4 | const resourceDirRoot = `/${resourceDir}`; 5 | const resourceDirRelative = `./${resourceDir}`; 6 | 7 | runManifestV3Test("contentScriptPaths", () => ({ 8 | content_scripts: [ 9 | { 10 | js: [`${resourceDirRoot}/content1.js`], 11 | matches: ["https://*/*", "http://*/*"], 12 | }, 13 | { 14 | js: [`${resourceDirRelative}/content2.js`], 15 | matches: ["https://*/*", "http://*/*"], 16 | }, 17 | ], 18 | })); 19 | -------------------------------------------------------------------------------- /test/manifest/contentScriptTypes.v2.test.ts: -------------------------------------------------------------------------------- 1 | import { getResourceDir, runManifestV2Test } from "./manifestTestUtils"; 2 | 3 | const resourceDir = getResourceDir("contentScriptTypes"); 4 | 5 | runManifestV2Test("contentScriptTypes", () => ({ 6 | content_scripts: [ 7 | { 8 | js: [`${resourceDir}/content1.js`], 9 | matches: ["https://example.com/"], 10 | }, 11 | { 12 | js: [`${resourceDir}/content2.ts`], 13 | matches: ["https://example.com/"], 14 | }, 15 | ], 16 | })); 17 | -------------------------------------------------------------------------------- /test/manifest/contentScriptTypes.v3.test.ts: -------------------------------------------------------------------------------- 1 | import { getResourceDir, runManifestV3Test } from "./manifestTestUtils"; 2 | 3 | const resourceDir = getResourceDir("contentScriptTypes"); 4 | 5 | runManifestV3Test("contentScriptTypes", () => ({ 6 | content_scripts: [ 7 | { 8 | js: [`${resourceDir}/content1.js`], 9 | matches: ["https://example.com/"], 10 | }, 11 | { 12 | js: [`${resourceDir}/content2.ts`], 13 | matches: ["https://example.com/"], 14 | }, 15 | ], 16 | })); 17 | -------------------------------------------------------------------------------- /test/manifest/contentWithChunkedImport.v2.test.ts: -------------------------------------------------------------------------------- 1 | import { getResourceDir, runManifestV2Test } from "./manifestTestUtils"; 2 | 3 | const resourceDir = getResourceDir("contentWithChunkedImport"); 4 | 5 | runManifestV2Test("contentWithChunkedImport", () => ({ 6 | content_scripts: [ 7 | { 8 | js: [`${resourceDir}/content1.js`], 9 | matches: ["https://*/*", "http://*/*"], 10 | }, 11 | { 12 | js: [`${resourceDir}/content2.js`], 13 | matches: ["https://*/*", "http://*/*"], 14 | }, 15 | ], 16 | })); 17 | -------------------------------------------------------------------------------- /test/manifest/contentWithChunkedImport.v3.test.ts: -------------------------------------------------------------------------------- 1 | import { getResourceDir, runManifestV3Test } from "./manifestTestUtils"; 2 | 3 | const resourceDir = getResourceDir("contentWithChunkedImport"); 4 | 5 | runManifestV3Test("contentWithChunkedImport", () => ({ 6 | content_scripts: [ 7 | { 8 | js: [`${resourceDir}/content1.js`], 9 | matches: [ 10 | "*://*/*", 11 | "https://*/*", 12 | "*://example.com/", 13 | "https://example.com/", 14 | "*://example.com/subpath/*", 15 | "https://example.com/subpath/*", 16 | ], 17 | }, 18 | { 19 | js: [`${resourceDir}/content2.js`], 20 | matches: [ 21 | "*://*/*", 22 | "https://*/*", 23 | "*://example.com/", 24 | "https://example.com/", 25 | "*://example.com/subpath/*", 26 | "https://example.com/subpath/*", 27 | ], 28 | }, 29 | ], 30 | })); 31 | -------------------------------------------------------------------------------- /test/manifest/contentWithDynamicImport.v2.test.ts: -------------------------------------------------------------------------------- 1 | import { getResourceDir, runManifestV2Test } from "./manifestTestUtils"; 2 | 3 | const resourceDir = getResourceDir("contentWithDynamicImport"); 4 | 5 | runManifestV2Test("contentWithDynamicImport", () => ({ 6 | content_scripts: [ 7 | { 8 | js: [`${resourceDir}/content1.js`], 9 | matches: ["https://*/*", "http://*/*"], 10 | }, 11 | { 12 | js: [`${resourceDir}/content2.js`], 13 | matches: ["https://*/*", "http://*/*"], 14 | }, 15 | ], 16 | })); 17 | -------------------------------------------------------------------------------- /test/manifest/contentWithDynamicImport.v3.test.ts: -------------------------------------------------------------------------------- 1 | import { getResourceDir, runManifestV3Test } from "./manifestTestUtils"; 2 | 3 | const resourceDir = getResourceDir("contentWithDynamicImport"); 4 | 5 | runManifestV3Test("contentWithDynamicImport", () => ({ 6 | content_scripts: [ 7 | { 8 | js: [`${resourceDir}/content1.js`], 9 | matches: [ 10 | "*://*/*", 11 | "https://*/*", 12 | "*://example.com/", 13 | "https://example.com/", 14 | "*://example.com/subpath/*", 15 | "https://example.com/subpath/*", 16 | ], 17 | }, 18 | { 19 | js: [`${resourceDir}/content2.js`], 20 | matches: [ 21 | "*://*/*", 22 | "https://*/*", 23 | "*://example.com/", 24 | "https://example.com/", 25 | "*://example.com/subpath/*", 26 | "https://example.com/subpath/*", 27 | ], 28 | }, 29 | ], 30 | })); 31 | -------------------------------------------------------------------------------- /test/manifest/contentWithNoImports.v2.test.ts: -------------------------------------------------------------------------------- 1 | import { getResourceDir, runManifestV2Test } from "./manifestTestUtils"; 2 | 3 | const resourceDir = getResourceDir("contentWithNoImports"); 4 | 5 | runManifestV2Test("contentWithNoImports", () => ({ 6 | content_scripts: [ 7 | { 8 | js: [`${resourceDir}/content.js`], 9 | matches: ["https://*/*", "http://*/*"], 10 | }, 11 | ], 12 | })); 13 | -------------------------------------------------------------------------------- /test/manifest/contentWithNoImports.v3.test.ts: -------------------------------------------------------------------------------- 1 | import { getResourceDir, runManifestV3Test } from "./manifestTestUtils"; 2 | 3 | const resourceDir = getResourceDir("contentWithNoImports"); 4 | 5 | runManifestV3Test("contentWithNoImports", () => ({ 6 | content_scripts: [ 7 | { 8 | js: [`${resourceDir}/content.js`], 9 | matches: [ 10 | "*://*/*", 11 | "https://*/*", 12 | "*://example.com/", 13 | "https://example.com/", 14 | "*://example.com/subpath/*", 15 | "https://example.com/subpath/*", 16 | ], 17 | }, 18 | ], 19 | })); 20 | -------------------------------------------------------------------------------- /test/manifest/contentWithSameScriptName.v2.test.ts: -------------------------------------------------------------------------------- 1 | import { getResourceDir, runManifestV2Test } from "./manifestTestUtils"; 2 | 3 | const resourceDir = getResourceDir("contentWithSameScriptName"); 4 | 5 | runManifestV2Test("contentWithSameScriptName", () => ({ 6 | content_scripts: [ 7 | { 8 | js: [`${resourceDir}/content1/content.js`], 9 | matches: ["https://*/*", "http://*/*"], 10 | }, 11 | { 12 | js: [`${resourceDir}/content2/content.js`], 13 | matches: ["https://*/*", "http://*/*"], 14 | }, 15 | ], 16 | })); 17 | -------------------------------------------------------------------------------- /test/manifest/contentWithSameScriptName.v3.test.ts: -------------------------------------------------------------------------------- 1 | import { getResourceDir, runManifestV3Test } from "./manifestTestUtils"; 2 | 3 | const resourceDir = getResourceDir("contentWithSameScriptName"); 4 | 5 | runManifestV3Test("contentWithSameScriptName", () => ({ 6 | content_scripts: [ 7 | { 8 | js: [`${resourceDir}/content1/content.js`], 9 | matches: [ 10 | "*://*/*", 11 | "https://*/*", 12 | "*://example.com/", 13 | "https://example.com/", 14 | "*://example.com/subpath/*", 15 | "https://example.com/subpath/*", 16 | ], 17 | }, 18 | { 19 | js: [`${resourceDir}/content2/content.js`], 20 | matches: [ 21 | "*://*/*", 22 | "https://*/*", 23 | "*://example.com/", 24 | "https://example.com/", 25 | "*://example.com/subpath/*", 26 | "https://example.com/subpath/*", 27 | ], 28 | }, 29 | ], 30 | })); 31 | -------------------------------------------------------------------------------- /test/manifest/contentWithUnchunkedImport.v2.test.ts: -------------------------------------------------------------------------------- 1 | import { getResourceDir, runManifestV2Test } from "./manifestTestUtils"; 2 | 3 | const resourceDir = getResourceDir("contentWithUnchunkedImport"); 4 | 5 | runManifestV2Test("contentWithUnchunkedImport", () => ({ 6 | content_scripts: [ 7 | { 8 | js: [`${resourceDir}/content.js`], 9 | matches: ["https://*/*", "http://*/*"], 10 | }, 11 | ], 12 | })); 13 | -------------------------------------------------------------------------------- /test/manifest/contentWithUnchunkedImport.v3.test.ts: -------------------------------------------------------------------------------- 1 | import { getResourceDir, runManifestV3Test } from "./manifestTestUtils"; 2 | 3 | const resourceDir = getResourceDir("contentWithUnchunkedImport"); 4 | 5 | runManifestV3Test("contentWithUnchunkedImport", () => ({ 6 | content_scripts: [ 7 | { 8 | js: [`${resourceDir}/content.js`], 9 | matches: [ 10 | "*://*/*", 11 | "https://*/*", 12 | "*://example.com/", 13 | "https://example.com/", 14 | "*://example.com/subpath/*", 15 | "https://example.com/subpath/*", 16 | ], 17 | }, 18 | ], 19 | })); 20 | -------------------------------------------------------------------------------- /test/manifest/devtoolsHtml.v2.test.ts: -------------------------------------------------------------------------------- 1 | import { getResourceDir, runManifestV2Test } from "./manifestTestUtils"; 2 | 3 | const resourceDir = getResourceDir("devtoolsHtml"); 4 | 5 | runManifestV2Test("devtoolsHtml", () => ({ 6 | devtools_page: `${resourceDir}/devtools.html`, 7 | })); 8 | -------------------------------------------------------------------------------- /test/manifest/devtoolsHtml.v3.test.ts: -------------------------------------------------------------------------------- 1 | import { getResourceDir, runManifestV3Test } from "./manifestTestUtils"; 2 | 3 | const resourceDir = getResourceDir("devtoolsHtml"); 4 | 5 | runManifestV3Test("devtoolsHtml", () => ({ 6 | devtools_page: `${resourceDir}/devtools.html`, 7 | })); 8 | -------------------------------------------------------------------------------- /test/manifest/fullExtension.v2.test.ts: -------------------------------------------------------------------------------- 1 | import { getResourceDir, runManifestV2Test } from "./manifestTestUtils"; 2 | 3 | const resourceDir = getResourceDir("fullExtension"); 4 | 5 | runManifestV2Test( 6 | "fullExtension", 7 | () => ({ 8 | background: { 9 | scripts: [`${resourceDir}/src/entries/background/main.js`], 10 | persistent: false, 11 | }, 12 | content_scripts: [ 13 | { 14 | js: [`${resourceDir}/src/entries/contentScript/primary/main.js`], 15 | matches: ["*://*/*"], 16 | }, 17 | ], 18 | browser_action: { 19 | default_icon: { 20 | 32: `${resourceDir}/src/assets/logo.svg`, 21 | }, 22 | // default_popup: `${resourceDir}/src/entries/popup/index.html`, 23 | }, 24 | options_ui: { 25 | chrome_style: false, 26 | open_in_tab: true, 27 | page: `${resourceDir}/src/entries/options/index.html`, 28 | }, 29 | permissions: ["*://*/*"], 30 | }), 31 | { 32 | additionalInputs: { 33 | scripts: [`${resourceDir}/src/lib.js`], 34 | }, 35 | } 36 | ); 37 | -------------------------------------------------------------------------------- /test/manifest/fullExtension.v3.test.ts: -------------------------------------------------------------------------------- 1 | import { getResourceDir, runManifestV3Test } from "./manifestTestUtils"; 2 | 3 | const resourceDir = getResourceDir("fullExtension"); 4 | 5 | runManifestV3Test( 6 | "fullExtension", 7 | () => ({ 8 | action: { 9 | default_icon: { 10 | 32: `${resourceDir}/src/assets/logo.svg`, 11 | }, 12 | // default_popup: `${resourceDir}/src/entries/popup/index.html`, 13 | }, 14 | background: { 15 | service_worker: `${resourceDir}/src/entries/background/main.js`, 16 | }, 17 | content_scripts: [ 18 | { 19 | js: [`${resourceDir}/src/entries/contentScript/primary/main.js`], 20 | matches: ["*://*/*"], 21 | }, 22 | ], 23 | host_permissions: ["*://*/*"], 24 | permissions: ["scripting", "tabs"], 25 | icons: { 26 | 512: `${resourceDir}/src/assets/logo.svg`, 27 | }, 28 | options_ui: { 29 | page: `${resourceDir}/src/entries/options/index.html`, 30 | open_in_tab: true, 31 | }, 32 | }), 33 | { 34 | additionalInputs: { 35 | scripts: [`${resourceDir}/src/lib.js`], 36 | }, 37 | } 38 | ); 39 | -------------------------------------------------------------------------------- /test/manifest/htmlUrlProperties.v2.test.ts: -------------------------------------------------------------------------------- 1 | import { getResourceDir, runManifestV2Test } from "./manifestTestUtils"; 2 | 3 | const resourceDir = getResourceDir("htmlUrlProperties"); 4 | 5 | runManifestV2Test("htmlUrlProperties", () => ({ 6 | browser_action: { 7 | default_popup: `${resourceDir}/popup.html#hashValue`, 8 | }, 9 | devtools_page: `${resourceDir}/devtools.html?query=1`, 10 | options_ui: { 11 | page: `${resourceDir}/options.html?query=1#hashValue`, 12 | }, 13 | })); 14 | -------------------------------------------------------------------------------- /test/manifest/htmlUrlProperties.v3.test.ts: -------------------------------------------------------------------------------- 1 | import { getResourceDir, runManifestV3Test } from "./manifestTestUtils"; 2 | 3 | const resourceDir = getResourceDir("htmlUrlProperties"); 4 | 5 | runManifestV3Test("htmlUrlProperties", () => ({ 6 | action: { 7 | default_popup: `${resourceDir}/popup.html#hashValue`, 8 | }, 9 | devtools_page: `${resourceDir}/devtools.html?query=1`, 10 | options_ui: { 11 | page: `${resourceDir}/options.html?query=1#hashValue`, 12 | }, 13 | })); 14 | -------------------------------------------------------------------------------- /test/manifest/manifestTestUtils.ts: -------------------------------------------------------------------------------- 1 | import path from "node:path"; 2 | import type { RollupOutput } from "rollup"; 3 | import { build, normalizePath } from "vite"; 4 | import { expect, test } from "vitest"; 5 | import webExtension from "../../src/index"; 6 | import { ViteWebExtensionOptions } from "../../types"; 7 | 8 | type InputManifestGenerator = () => Partial; 9 | 10 | function normalizeFileName(fileName: string): string { 11 | return normalizePath(path.normalize(fileName)); 12 | } 13 | 14 | async function bundleGenerate( 15 | options: ViteWebExtensionOptions 16 | ): Promise { 17 | const bundle = await build({ 18 | logLevel: "warn", 19 | build: { 20 | write: false, 21 | minify: false, 22 | rollupOptions: { 23 | output: { 24 | entryFileNames: `assets/[name].js`, 25 | chunkFileNames: `assets/[name].js`, 26 | assetFileNames: `assets/[name].[ext]`, 27 | }, 28 | }, 29 | }, 30 | plugins: [webExtension(options)], 31 | }); 32 | 33 | return bundle as RollupOutput; 34 | } 35 | 36 | function trimFilePathToRepoDirectory(filePath: string): string { 37 | return filePath.substring(filePath.lastIndexOf("vite-plugin-web-extension")); 38 | } 39 | 40 | export async function runTest({ 41 | manifestGenerator, 42 | manifestVersion, 43 | pluginOptions, 44 | }: { 45 | manifestVersion: ManifestType["manifest_version"]; 46 | manifestGenerator: InputManifestGenerator; 47 | pluginOptions: Partial; 48 | }): Promise { 49 | const [repoDir] = __dirname.split("/test/manifest"); 50 | 51 | const baseManifest: chrome.runtime.Manifest = { 52 | version: "1.0.0", 53 | name: "Manifest Name", 54 | manifest_version: manifestVersion, 55 | }; 56 | 57 | let { output } = await bundleGenerate({ 58 | manifest: { 59 | ...baseManifest, 60 | ...manifestGenerator(), 61 | }, 62 | ...pluginOptions, 63 | }); 64 | 65 | expect( 66 | output 67 | .map((file) => { 68 | if (file.type === "chunk") { 69 | const modules = {}; 70 | for (const [key, value] of Object.entries(file.modules)) { 71 | modules[trimFilePathToRepoDirectory(key)] = value; 72 | } 73 | 74 | return { 75 | code: file.code, 76 | dynamicImports: file.dynamicImports, 77 | exports: file.exports, 78 | facadeModuleId: file.facadeModuleId 79 | ? trimFilePathToRepoDirectory(file.facadeModuleId) 80 | : null, 81 | fileName: normalizeFileName(file.fileName), 82 | implicitlyLoadedBefore: file.implicitlyLoadedBefore, 83 | importedBindings: file.importedBindings, 84 | imports: file.imports, 85 | isDynamicEntry: file.isDynamicEntry, 86 | isEntry: file.isEntry, 87 | isImplicitEntry: file.isImplicitEntry, 88 | map: file.map, 89 | modules: modules, 90 | name: normalizeFileName(file.name), 91 | referencedFiles: file.referencedFiles, 92 | type: file.type, 93 | viteMetadata: file.viteMetadata, 94 | }; 95 | } 96 | 97 | if (file.type === "asset") { 98 | return { 99 | fileName: normalizeFileName(file.fileName), 100 | name: 101 | typeof file.name === "undefined" 102 | ? undefined 103 | : normalizeFileName(file.name), 104 | source: file.source, 105 | type: file.type, 106 | }; 107 | } 108 | 109 | return file; 110 | }) 111 | .sort((a, b) => a.fileName.localeCompare(b.fileName)) 112 | ).toMatchSnapshot(); 113 | } 114 | 115 | export function getResourceDir(path: string): string { 116 | return `test/manifest/resources/${path}`; 117 | } 118 | 119 | export async function runManifestV2Test( 120 | testName: string, 121 | manifestGenerator: InputManifestGenerator, 122 | pluginOptions: Partial = {} 123 | ) { 124 | test(`${testName} - Manifest V2`, async () => { 125 | await runTest({ 126 | manifestVersion: 2, 127 | manifestGenerator, 128 | pluginOptions, 129 | }); 130 | }); 131 | } 132 | 133 | export async function runManifestV3Test( 134 | testName: string, 135 | manifestGenerator: InputManifestGenerator, 136 | pluginOptions: Partial = {} 137 | ) { 138 | test(`${testName} - Manifest V3`, async () => { 139 | await runTest({ 140 | manifestVersion: 3, 141 | manifestGenerator, 142 | pluginOptions, 143 | }); 144 | }); 145 | } 146 | -------------------------------------------------------------------------------- /test/manifest/optimizeWebAccessibleResourcesDisabled.v2.test.ts: -------------------------------------------------------------------------------- 1 | import { getResourceDir, runManifestV2Test } from "./manifestTestUtils"; 2 | 3 | const resourceDir = getResourceDir("optimizeWebAccessibleResources"); 4 | 5 | runManifestV2Test( 6 | "optimizeWebAccessibleResourcesDisabled", 7 | () => ({ 8 | content_scripts: [ 9 | { 10 | js: [`${resourceDir}/content1.js`], 11 | matches: [""], 12 | }, 13 | { 14 | js: [`${resourceDir}/content2.js`], 15 | matches: [""], 16 | }, 17 | ], 18 | }), 19 | { 20 | additionalInputs: { 21 | scripts: [`${resourceDir}/script1.js`, `${resourceDir}/script2.js`], 22 | }, 23 | optimizeWebAccessibleResources: false, 24 | } 25 | ); 26 | -------------------------------------------------------------------------------- /test/manifest/optimizeWebAccessibleResourcesDisabled.v3.test.ts: -------------------------------------------------------------------------------- 1 | import { getResourceDir, runManifestV3Test } from "./manifestTestUtils"; 2 | 3 | const resourceDir = getResourceDir("optimizeWebAccessibleResources"); 4 | 5 | runManifestV3Test( 6 | "optimizeWebAccessibleResourcesDisabled", 7 | () => ({ 8 | content_scripts: [ 9 | { 10 | js: [`${resourceDir}/content1.js`], 11 | matches: [""], 12 | }, 13 | { 14 | js: [`${resourceDir}/content2.js`], 15 | matches: [""], 16 | }, 17 | ], 18 | }), 19 | { 20 | additionalInputs: { 21 | scripts: [`${resourceDir}/script1.js`, `${resourceDir}/script2.js`], 22 | }, 23 | optimizeWebAccessibleResources: false, 24 | } 25 | ); 26 | -------------------------------------------------------------------------------- /test/manifest/optimizeWebAccessibleResourcesEnabled.v2.test.ts: -------------------------------------------------------------------------------- 1 | import { getResourceDir, runManifestV2Test } from "./manifestTestUtils"; 2 | 3 | const resourceDir = getResourceDir("optimizeWebAccessibleResources"); 4 | 5 | runManifestV2Test( 6 | "optimizeWebAccessibleResourcesEnabled", 7 | () => ({ 8 | content_scripts: [ 9 | { 10 | js: [`${resourceDir}/content1.js`], 11 | matches: [""], 12 | }, 13 | { 14 | js: [`${resourceDir}/content2.js`], 15 | matches: [""], 16 | }, 17 | ], 18 | }), 19 | { 20 | additionalInputs: { 21 | scripts: [`${resourceDir}/script1.js`, `${resourceDir}/script2.js`], 22 | }, 23 | } 24 | ); 25 | -------------------------------------------------------------------------------- /test/manifest/optimizeWebAccessibleResourcesEnabled.v3.test.ts: -------------------------------------------------------------------------------- 1 | import { getResourceDir, runManifestV3Test } from "./manifestTestUtils"; 2 | 3 | const resourceDir = getResourceDir("optimizeWebAccessibleResources"); 4 | 5 | runManifestV3Test( 6 | "optimizeWebAccessibleResourcesEnabled", 7 | () => ({ 8 | content_scripts: [ 9 | { 10 | js: [`${resourceDir}/content1.js`], 11 | matches: [""], 12 | }, 13 | { 14 | js: [`${resourceDir}/content2.js`], 15 | matches: [""], 16 | }, 17 | ], 18 | }), 19 | { 20 | additionalInputs: { 21 | scripts: [`${resourceDir}/script1.js`, `${resourceDir}/script2.js`], 22 | }, 23 | } 24 | ); 25 | -------------------------------------------------------------------------------- /test/manifest/optionsHtml.v2.test.ts: -------------------------------------------------------------------------------- 1 | import { getResourceDir, runManifestV2Test } from "./manifestTestUtils"; 2 | 3 | const resourceDir = getResourceDir("optionsHtml"); 4 | 5 | runManifestV2Test("optionsHtml", () => ({ 6 | options_ui: { 7 | page: `${resourceDir}/options.html`, 8 | }, 9 | })); 10 | -------------------------------------------------------------------------------- /test/manifest/optionsHtml.v3.test.ts: -------------------------------------------------------------------------------- 1 | import { getResourceDir, runManifestV3Test } from "./manifestTestUtils"; 2 | 3 | const resourceDir = getResourceDir("optionsHtml"); 4 | 5 | runManifestV3Test("optionsHtml", () => ({ 6 | options_ui: { 7 | page: `${resourceDir}/options.html`, 8 | }, 9 | })); 10 | -------------------------------------------------------------------------------- /test/manifest/popupHtml.v2.test.ts: -------------------------------------------------------------------------------- 1 | import { getResourceDir, runManifestV2Test } from "./manifestTestUtils"; 2 | 3 | const resourceDir = getResourceDir("popupHtml"); 4 | 5 | runManifestV2Test("popupHtml", () => ({ 6 | browser_action: { 7 | default_popup: `${resourceDir}/popup.html`, 8 | }, 9 | })); 10 | -------------------------------------------------------------------------------- /test/manifest/popupHtml.v3.test.ts: -------------------------------------------------------------------------------- 1 | import { getResourceDir, runManifestV3Test } from "./manifestTestUtils"; 2 | 3 | const resourceDir = getResourceDir("popupHtml"); 4 | 5 | runManifestV3Test("popupHtml", () => ({ 6 | action: { 7 | default_popup: `${resourceDir}/popup.html`, 8 | }, 9 | })); 10 | -------------------------------------------------------------------------------- /test/manifest/resources/additionalInputsHtml/html.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /test/manifest/resources/additionalInputsHtml/script.js: -------------------------------------------------------------------------------- 1 | import log from "./../shared/log"; 2 | 3 | log("webAccessible"); 4 | -------------------------------------------------------------------------------- /test/manifest/resources/additionalInputsHtml/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | color: red; 3 | } 4 | -------------------------------------------------------------------------------- /test/manifest/resources/additionalInputsScriptsChunkedImport/script1.js: -------------------------------------------------------------------------------- 1 | import log from "../shared/log"; 2 | 3 | log("script1"); 4 | -------------------------------------------------------------------------------- /test/manifest/resources/additionalInputsScriptsChunkedImport/script2.js: -------------------------------------------------------------------------------- 1 | import log from "../shared/log"; 2 | 3 | log("script2"); 4 | -------------------------------------------------------------------------------- /test/manifest/resources/additionalInputsScriptsNoImport/script1.js: -------------------------------------------------------------------------------- 1 | console.log("script1"); 2 | -------------------------------------------------------------------------------- /test/manifest/resources/additionalInputsScriptsNoImport/script2.js: -------------------------------------------------------------------------------- 1 | console.log("script2"); 2 | -------------------------------------------------------------------------------- /test/manifest/resources/additionalInputsScriptsTypes/script1.js: -------------------------------------------------------------------------------- 1 | console.log("script1"); 2 | -------------------------------------------------------------------------------- /test/manifest/resources/additionalInputsScriptsTypes/script2.ts: -------------------------------------------------------------------------------- 1 | console.log("script2"); 2 | -------------------------------------------------------------------------------- /test/manifest/resources/additionalInputsScriptsUnchunkedImport/script1.js: -------------------------------------------------------------------------------- 1 | import log from "../shared/log"; 2 | 3 | log("script1"); 4 | -------------------------------------------------------------------------------- /test/manifest/resources/additionalInputsScriptsUnchunkedImport/script2.js: -------------------------------------------------------------------------------- 1 | console.log("script2"); 2 | -------------------------------------------------------------------------------- /test/manifest/resources/additionalInputsStylesTypes/style1.css: -------------------------------------------------------------------------------- 1 | body { 2 | color: red; 3 | } 4 | -------------------------------------------------------------------------------- /test/manifest/resources/additionalInputsStylesTypes/style2.scss: -------------------------------------------------------------------------------- 1 | body { 2 | color: green; 3 | } 4 | -------------------------------------------------------------------------------- /test/manifest/resources/additionalInputsWebAccessible/chunkedScript1.js: -------------------------------------------------------------------------------- 1 | import log from "../shared/log"; 2 | 3 | log("chunkedScript1"); 4 | -------------------------------------------------------------------------------- /test/manifest/resources/additionalInputsWebAccessible/chunkedScript2.js: -------------------------------------------------------------------------------- 1 | import log from "../shared/log"; 2 | 3 | log("chunkedScript2"); 4 | -------------------------------------------------------------------------------- /test/manifest/resources/additionalInputsWebAccessible/chunkedScript3.js: -------------------------------------------------------------------------------- 1 | import log from "../shared/log"; 2 | 3 | log("chunkedScript3"); 4 | -------------------------------------------------------------------------------- /test/manifest/resources/additionalInputsWebAccessible/script1.js: -------------------------------------------------------------------------------- 1 | console.log("script1"); 2 | -------------------------------------------------------------------------------- /test/manifest/resources/additionalInputsWebAccessible/script2.js: -------------------------------------------------------------------------------- 1 | console.log("script2"); 2 | -------------------------------------------------------------------------------- /test/manifest/resources/additionalInputsWebAccessible/script3.js: -------------------------------------------------------------------------------- 1 | console.log("script3"); 2 | -------------------------------------------------------------------------------- /test/manifest/resources/additionalInputsWebAccessible/script4.js: -------------------------------------------------------------------------------- 1 | console.log("script4"); 2 | -------------------------------------------------------------------------------- /test/manifest/resources/additionalInputsWebAccessible/script5.ts: -------------------------------------------------------------------------------- 1 | console.log("script5"); 2 | -------------------------------------------------------------------------------- /test/manifest/resources/additionalInputsWebAccessible/script6.js: -------------------------------------------------------------------------------- 1 | console.log("script6"); 2 | -------------------------------------------------------------------------------- /test/manifest/resources/additionalInputsWebAccessible/script7.js: -------------------------------------------------------------------------------- 1 | console.log("script7"); 2 | -------------------------------------------------------------------------------- /test/manifest/resources/backgroundHtml/background.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /test/manifest/resources/backgroundHtml/background.js: -------------------------------------------------------------------------------- 1 | import log from "./../shared/log"; 2 | 3 | log("background"); 4 | -------------------------------------------------------------------------------- /test/manifest/resources/backgroundScript/background.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /test/manifest/resources/backgroundScript/background.js: -------------------------------------------------------------------------------- 1 | import log from "./../shared/log"; 2 | 3 | log("background"); 4 | -------------------------------------------------------------------------------- /test/manifest/resources/backgroundServiceWorker/serviceWorker.js: -------------------------------------------------------------------------------- 1 | console.log("serviceWorker"); 2 | -------------------------------------------------------------------------------- /test/manifest/resources/chromeUrlOverridesHtml/bookmarks.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /test/manifest/resources/chromeUrlOverridesHtml/chromeUrlOverridesHtml.js: -------------------------------------------------------------------------------- 1 | import log from "./../shared/log"; 2 | 3 | log("chromeUrlOverridesHtml"); 4 | -------------------------------------------------------------------------------- /test/manifest/resources/chromeUrlOverridesHtml/devtools.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /test/manifest/resources/chromeUrlOverridesHtml/history.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /test/manifest/resources/chromeUrlOverridesHtml/newtab.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /test/manifest/resources/chunkCssRewrite/content1.css: -------------------------------------------------------------------------------- 1 | #content1 { 2 | display: flex; 3 | } 4 | -------------------------------------------------------------------------------- /test/manifest/resources/chunkCssRewrite/content1.js: -------------------------------------------------------------------------------- 1 | import "./content1.css"; 2 | import "./contentShared.css"; 3 | 4 | console.log(import.meta.PLUGIN_WEB_EXT_CHUNK_CSS_PATHS); 5 | -------------------------------------------------------------------------------- /test/manifest/resources/chunkCssRewrite/content2.css: -------------------------------------------------------------------------------- 1 | #content2 { 2 | display: flex; 3 | } 4 | -------------------------------------------------------------------------------- /test/manifest/resources/chunkCssRewrite/content2.js: -------------------------------------------------------------------------------- 1 | import "./content2.css"; 2 | import "./contentShared.css"; 3 | 4 | console.log(import.meta.PLUGIN_WEB_EXT_CHUNK_CSS_PATHS); 5 | -------------------------------------------------------------------------------- /test/manifest/resources/chunkCssRewrite/contentNoCss.js: -------------------------------------------------------------------------------- 1 | console.log(import.meta.PLUGIN_WEB_EXT_CHUNK_CSS_PATHS); 2 | -------------------------------------------------------------------------------- /test/manifest/resources/chunkCssRewrite/contentShared.css: -------------------------------------------------------------------------------- 1 | #contentShared { 2 | display: flex; 3 | } 4 | -------------------------------------------------------------------------------- /test/manifest/resources/contentCss/content.js: -------------------------------------------------------------------------------- 1 | console.log("content"); 2 | -------------------------------------------------------------------------------- /test/manifest/resources/contentCss/content1.css: -------------------------------------------------------------------------------- 1 | .css { 2 | color: red; 3 | } 4 | -------------------------------------------------------------------------------- /test/manifest/resources/contentCss/content2.scss: -------------------------------------------------------------------------------- 1 | .css { 2 | color: green; 3 | } 4 | -------------------------------------------------------------------------------- /test/manifest/resources/contentScriptTypes/content1.js: -------------------------------------------------------------------------------- 1 | console.log("content1"); 2 | -------------------------------------------------------------------------------- /test/manifest/resources/contentScriptTypes/content2.ts: -------------------------------------------------------------------------------- 1 | console.log("content2"); 2 | -------------------------------------------------------------------------------- /test/manifest/resources/contentWithChunkedImport/content1.js: -------------------------------------------------------------------------------- 1 | import log from "./../shared/log"; 2 | 3 | log("content"); 4 | -------------------------------------------------------------------------------- /test/manifest/resources/contentWithChunkedImport/content2.js: -------------------------------------------------------------------------------- 1 | import log from "./../shared/log"; 2 | 3 | log("content2"); 4 | -------------------------------------------------------------------------------- /test/manifest/resources/contentWithDynamicImport/content1.js: -------------------------------------------------------------------------------- 1 | (async () => { 2 | const log = await import("./../shared/log"); 3 | 4 | log("content"); 5 | })(); 6 | -------------------------------------------------------------------------------- /test/manifest/resources/contentWithDynamicImport/content2.js: -------------------------------------------------------------------------------- 1 | (async () => { 2 | const log = await import("./../shared/log"); 3 | 4 | log("content2"); 5 | })(); 6 | -------------------------------------------------------------------------------- /test/manifest/resources/contentWithNoImports/content.js: -------------------------------------------------------------------------------- 1 | console.log("content"); 2 | -------------------------------------------------------------------------------- /test/manifest/resources/contentWithSameScriptName/content1/content.js: -------------------------------------------------------------------------------- 1 | console.log("content1"); 2 | -------------------------------------------------------------------------------- /test/manifest/resources/contentWithSameScriptName/content2/content.js: -------------------------------------------------------------------------------- 1 | console.log("content2"); 2 | -------------------------------------------------------------------------------- /test/manifest/resources/contentWithUnchunkedImport/content.js: -------------------------------------------------------------------------------- 1 | import log from "./../shared/log"; 2 | 3 | log("content"); 4 | -------------------------------------------------------------------------------- /test/manifest/resources/devtoolsHtml/devtools.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /test/manifest/resources/devtoolsHtml/devtools.js: -------------------------------------------------------------------------------- 1 | import log from "./../shared/log"; 2 | 3 | log("devtools"); 4 | -------------------------------------------------------------------------------- /test/manifest/resources/fullExtension/src/assets/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Layer 1 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /test/manifest/resources/fullExtension/src/entries/background/main.js: -------------------------------------------------------------------------------- 1 | browser.runtime.onInstalled.addListener(() => { 2 | console.log("Extension installed"); 3 | }); 4 | 5 | browser.action.onClicked.addListener(async () => { 6 | const tab = await getCurrentTab(); 7 | 8 | chrome.scripting.executeScript({ 9 | target: { tabId: tab?.id }, 10 | files: ["src/lib.js"], 11 | }); 12 | }); 13 | 14 | async function getCurrentTab() { 15 | let queryOptions = { active: true, lastFocusedWindow: true }; 16 | let [tab] = await chrome.tabs.query(queryOptions); 17 | return tab; 18 | } 19 | -------------------------------------------------------------------------------- /test/manifest/resources/fullExtension/src/entries/contentScript/primary/main.js: -------------------------------------------------------------------------------- 1 | import renderContent from "../renderContent"; 2 | import logo from "../../../assets/logo.svg"; 3 | import "./style.css"; 4 | 5 | renderContent(import.meta.PLUGIN_WEB_EXT_CHUNK_CSS_PATHS, (appRoot) => { 6 | const logoImageUrl = new URL(logo, import.meta.url).href; 7 | 8 | appRoot.innerHTML = ` 9 | 12 | `; 13 | }); 14 | 15 | console.log(chrome.runtime.getURL("src/lib.js")); 16 | -------------------------------------------------------------------------------- /test/manifest/resources/fullExtension/src/entries/contentScript/primary/style.css: -------------------------------------------------------------------------------- 1 | .logo { 2 | z-index: 99999; 3 | position: fixed; 4 | bottom: 20px; 5 | right: 10px; 6 | width: 60px; 7 | height: 60px; 8 | display: flex; 9 | justify-content: center; 10 | align-items: center; 11 | border: 4px solid #c72a21; 12 | border-radius: 50%; 13 | background-color: #fff; 14 | } 15 | 16 | img { 17 | position: absolute; 18 | top: 7px; 19 | } 20 | -------------------------------------------------------------------------------- /test/manifest/resources/fullExtension/src/entries/contentScript/renderContent.js: -------------------------------------------------------------------------------- 1 | export default async function renderContent( 2 | cssPaths, 3 | render = (_appRoot) => {} 4 | ) { 5 | console.log("renderContent", cssPaths); 6 | } 7 | -------------------------------------------------------------------------------- /test/manifest/resources/fullExtension/src/entries/options/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Options 6 | 7 | 8 |
9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /test/manifest/resources/fullExtension/src/entries/options/main.js: -------------------------------------------------------------------------------- 1 | import logo from "../../assets/logo.svg"; 2 | import "./style.css"; 3 | 4 | const imageUrl = new URL(logo, import.meta.url).href; 5 | 6 | document.querySelector("#app").innerHTML = ` 7 | 8 |

Options

9 | Vite Docs 10 | `; 11 | -------------------------------------------------------------------------------- /test/manifest/resources/fullExtension/src/entries/options/style.css: -------------------------------------------------------------------------------- 1 | #app { 2 | font-family: Avenir, Helvetica, Arial, sans-serif; 3 | -webkit-font-smoothing: antialiased; 4 | -moz-osx-font-smoothing: grayscale; 5 | text-align: center; 6 | color: #2c3e50; 7 | } 8 | 9 | h1 { 10 | margin: 5px; 11 | } 12 | -------------------------------------------------------------------------------- /test/manifest/resources/fullExtension/src/entries/popup/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Popup 6 | 7 | 8 |
9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /test/manifest/resources/fullExtension/src/entries/popup/main.js: -------------------------------------------------------------------------------- 1 | import logo from "../../assets/logo.svg"; 2 | import "./style.css"; 3 | 4 | const imageUrl = new URL(logo, import.meta.url).href; 5 | 6 | document.querySelector("#app").innerHTML = ` 7 | 8 |

Popup

9 | Vite Docs 10 | `; 11 | -------------------------------------------------------------------------------- /test/manifest/resources/fullExtension/src/entries/popup/style.css: -------------------------------------------------------------------------------- 1 | #app { 2 | font-family: Avenir, Helvetica, Arial, sans-serif; 3 | -webkit-font-smoothing: antialiased; 4 | -moz-osx-font-smoothing: grayscale; 5 | text-align: center; 6 | color: #2c3e50; 7 | } 8 | 9 | h1 { 10 | margin: 5px; 11 | } 12 | -------------------------------------------------------------------------------- /test/manifest/resources/fullExtension/src/lib.js: -------------------------------------------------------------------------------- 1 | console.log("lib.js"); 2 | -------------------------------------------------------------------------------- /test/manifest/resources/htmlUrlProperties/devtools.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /test/manifest/resources/htmlUrlProperties/devtools.js: -------------------------------------------------------------------------------- 1 | import log from "./../shared/log"; 2 | 3 | log("devtools"); 4 | -------------------------------------------------------------------------------- /test/manifest/resources/htmlUrlProperties/options.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /test/manifest/resources/htmlUrlProperties/options.js: -------------------------------------------------------------------------------- 1 | import log from "./../shared/log"; 2 | 3 | log("options"); 4 | -------------------------------------------------------------------------------- /test/manifest/resources/htmlUrlProperties/popup.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /test/manifest/resources/htmlUrlProperties/popup.js: -------------------------------------------------------------------------------- 1 | import log from "./../shared/log"; 2 | 3 | log("popup"); 4 | -------------------------------------------------------------------------------- /test/manifest/resources/optimizeWebAccessibleResources/content1.js: -------------------------------------------------------------------------------- 1 | import log from "./../shared/log"; 2 | 3 | log("content"); 4 | -------------------------------------------------------------------------------- /test/manifest/resources/optimizeWebAccessibleResources/content2.js: -------------------------------------------------------------------------------- 1 | import log from "./../shared/log"; 2 | 3 | log("content2"); 4 | -------------------------------------------------------------------------------- /test/manifest/resources/optimizeWebAccessibleResources/script1.js: -------------------------------------------------------------------------------- 1 | import log from "../shared/log"; 2 | 3 | log("script1"); 4 | -------------------------------------------------------------------------------- /test/manifest/resources/optimizeWebAccessibleResources/script2.js: -------------------------------------------------------------------------------- 1 | import log from "../shared/log"; 2 | 3 | log("script2"); 4 | -------------------------------------------------------------------------------- /test/manifest/resources/optionsHtml/options.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /test/manifest/resources/optionsHtml/options.js: -------------------------------------------------------------------------------- 1 | import log from "./../shared/log"; 2 | 3 | log("options"); 4 | -------------------------------------------------------------------------------- /test/manifest/resources/popupHtml/popup.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /test/manifest/resources/popupHtml/popup.js: -------------------------------------------------------------------------------- 1 | import log from "./../shared/log"; 2 | 3 | log("popup"); 4 | -------------------------------------------------------------------------------- /test/manifest/resources/shared/log.js: -------------------------------------------------------------------------------- 1 | export default function log(message) { 2 | console.log(message); 3 | } 4 | -------------------------------------------------------------------------------- /test/manifest/resources/sidePanelHtml/sidepanel.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /test/manifest/resources/sidePanelHtml/sidepanel.js: -------------------------------------------------------------------------------- 1 | import log from "./../shared/log"; 2 | 3 | log("sidepanel"); 4 | -------------------------------------------------------------------------------- /test/manifest/resources/useDynamicUrlWebAccessibleResources/content1.js: -------------------------------------------------------------------------------- 1 | import log from "./../shared/log"; 2 | 3 | log("content"); 4 | -------------------------------------------------------------------------------- /test/manifest/resources/useDynamicUrlWebAccessibleResources/content2.js: -------------------------------------------------------------------------------- 1 | import log from "./../shared/log"; 2 | 3 | log("content2"); 4 | -------------------------------------------------------------------------------- /test/manifest/resources/useDynamicUrlWebAccessibleResources/script1.js: -------------------------------------------------------------------------------- 1 | import log from "../shared/log"; 2 | 3 | log("script1"); 4 | -------------------------------------------------------------------------------- /test/manifest/resources/useDynamicUrlWebAccessibleResources/script2.js: -------------------------------------------------------------------------------- 1 | import log from "../shared/log"; 2 | 3 | log("script2"); 4 | -------------------------------------------------------------------------------- /test/manifest/sidePanelHtml.v3.test.ts: -------------------------------------------------------------------------------- 1 | import { getResourceDir, runManifestV3Test } from "./manifestTestUtils"; 2 | 3 | const resourceDir = getResourceDir("sidePanelHtml"); 4 | 5 | runManifestV3Test("sidePanelHtml", () => ({ 6 | side_panel: { 7 | default_path: `${resourceDir}/sidepanel.html`, 8 | }, 9 | })); 10 | -------------------------------------------------------------------------------- /test/manifest/useDynamicUrlWebAccessibleResourcesDisabled.v3.test.ts: -------------------------------------------------------------------------------- 1 | import { getResourceDir, runManifestV3Test } from "./manifestTestUtils"; 2 | 3 | const resourceDir = getResourceDir("useDynamicUrlWebAccessibleResources"); 4 | 5 | runManifestV3Test( 6 | "useDynamicUrlWebAccessibleResourcesDisabled", 7 | () => ({ 8 | content_scripts: [ 9 | { 10 | js: [`${resourceDir}/content1.js`], 11 | matches: [""], 12 | }, 13 | { 14 | js: [`${resourceDir}/content2.js`], 15 | matches: [""], 16 | }, 17 | ], 18 | }), 19 | { 20 | additionalInputs: { 21 | scripts: [`${resourceDir}/script1.js`, `${resourceDir}/script2.js`], 22 | }, 23 | useDynamicUrlWebAccessibleResources: false, 24 | } 25 | ); 26 | -------------------------------------------------------------------------------- /test/manifest/useDynamicUrlWebAccessibleResourcesEnabled.v3.test.ts: -------------------------------------------------------------------------------- 1 | import { getResourceDir, runManifestV3Test } from "./manifestTestUtils"; 2 | 3 | const resourceDir = getResourceDir("useDynamicUrlWebAccessibleResources"); 4 | 5 | runManifestV3Test( 6 | "useDynamicUrlWebAccessibleResourcesEnabled", 7 | () => ({ 8 | content_scripts: [ 9 | { 10 | js: [`${resourceDir}/content1.js`], 11 | matches: [""], 12 | }, 13 | { 14 | js: [`${resourceDir}/content2.js`], 15 | matches: [""], 16 | }, 17 | ], 18 | }), 19 | { 20 | additionalInputs: { 21 | scripts: [`${resourceDir}/script1.js`, `${resourceDir}/script2.js`], 22 | }, 23 | useDynamicUrlWebAccessibleResources: true, 24 | } 25 | ); 26 | -------------------------------------------------------------------------------- /test/manifest/useDynamicUrlWebAccessibleResourcesUndefined.v3.test.ts: -------------------------------------------------------------------------------- 1 | import { getResourceDir, runManifestV3Test } from "./manifestTestUtils"; 2 | 3 | const resourceDir = getResourceDir("useDynamicUrlWebAccessibleResources"); 4 | 5 | runManifestV3Test( 6 | "useDynamicUrlWebAccessibleResourcesEnabled", 7 | () => ({ 8 | content_scripts: [ 9 | { 10 | js: [`${resourceDir}/content1.js`], 11 | matches: [""], 12 | }, 13 | { 14 | js: [`${resourceDir}/content2.js`], 15 | matches: [""], 16 | }, 17 | ], 18 | }), 19 | { 20 | additionalInputs: { 21 | scripts: [`${resourceDir}/script1.js`, `${resourceDir}/script2.js`], 22 | }, 23 | } 24 | ); 25 | -------------------------------------------------------------------------------- /test/utils/addHmrSupportToCsp.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, expect, it } from "vitest"; 2 | import parse from "content-security-policy-parser"; 3 | 4 | import { addHmrSupportToCsp } from "./../../src/utils/addHmrSupportToCsp"; 5 | 6 | const basicCsp = 7 | "script-src 'self' https://app.foo.com; connect-src https://*.googleapis.com; image-src 'self'; object-src 'self'"; 8 | const basicCspWithDupes = 9 | "script-src 'self' https://app.foo.com 'self'; connect-src https://*.googleapis.com; image-src 'self'; object-src 'none' 'none'"; 10 | 11 | describe("Creating an HMR friendly CSP document", () => { 12 | it("should work without a passed in existing CSP", () => { 13 | const cspStr = addHmrSupportToCsp("http://localhost:5173", []); 14 | const csp = parse(cspStr); 15 | 16 | expect(csp["script-src"].length).toEqual(2); 17 | expect(csp["script-src"]).toContain("'self'"); 18 | expect(csp["script-src"]).toContain("http://localhost:5173"); 19 | expect(csp["object-src"].length).toEqual(1); 20 | expect(csp["object-src"]).toContain("'self'"); 21 | }); 22 | it("should let us pass in our own document", () => { 23 | const cspStr = addHmrSupportToCsp("http://localhost:5173", [], basicCsp); 24 | const csp = parse(cspStr); 25 | 26 | expect(csp["script-src"].length).toEqual(3); 27 | expect(csp["object-src"].length).toEqual(1); 28 | }); 29 | it("should let us include inline hashes", () => { 30 | const cspStr = addHmrSupportToCsp( 31 | "http://localhost:5173", 32 | new Set([ 33 | "sha256-B2yPHKaXnvFWtRChIbabYmUBFZdVfKKXHbWtWidDVF8=", 34 | "sha256-B2yPHKaXnvFWtRChIbabYmUBFZdVfKKXHbWtWidDVF7=", 35 | ]), 36 | basicCsp 37 | ); 38 | const csp = parse(cspStr); 39 | 40 | expect(csp["script-src"].length).toEqual(5); 41 | }); 42 | 43 | it("should let dedupe values", () => { 44 | const cspStr = addHmrSupportToCsp( 45 | "http://localhost:5173", 46 | new Set([ 47 | "sha256-B2yPHKaXnvFWtRChIbabYmUBFZdVfKKXHbWtWidDVF8=", 48 | "sha256-B2yPHKaXnvFWtRChIbabYmUBFZdVfKKXHbWtWidDVF7=", 49 | ]), 50 | basicCspWithDupes 51 | ); 52 | const csp = parse(cspStr); 53 | 54 | expect(csp["script-src"].length).toEqual(5); 55 | expect(csp["object-src"].length).toEqual(2); 56 | }); 57 | }); 58 | -------------------------------------------------------------------------------- /test/utils/rollup.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, it, expect } from "vitest"; 2 | import { addInputScriptsToOptionsInput } from "./../../src/utils/rollup"; 3 | 4 | describe("Rollup Utils", () => { 5 | describe("addInputScriptsToOptionsInput", () => { 6 | it("Adds input scripts to string input", () => { 7 | expect( 8 | addInputScriptsToOptionsInput( 9 | [["outputFile.js", "inputFile.js"]], 10 | "src/index.js" 11 | ) 12 | ).toEqual({ 13 | "src/index.js": "src/index.js", 14 | "outputFile.js": "inputFile.js", 15 | }); 16 | }); 17 | 18 | it("Adds input scripts to array input", () => { 19 | expect( 20 | addInputScriptsToOptionsInput( 21 | [["outputFile.js", "inputFile.js"]], 22 | ["src/index.js", "src/index2.js"] 23 | ) 24 | ).toEqual({ 25 | "src/index.js": "src/index.js", 26 | "src/index2.js": "src/index2.js", 27 | "outputFile.js": "inputFile.js", 28 | }); 29 | }); 30 | 31 | it("Adds input scripts to empty options input object", () => { 32 | expect( 33 | addInputScriptsToOptionsInput([["outputFile.js", "inputFile.js"]], {}) 34 | ).toEqual({ 35 | "outputFile.js": "inputFile.js", 36 | }); 37 | }); 38 | 39 | it("Adds input scripts to options input object with existing entries", () => { 40 | expect( 41 | addInputScriptsToOptionsInput([["outputFile2.js", "inputFile2.js"]], { 42 | "outputFile.js": "inputFile.js", 43 | }) 44 | ).toEqual({ 45 | "outputFile.js": "inputFile.js", 46 | "outputFile2.js": "inputFile2.js", 47 | }); 48 | }); 49 | }); 50 | }); 51 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "allowSyntheticDefaultImports": true, 4 | "esModuleInterop": true, 5 | "lib": ["es2021"], 6 | "module": "esnext", 7 | "moduleResolution": "bundler", 8 | "noEmit": true, 9 | "noEmitOnError": false, 10 | "noUnusedLocals": true, 11 | "noUnusedParameters": true, 12 | "pretty": true, 13 | "sourceMap": true, 14 | "strict": true, 15 | "target": "es2021", 16 | "skipLibCheck": true 17 | }, 18 | "exclude": ["dist", "node_modules", "test/types"], 19 | "include": ["src/**/*", "types/**/*"] 20 | } 21 | -------------------------------------------------------------------------------- /types/index.d.ts: -------------------------------------------------------------------------------- 1 | import type { Plugin } from "vite"; 2 | 3 | type WebAccessibleDefinition = 4 | | { 5 | matches: string[]; 6 | extensionIds?: string[]; 7 | excludeEntryFile?: boolean; 8 | } 9 | | { 10 | matches?: string[]; 11 | extensionIds: string[]; 12 | excludeEntryFile?: boolean; 13 | }; 14 | 15 | type AdditionalInput = 16 | | string 17 | | { 18 | fileName: string; 19 | webAccessible: boolean | WebAccessibleDefinition; 20 | }; 21 | 22 | type NormalizedAdditionalInput = { 23 | fileName: string; 24 | webAccessible: WebAccessibleDefinition | null; 25 | }; 26 | 27 | export interface ViteWebExtensionOptions { 28 | /** 29 | * The manifest file to use as a base for the generated extension 30 | */ 31 | manifest: chrome.runtime.Manifest; 32 | 33 | /** 34 | * Sets the use_dynamic_url property on web accessible resources generated by the plugin 35 | * Default: true 36 | */ 37 | useDynamicUrlWebAccessibleResources?: boolean; 38 | 39 | /** 40 | * On build, in Manifest V3, merge web accessible resource definitions that have matching non-`resource` properties and dedupe and sort `resources`. In Manifest V2, sort web accessible resources. 41 | * Default: true 42 | */ 43 | optimizeWebAccessibleResources?: boolean; 44 | 45 | /** 46 | * Additional input files that should be processed and treated as web extension inputs. 47 | * Useful for dynamically injected scripts and dynamically opened HTML pages. 48 | * The webAccessible option configures whether the entry file and its dependencies are included in the manifest `web_accessible_resources` property. Defaults to true. 49 | * When set to `true`, defaults to: 50 | ```ts 51 | { 52 | matches: [''], 53 | excludeEntryFile: false, 54 | } 55 | ``` 56 | * The `excludeEntryFile` option prevents the entry file from being added as a web accessible resource. Defaults to false. 57 | */ 58 | additionalInputs?: { 59 | scripts?: AdditionalInput[]; 60 | html?: AdditionalInput[]; 61 | styles?: AdditionalInput[]; 62 | }; 63 | } 64 | 65 | /** 66 | * Build cross platform, module-based web extensions using vite 67 | */ 68 | export default function webExtension(options?: ViteWebExtensionOptions): Plugin; 69 | --------------------------------------------------------------------------------