Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 969e39c541 | |||
| b256939cc4 | |||
| c46137644b | |||
| 1bd7ef56c4 | |||
| c258b99cec |
+16
-3
@@ -1,5 +1,18 @@
|
||||
# Changelog
|
||||
|
||||
## v0.16.10
|
||||
|
||||
[compare changes](https://github.com/wxt-dev/wxt/compare/v0.16.9...v0.16.10)
|
||||
|
||||
### 🚀 Enhancements
|
||||
|
||||
- Customize when content scripts are registered, in the manifest or at runtime ([#471](https://github.com/wxt-dev/wxt/pull/471))
|
||||
|
||||
### 🩹 Fixes
|
||||
|
||||
- Don't assume react when importing JSX entrypoints during build ([#470](https://github.com/wxt-dev/wxt/pull/470))
|
||||
- Respect `configFile` option ([#472](https://github.com/wxt-dev/wxt/pull/472))
|
||||
|
||||
## v0.16.9
|
||||
|
||||
[compare changes](https://github.com/wxt-dev/wxt/compare/v0.16.8...v0.16.9)
|
||||
@@ -22,7 +35,7 @@
|
||||
|
||||
### ❤️ Contributors
|
||||
|
||||
- Okou
|
||||
- Okou ([@ookkoouu](https://github.com/ookkoouu))
|
||||
|
||||
## v0.16.8
|
||||
|
||||
@@ -83,8 +96,8 @@
|
||||
|
||||
### ❤️ Contributors
|
||||
|
||||
- Lionelhorn
|
||||
- Okou
|
||||
- Lionelhorn ([@Lionelhorn](https://github.com/Lionelhorn))
|
||||
- Okou ([@ookkoouu](https://github.com/ookkoouu))
|
||||
|
||||
## v0.16.5
|
||||
|
||||
|
||||
@@ -37,6 +37,9 @@ export default defineContentScript({
|
||||
// Configure how CSS is injected onto the page
|
||||
cssInjectionMode: undefined | "manifest" | "manual" | "ui",
|
||||
|
||||
// Configure how/when content script will be registered
|
||||
registration: undefined | "manifest" | "runtime",
|
||||
|
||||
main(ctx) {
|
||||
// Executed when content script is loaded
|
||||
},
|
||||
|
||||
@@ -107,4 +107,29 @@ describe('User Config', () => {
|
||||
});
|
||||
expect(withoutPolyfill).not.toBe(withPolyfill);
|
||||
});
|
||||
|
||||
it('should respect changing config files', async () => {
|
||||
const project = new TestProject();
|
||||
project.addFile(
|
||||
'src/entrypoints/background.ts',
|
||||
`export default defineBackground(
|
||||
() => console.log('Hello background'),
|
||||
);`,
|
||||
);
|
||||
project.addFile(
|
||||
'test.config.ts',
|
||||
`import { defineConfig } from 'wxt';
|
||||
|
||||
export default defineConfig({
|
||||
outDir: ".custom-output",
|
||||
srcDir: "src",
|
||||
});`,
|
||||
);
|
||||
|
||||
await project.build({ configFile: 'test.config.ts' });
|
||||
|
||||
expect(
|
||||
await project.fileExists('.custom-output/chrome-mv3/background.js'),
|
||||
).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "wxt",
|
||||
"type": "module",
|
||||
"version": "0.16.9",
|
||||
"version": "0.16.10",
|
||||
"description": "Next gen framework for developing web extensions",
|
||||
"engines": {
|
||||
"node": ">=18",
|
||||
|
||||
@@ -4,6 +4,7 @@ import {
|
||||
fakeArray,
|
||||
fakeBackgroundEntrypoint,
|
||||
fakeBuildOutput,
|
||||
fakeContentScriptEntrypoint,
|
||||
fakeEntrypoint,
|
||||
fakeManifestCommand,
|
||||
fakeOptionsEntrypoint,
|
||||
@@ -757,6 +758,70 @@ describe('Manifest Utils', () => {
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('registration', () => {
|
||||
it('should throw an error when registration=runtime for MV2', async () => {
|
||||
const cs: ContentScriptEntrypoint = fakeContentScriptEntrypoint({
|
||||
options: {
|
||||
registration: 'runtime',
|
||||
},
|
||||
});
|
||||
|
||||
const entrypoints = [cs];
|
||||
const buildOutput: Omit<BuildOutput, 'manifest'> = {
|
||||
publicAssets: [],
|
||||
steps: [{ entrypoints: cs, chunks: [] }],
|
||||
};
|
||||
setFakeWxt({
|
||||
config: {
|
||||
manifestVersion: 2,
|
||||
},
|
||||
});
|
||||
|
||||
await expect(
|
||||
generateManifest(entrypoints, buildOutput),
|
||||
).rejects.toThrowError();
|
||||
});
|
||||
|
||||
it('should add host_permissions instead of content_scripts when registration=runtime', async () => {
|
||||
const cs: ContentScriptEntrypoint = {
|
||||
type: 'content-script',
|
||||
name: 'one',
|
||||
inputPath: 'entrypoints/one.content.ts',
|
||||
outputDir: contentScriptOutDir,
|
||||
options: {
|
||||
matches: ['*://google.com/*'],
|
||||
registration: 'runtime',
|
||||
},
|
||||
skipped: false,
|
||||
};
|
||||
const styles: OutputAsset = {
|
||||
type: 'asset',
|
||||
fileName: 'content-scripts/one.css',
|
||||
};
|
||||
|
||||
const entrypoints = [cs];
|
||||
const buildOutput: Omit<BuildOutput, 'manifest'> = {
|
||||
publicAssets: [],
|
||||
steps: [{ entrypoints: cs, chunks: [styles] }],
|
||||
};
|
||||
setFakeWxt({
|
||||
config: {
|
||||
manifestVersion: 3,
|
||||
outDir,
|
||||
command: 'build',
|
||||
},
|
||||
});
|
||||
|
||||
const { manifest: actual } = await generateManifest(
|
||||
entrypoints,
|
||||
buildOutput,
|
||||
);
|
||||
|
||||
expect(actual.content_scripts).toEqual([]);
|
||||
expect(actual.host_permissions).toEqual(['*://google.com/*']);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('sidepanel', () => {
|
||||
|
||||
@@ -105,6 +105,13 @@ function getEsbuildOptions(opts: JitiTransformOptions): TransformOptions {
|
||||
return {
|
||||
format: 'cjs',
|
||||
loader: isJsx ? 'tsx' : 'ts',
|
||||
jsx: isJsx ? 'automatic' : undefined,
|
||||
...(isJsx
|
||||
? {
|
||||
// `h` and `Fragment` are undefined, but that's OK because JSX is never evaluated while
|
||||
// grabbing the entrypoint's options.
|
||||
jsxFactory: 'h',
|
||||
jsxFragment: 'Fragment',
|
||||
}
|
||||
: undefined),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -37,6 +37,7 @@ export async function resolveConfig(
|
||||
let userConfigMetadata: ResolvedConfig['userConfigMetadata'] | undefined;
|
||||
if (inlineConfig.configFile !== false) {
|
||||
const { config: loadedConfig, ...metadata } = await loadConfig<UserConfig>({
|
||||
configFile: inlineConfig.configFile,
|
||||
name: 'wxt',
|
||||
cwd: inlineConfig.root ?? process.cwd(),
|
||||
rcFile: false,
|
||||
|
||||
+39
-22
@@ -355,37 +355,54 @@ function addEntrypoints(
|
||||
// Don't add content scripts to the manifest in dev mode for MV3 - they're managed and reloaded
|
||||
// at runtime
|
||||
if (wxt.config.command === 'serve' && wxt.config.manifestVersion === 3) {
|
||||
const hostPermissions = new Set<string>(manifest.host_permissions ?? []);
|
||||
contentScripts.forEach((script) => {
|
||||
script.options.matches.forEach((matchPattern) => {
|
||||
hostPermissions.add(matchPattern);
|
||||
addHostPermission(manifest, matchPattern);
|
||||
});
|
||||
});
|
||||
hostPermissions.forEach((permission) =>
|
||||
addHostPermission(manifest, permission),
|
||||
);
|
||||
} else {
|
||||
const hashToEntrypointsMap = contentScripts.reduce((map, script) => {
|
||||
const hash = hashContentScriptOptions(script.options);
|
||||
if (map.has(hash)) map.get(hash)?.push(script);
|
||||
else map.set(hash, [script]);
|
||||
return map;
|
||||
}, new Map<string, ContentScriptEntrypoint[]>());
|
||||
|
||||
const newContentScripts = Array.from(hashToEntrypointsMap.entries()).map(
|
||||
([, scripts]) =>
|
||||
mapWxtOptionsToContentScript(
|
||||
scripts[0].options,
|
||||
scripts.map((entry) =>
|
||||
getEntrypointBundlePath(entry, wxt.config.outDir, '.js'),
|
||||
),
|
||||
getContentScriptCssFiles(scripts, cssMap),
|
||||
// Manifest scripts
|
||||
const hashToEntrypointsMap = contentScripts
|
||||
.filter((cs) => cs.options.registration !== 'runtime')
|
||||
.reduce((map, script) => {
|
||||
const hash = hashContentScriptOptions(script.options);
|
||||
if (map.has(hash)) map.get(hash)?.push(script);
|
||||
else map.set(hash, [script]);
|
||||
return map;
|
||||
}, new Map<string, ContentScriptEntrypoint[]>());
|
||||
const manifestContentScripts = Array.from(
|
||||
hashToEntrypointsMap.values(),
|
||||
).map((scripts) =>
|
||||
mapWxtOptionsToContentScript(
|
||||
scripts[0].options,
|
||||
scripts.map((entry) =>
|
||||
getEntrypointBundlePath(entry, wxt.config.outDir, '.js'),
|
||||
),
|
||||
getContentScriptCssFiles(scripts, cssMap),
|
||||
),
|
||||
);
|
||||
if (newContentScripts.length >= 0) {
|
||||
if (manifestContentScripts.length >= 0) {
|
||||
manifest.content_scripts ??= [];
|
||||
manifest.content_scripts.push(...newContentScripts);
|
||||
manifest.content_scripts.push(...manifestContentScripts);
|
||||
}
|
||||
|
||||
// Runtime content scripts
|
||||
const runtimeContentScripts = contentScripts.filter(
|
||||
(cs) => cs.options.registration === 'runtime',
|
||||
);
|
||||
if (
|
||||
runtimeContentScripts.length > 0 &&
|
||||
wxt.config.manifestVersion === 2
|
||||
) {
|
||||
throw Error(
|
||||
'Cannot use `registration: "runtime"` with MV2 content scripts, it is a MV3-only feature.',
|
||||
);
|
||||
}
|
||||
runtimeContentScripts.forEach((script) => {
|
||||
script.options.matches.forEach((matchPattern) => {
|
||||
addHostPermission(manifest, matchPattern);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
const contentScriptCssResources = getContentScriptCssWebAccessibleResources(
|
||||
|
||||
@@ -507,6 +507,18 @@ export interface BaseContentScriptEntrypointOptions
|
||||
* @default "manifest"
|
||||
*/
|
||||
cssInjectionMode?: PerBrowserOption<'manifest' | 'manual' | 'ui'>;
|
||||
/**
|
||||
* Specify how the content script is registered.
|
||||
*
|
||||
* - `"manifest"`: The content script will be added to the `content_scripts` entry in the
|
||||
* manifest. This is the normal and most well known way of registering a content script.
|
||||
* - `"runtime"`: The content script's `matches` is added to `host_permissions` and you are
|
||||
* responsible for using the scripting API to register the content script dynamically at
|
||||
* runtime.
|
||||
*
|
||||
* @default "manifest"
|
||||
*/
|
||||
registration?: PerBrowserOption<'manifest' | 'runtime'>;
|
||||
}
|
||||
|
||||
export interface MainWorldContentScriptEntrypointOptions
|
||||
|
||||
Reference in New Issue
Block a user