Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 69e840b984 | |||
| 2fb5a542d3 | |||
| 84657e035a | |||
| 6f5bf89645 | |||
| 90fa6bfc40 |
@@ -1,5 +1,33 @@
|
||||
# Changelog
|
||||
|
||||
## v0.2.2
|
||||
|
||||
[compare changes](https://github.com/aklinker1/wxt/compare/v0.2.1...v0.2.2)
|
||||
|
||||
### 🩹 Fixes
|
||||
|
||||
- Register content scripts correctly ([2fb5a54](https://github.com/aklinker1/wxt/commit/2fb5a54))
|
||||
|
||||
### ❤️ Contributors
|
||||
|
||||
- Aaron Klinker
|
||||
|
||||
## v0.2.1
|
||||
|
||||
[compare changes](https://github.com/aklinker1/wxt/compare/v0.2.0...v0.2.1)
|
||||
|
||||
### 🚀 Enhancements
|
||||
|
||||
- Support all content script options ([6f5bf89](https://github.com/aklinker1/wxt/commit/6f5bf89))
|
||||
|
||||
### 🩹 Fixes
|
||||
|
||||
- Remove HMR log ([90fa6bf](https://github.com/aklinker1/wxt/commit/90fa6bf))
|
||||
|
||||
### ❤️ Contributors
|
||||
|
||||
- Aaron Klinker
|
||||
|
||||
## v0.2.0
|
||||
|
||||
[compare changes](https://github.com/aklinker1/wxt/compare/v0.1.6...v0.2.0)
|
||||
|
||||
@@ -17,6 +17,10 @@ When a filename matches the pattern below, it is added as a content script in th
|
||||
export default defineContentScript({
|
||||
// Set manifest options
|
||||
matches: ['*://google.com/*', '*://duckduckgo.com/*'],
|
||||
excludeMatches: undefined | [],
|
||||
includeGlobs: undefined | [],
|
||||
excludeGlobs: undefined | [],
|
||||
allFrames: undefined | [],
|
||||
runAt: undefined | 'document_start' | 'document_end' | 'document_idle',
|
||||
matchAboutBlank: undefined | true | false,
|
||||
matchOriginAsFallback: undefined | true | false,
|
||||
|
||||
@@ -149,7 +149,7 @@ describe('Manifest Content', () => {
|
||||
`import "./style.css";
|
||||
export default defineContentScript({
|
||||
matches: ["*://google.com/*"],
|
||||
run_at: "document_end",
|
||||
runAt: "document_end",
|
||||
main: () => {},
|
||||
})`,
|
||||
);
|
||||
@@ -162,7 +162,7 @@ describe('Manifest Content', () => {
|
||||
`import "./style.css";
|
||||
export default defineContentScript({
|
||||
matches: ["*://google.com/*"],
|
||||
run_at: "document_end",
|
||||
runAt: "document_end",
|
||||
main: () => {},
|
||||
})`,
|
||||
);
|
||||
@@ -175,7 +175,7 @@ describe('Manifest Content', () => {
|
||||
`import "./style.css";
|
||||
export default defineContentScript({
|
||||
matches: ["*://duckduckgo.com/*"],
|
||||
run_at: "document_end",
|
||||
runAt: "document_end",
|
||||
main: () => {},
|
||||
})`,
|
||||
);
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "wxt",
|
||||
"type": "module",
|
||||
"version": "0.2.0",
|
||||
"version": "0.2.2",
|
||||
"description": "Next gen framework for developing web extensions",
|
||||
"engines": {
|
||||
"node": ">=18.16.0",
|
||||
|
||||
+5
-3
@@ -6,7 +6,7 @@ import {
|
||||
} from './types';
|
||||
import * as vite from 'vite';
|
||||
import { findOpenPort } from './utils/findOpenPort';
|
||||
import { Manifest } from 'webextension-polyfill';
|
||||
import { Scripting } from 'webextension-polyfill';
|
||||
import { getEntrypointBundlePath } from './utils/entrypoints';
|
||||
import { getContentScriptCssFiles } from './utils/manifest';
|
||||
import { createWebExtRunner } from './runners/createWebExtRunner';
|
||||
@@ -58,7 +58,9 @@ export async function setupServer(
|
||||
// paths ending in "/index.html"
|
||||
viteServer.ws.send('wxt:reload-page', path);
|
||||
};
|
||||
const reloadContentScript = (contentScript: Manifest.ContentScript) => {
|
||||
const reloadContentScript = (
|
||||
contentScript: Omit<Scripting.RegisteredContentScript, 'id'>,
|
||||
) => {
|
||||
viteServer.ws.send('wxt:reload-content-script', contentScript);
|
||||
};
|
||||
|
||||
@@ -102,9 +104,9 @@ export function reloadContentScripts(
|
||||
const css = getContentScriptCssFiles([entry], server.currentOutput);
|
||||
|
||||
server.reloadContentScript({
|
||||
...entry.options,
|
||||
js,
|
||||
css,
|
||||
...entry.options,
|
||||
});
|
||||
});
|
||||
} else {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import * as vite from 'vite';
|
||||
import { Manifest } from 'webextension-polyfill';
|
||||
import { Manifest, Scripting } from 'webextension-polyfill';
|
||||
import { UnimportOptions } from 'unimport';
|
||||
import { EntrypointGroup } from '.';
|
||||
|
||||
@@ -152,7 +152,9 @@ export interface WxtDevServer extends vite.ViteDevServer {
|
||||
*
|
||||
* @param contentScript The manifest definition for a content script
|
||||
*/
|
||||
reloadContentScript: (contentScript: Manifest.ContentScript) => void;
|
||||
reloadContentScript: (
|
||||
contentScript: Omit<Scripting.RegisteredContentScript, 'id'>,
|
||||
) => void;
|
||||
}
|
||||
|
||||
export type TargetBrowser = 'chrome' | 'firefox' | 'safari' | 'edge' | 'opera';
|
||||
@@ -255,11 +257,50 @@ export type Entrypoint =
|
||||
export type OnContentScriptStopped = (cb: () => void) => void;
|
||||
|
||||
export interface ContentScriptDefinition {
|
||||
matches: string[];
|
||||
runAt?: 'document_start' | 'document_end' | 'document_idle';
|
||||
matchAboutBlank?: boolean;
|
||||
matches: Manifest.ContentScript['matches'];
|
||||
/**
|
||||
* See https://developer.chrome.com/docs/extensions/mv3/content_scripts/
|
||||
* @default "documentIdle"
|
||||
*/
|
||||
runAt?: Manifest.ContentScript['run_at'];
|
||||
/**
|
||||
* See https://developer.chrome.com/docs/extensions/mv3/content_scripts/
|
||||
* @default false
|
||||
*/
|
||||
matchAboutBlank?: Manifest.ContentScript['match_about_blank'];
|
||||
/**
|
||||
* See https://developer.chrome.com/docs/extensions/mv3/content_scripts/
|
||||
* @default []
|
||||
*/
|
||||
excludeMatches?: Manifest.ContentScript['exclude_matches'];
|
||||
/**
|
||||
* See https://developer.chrome.com/docs/extensions/mv3/content_scripts/
|
||||
* @default []
|
||||
*/
|
||||
includeGlobs?: Manifest.ContentScript['include_globs'];
|
||||
/**
|
||||
* See https://developer.chrome.com/docs/extensions/mv3/content_scripts/
|
||||
* @default []
|
||||
*/
|
||||
excludeGlobs?: Manifest.ContentScript['exclude_globs'];
|
||||
/**
|
||||
* See https://developer.chrome.com/docs/extensions/mv3/content_scripts/
|
||||
* @default false
|
||||
*/
|
||||
allFrames?: Manifest.ContentScript['all_frames'];
|
||||
/**
|
||||
* See https://developer.chrome.com/docs/extensions/mv3/content_scripts/
|
||||
* @default false
|
||||
*/
|
||||
matchOriginAsFallback?: boolean;
|
||||
/**
|
||||
* See https://developer.chrome.com/docs/extensions/mv3/content_scripts/
|
||||
* @default "ISOLATED"
|
||||
*/
|
||||
world?: 'ISOLATED' | 'MAIN';
|
||||
/**
|
||||
* Main function executed when the content script is loaded.
|
||||
*/
|
||||
main(): void | Promise<void>;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { hashContentScriptOptions } from '../content-scripts';
|
||||
|
||||
describe('Content Script Utils', () => {
|
||||
describe('hashContentScriptOptions', () => {
|
||||
it('should return a string containing all the options with defaults applied', () => {
|
||||
const hash = hashContentScriptOptions({ matches: [] });
|
||||
|
||||
expect(hash).toMatchInlineSnapshot(
|
||||
'"[[\\"allFrames\\",false],[\\"excludeGlobs\\",[]],[\\"excludeMatches\\",[]],[\\"includeGlobs\\",[]],[\\"matchAboutBlank\\",false],[\\"matches\\",[]],[\\"matchOriginAsFallback\\",false],[\\"runAt\\",\\"document_idle\\"],[\\"world\\",\\"ISOLATED\\"]]"',
|
||||
);
|
||||
});
|
||||
|
||||
it('should be consistent regardless of the object ordering and default values', () => {
|
||||
const hash1 = hashContentScriptOptions({
|
||||
allFrames: true,
|
||||
matches: ['*://google.com/*', '*://duckduckgo.com/*'],
|
||||
matchAboutBlank: false,
|
||||
});
|
||||
const hash2 = hashContentScriptOptions({
|
||||
matches: ['*://duckduckgo.com/*', '*://google.com/*'],
|
||||
allFrames: true,
|
||||
});
|
||||
|
||||
expect(hash1).toBe(hash2);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,52 @@
|
||||
import { Manifest } from 'webextension-polyfill';
|
||||
import { ContentScriptEntrypoint } from '../types';
|
||||
|
||||
/**
|
||||
* Returns a unique and consistent string hash based on a content scripts options.
|
||||
*
|
||||
* It is able to recognize default values,
|
||||
*/
|
||||
export function hashContentScriptOptions(
|
||||
options: ContentScriptEntrypoint['options'],
|
||||
): string {
|
||||
const withDefaults: ContentScriptEntrypoint['options'] = {
|
||||
excludeGlobs: [],
|
||||
excludeMatches: [],
|
||||
includeGlobs: [],
|
||||
matchAboutBlank: false,
|
||||
matchOriginAsFallback: false,
|
||||
runAt: 'document_idle',
|
||||
allFrames: false,
|
||||
world: 'ISOLATED',
|
||||
// TODO: strip undefined fields from options object to improve content script grouping.
|
||||
...options,
|
||||
};
|
||||
return JSON.stringify(
|
||||
Object.entries(withDefaults)
|
||||
// Sort any arrays so their values are consistent
|
||||
.map<[string, unknown]>(([key, value]) => {
|
||||
if (Array.isArray(value)) return [key, value.sort()];
|
||||
else return [key, value];
|
||||
})
|
||||
// Sort all the fields alphabetically
|
||||
.sort((l, r) => l[0].localeCompare(r[0])),
|
||||
);
|
||||
}
|
||||
|
||||
export function mapWxtOptionsToContentScript(
|
||||
options: ContentScriptEntrypoint['options'],
|
||||
): Omit<Manifest.ContentScript, 'js' | 'css'> {
|
||||
return {
|
||||
matches: options.matches,
|
||||
all_frames: options.allFrames,
|
||||
match_about_blank: options.matchAboutBlank,
|
||||
exclude_globs: options.excludeGlobs,
|
||||
exclude_matches: options.excludeMatches,
|
||||
include_globs: options.includeGlobs,
|
||||
run_at: options.runAt,
|
||||
|
||||
// @ts-expect-error: untyped chrome options
|
||||
match_origin_as_fallback: options.matchOriginAsFallback,
|
||||
world: options.world,
|
||||
};
|
||||
}
|
||||
@@ -122,7 +122,6 @@ export async function getInternalConfig(
|
||||
);
|
||||
finalConfig.vite.plugins.push(plugins.devServerGlobals(finalConfig));
|
||||
finalConfig.vite.plugins.push(plugins.tsconfigPaths(finalConfig));
|
||||
finalConfig.vite.plugins.push(plugins.hmrLogger(finalConfig));
|
||||
|
||||
finalConfig.vite.define ??= {};
|
||||
getGlobals(finalConfig).forEach((global) => {
|
||||
|
||||
@@ -12,6 +12,10 @@ import fs from 'fs-extra';
|
||||
import { resolve } from 'path';
|
||||
import { getEntrypointBundlePath } from './entrypoints';
|
||||
import { ContentSecurityPolicy } from './ContentSecurityPolicy';
|
||||
import {
|
||||
hashContentScriptOptions,
|
||||
mapWxtOptionsToContentScript,
|
||||
} from './content-scripts';
|
||||
|
||||
/**
|
||||
* Writes the manifest to the output directory and the build output.
|
||||
@@ -285,7 +289,7 @@ function addEntrypoints(
|
||||
);
|
||||
} else {
|
||||
const hashToEntrypointsMap = contentScripts.reduce((map, script) => {
|
||||
const hash = JSON.stringify(script.options);
|
||||
const hash = hashContentScriptOptions(script.options);
|
||||
if (map.has(hash)) map.get(hash)?.push(script);
|
||||
else map.set(hash, [script]);
|
||||
return map;
|
||||
@@ -293,7 +297,7 @@ function addEntrypoints(
|
||||
|
||||
manifest.content_scripts = Array.from(hashToEntrypointsMap.entries()).map(
|
||||
([, scripts]) => ({
|
||||
...scripts[0].options,
|
||||
...mapWxtOptionsToContentScript(scripts[0].options),
|
||||
// TOOD: Sorting css and js arrays here so we get consistent test results... but we
|
||||
// shouldn't have to. Where is the inconsistency coming from?
|
||||
css: getContentScriptCssFiles(scripts, buildOutput)?.sort(),
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
import { Plugin } from 'vite';
|
||||
import { InternalConfig } from '../types';
|
||||
import { relative } from 'path';
|
||||
import pc from 'picocolors';
|
||||
|
||||
/**
|
||||
* Log when HMR changes are fired
|
||||
*/
|
||||
export function hmrLogger(config: InternalConfig): Plugin {
|
||||
return {
|
||||
name: 'wxt:hmr-logger',
|
||||
apply: 'serve',
|
||||
handleHotUpdate(ctx) {
|
||||
if (
|
||||
ctx.file.startsWith(config.srcDir) &&
|
||||
!ctx.file.startsWith(config.wxtDir) &&
|
||||
!ctx.file.endsWith('.html')
|
||||
) {
|
||||
config.logger.info(
|
||||
'Hot reload: ' + pc.dim(relative(process.cwd(), ctx.file)),
|
||||
);
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -5,4 +5,3 @@ export * from './multipageMove';
|
||||
export * from './unimport';
|
||||
export * from './virtualEntrypoint';
|
||||
export * from './tsconfigPaths';
|
||||
export * from './hmrLogger';
|
||||
|
||||
Reference in New Issue
Block a user