Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 7e37e11caf | |||
| bb90029c54 | |||
| d3b14afbce | |||
| ba2197a609 | |||
| 4c558d3eb6 | |||
| dcd175444a | |||
| 16fc58404a |
@@ -1,5 +1,28 @@
|
||||
# Changelog
|
||||
|
||||
## v0.17.11
|
||||
|
||||
[compare changes](https://github.com/wxt-dev/wxt/compare/v0.17.10...v0.17.11)
|
||||
|
||||
### 🩹 Fixes
|
||||
|
||||
- Resolve absolute paths from the public directory properly ([#583](https://github.com/wxt-dev/wxt/pull/583))
|
||||
|
||||
### 📖 Documentation
|
||||
|
||||
- Fix `zip.includeSources` example ([16fc584](https://github.com/wxt-dev/wxt/commit/16fc584))
|
||||
- Add "GitHub Custom Notifier" to homepage ([#580](https://github.com/wxt-dev/wxt/pull/580))
|
||||
|
||||
### 🏡 Chore
|
||||
|
||||
- Simplify virtual module setup ([#581](https://github.com/wxt-dev/wxt/pull/581))
|
||||
- Add some array utils ([#582](https://github.com/wxt-dev/wxt/pull/582))
|
||||
- Extract helper function ([d3b14af](https://github.com/wxt-dev/wxt/commit/d3b14af))
|
||||
|
||||
### ❤️ Contributors
|
||||
|
||||
- Qiwei Yang ([@qiweiii](http://github.com/qiweiii))
|
||||
|
||||
## v0.17.10
|
||||
|
||||
[compare changes](https://github.com/wxt-dev/wxt/compare/v0.17.9...v0.17.10)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import messages from 'public/_locales/en/messages.json';
|
||||
import messages from '~/public/_locales/en/messages.json';
|
||||
|
||||
export default defineBackground({
|
||||
// type: 'module',
|
||||
|
||||
@@ -12,9 +12,6 @@ export default defineConfig({
|
||||
},
|
||||
],
|
||||
},
|
||||
alias: {
|
||||
public: 'src/public',
|
||||
},
|
||||
zip: {
|
||||
downloadPackages: ['sass'],
|
||||
},
|
||||
|
||||
@@ -21,6 +21,7 @@ const chromeExtensionIds = [
|
||||
'aiakblgmlabokilgljkglggnpflljdgp', // Markdown Sticky Notes
|
||||
'nomnkbngkijpffepcgbbofhcnafpkiep', // DocVersionRedirector
|
||||
'ceicccfeikoipigeghddpocceifjelph', // Plex Skipper
|
||||
'aelkipgppclpfimeamgmlonimflbhlgf', // GitHub Custom Notifier
|
||||
];
|
||||
|
||||
const { data, err, isLoading } = useListExtensionDetails(chromeExtensionIds);
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "wxt",
|
||||
"type": "module",
|
||||
"version": "0.17.10",
|
||||
"version": "0.17.11",
|
||||
"description": "Next gen framework for developing web extensions",
|
||||
"engines": {
|
||||
"node": ">=18",
|
||||
|
||||
+12
-17
@@ -8,6 +8,10 @@ import { consola } from 'consola';
|
||||
import pMap from 'p-map';
|
||||
import os from 'node:os';
|
||||
import path from 'node:path';
|
||||
import {
|
||||
virtualModuleNames,
|
||||
virtualEntrypointModuleNames,
|
||||
} from '~/core/utils/virtual-modules';
|
||||
|
||||
const spinnerText = 'Building WXT';
|
||||
const spinner = ora(spinnerText).start();
|
||||
@@ -20,12 +24,7 @@ const preset = {
|
||||
dts: true,
|
||||
silent: true,
|
||||
sourcemap: false,
|
||||
external: [
|
||||
'virtual:user-unlisted-script',
|
||||
'virtual:user-content-script-isolated-world',
|
||||
'virtual:user-content-script-main-world',
|
||||
'virtual:user-background',
|
||||
],
|
||||
external: virtualEntrypointModuleNames.map((name) => `virtual:user-${name}`),
|
||||
} satisfies tsup.Options;
|
||||
|
||||
function spinnerPMap(configs: tsup.Options[]) {
|
||||
@@ -74,17 +73,13 @@ const config: tsup.Options[] = [
|
||||
},
|
||||
{
|
||||
...preset,
|
||||
entry: {
|
||||
'virtual/background-entrypoint': 'src/virtual/background-entrypoint.ts',
|
||||
'virtual/content-script-isolated-world-entrypoint':
|
||||
'src/virtual/content-script-isolated-world-entrypoint.ts',
|
||||
'virtual/content-script-main-world-entrypoint':
|
||||
'src/virtual/content-script-main-world-entrypoint.ts',
|
||||
'virtual/mock-browser': 'src/virtual/mock-browser.ts',
|
||||
'virtual/reload-html': 'src/virtual/reload-html.ts',
|
||||
'virtual/unlisted-script-entrypoint':
|
||||
'src/virtual/unlisted-script-entrypoint.ts',
|
||||
},
|
||||
entry: virtualModuleNames.reduce<Record<string, string>>(
|
||||
(acc, moduleName) => {
|
||||
acc[`virtual/${moduleName}`] = `src/virtual/${moduleName}.ts`;
|
||||
return acc;
|
||||
},
|
||||
{},
|
||||
),
|
||||
format: ['esm'],
|
||||
splitting: false,
|
||||
dts: false,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { CAC, Command } from 'cac';
|
||||
import consola, { LogLevels } from 'consola';
|
||||
import { filterTruthy, toArray } from '~/core/utils/arrays';
|
||||
import { printHeader } from '~/core/utils/log';
|
||||
import { formatDuration } from '~/core/utils/time';
|
||||
import { ValidationError } from '~/core/utils/validation';
|
||||
@@ -56,8 +57,8 @@ export function getArrayFromFlags<T>(
|
||||
flags: any,
|
||||
name: string,
|
||||
): T[] | undefined {
|
||||
const array = [flags[name]].flat() as Array<T | undefined>;
|
||||
const result = array.filter((item) => item != null) as T[];
|
||||
const array = toArray<T | undefined>(flags[name]);
|
||||
const result = filterTruthy(array);
|
||||
return result.length ? result : undefined;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@ import {
|
||||
BuildStepOutput,
|
||||
Entrypoint,
|
||||
ResolvedConfig,
|
||||
VirtualEntrypointType,
|
||||
WxtBuilder,
|
||||
WxtBuilderServer,
|
||||
WxtDevServer,
|
||||
@@ -13,6 +12,10 @@ import {
|
||||
getEntrypointBundlePath,
|
||||
isHtmlEntrypoint,
|
||||
} from '~/core/utils/entrypoints';
|
||||
import {
|
||||
VirtualEntrypointType,
|
||||
VirtualModuleId,
|
||||
} from '~/core/utils/virtual-modules';
|
||||
|
||||
export async function createViteBuilder(
|
||||
wxtConfig: ResolvedConfig,
|
||||
@@ -32,6 +35,8 @@ export async function createViteBuilder(
|
||||
config.mode = wxtConfig.mode;
|
||||
|
||||
config.build ??= {};
|
||||
config.publicDir = wxtConfig.publicDir;
|
||||
config.build.copyPublicDir = false;
|
||||
config.build.outDir = wxtConfig.outDir;
|
||||
config.build.emptyOutDir = false;
|
||||
// Disable minification for the dev command
|
||||
@@ -48,10 +53,7 @@ export async function createViteBuilder(
|
||||
wxtPlugins.download(wxtConfig),
|
||||
wxtPlugins.devHtmlPrerender(wxtConfig, server),
|
||||
wxtPlugins.unimport(wxtConfig),
|
||||
wxtPlugins.virtualEntrypoint('background', wxtConfig),
|
||||
wxtPlugins.virtualEntrypoint('content-script-isolated-world', wxtConfig),
|
||||
wxtPlugins.virtualEntrypoint('content-script-main-world', wxtConfig),
|
||||
wxtPlugins.virtualEntrypoint('unlisted-script', wxtConfig),
|
||||
wxtPlugins.resolveVirtualModules(wxtConfig),
|
||||
wxtPlugins.devServerGlobals(wxtConfig, server),
|
||||
wxtPlugins.tsconfigPaths(wxtConfig),
|
||||
wxtPlugins.noopBackground(),
|
||||
@@ -268,7 +270,10 @@ function getRollupEntry(entrypoint: Entrypoint): string {
|
||||
: 'content-script-isolated-world';
|
||||
break;
|
||||
}
|
||||
return virtualEntrypointType
|
||||
? `virtual:wxt-${virtualEntrypointType}?${entrypoint.inputPath}`
|
||||
: entrypoint.inputPath;
|
||||
|
||||
if (virtualEntrypointType) {
|
||||
const moduleId: VirtualModuleId = `virtual:wxt-${virtualEntrypointType}-entrypoint`;
|
||||
return `${moduleId}?${entrypoint.inputPath}`;
|
||||
}
|
||||
return entrypoint.inputPath;
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ export * from './devServerGlobals';
|
||||
export * from './download';
|
||||
export * from './multipageMove';
|
||||
export * from './unimport';
|
||||
export * from './virtualEntrypoint';
|
||||
export * from './resolveVirtualModules';
|
||||
export * from './tsconfigPaths';
|
||||
export * from './noopBackground';
|
||||
export * from './cssEntrypoints';
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
import { Plugin } from 'vite';
|
||||
import { ResolvedConfig } from '~/types';
|
||||
import { normalizePath } from '~/core/utils/paths';
|
||||
import {
|
||||
VirtualModuleId,
|
||||
virtualModuleNames,
|
||||
} from '~/core/utils/virtual-modules';
|
||||
import fs from 'fs-extra';
|
||||
import { resolve } from 'path';
|
||||
|
||||
/**
|
||||
* Resolve all the virtual modules to the `node_modules/wxt/dist/virtual` directory.
|
||||
*/
|
||||
export function resolveVirtualModules(config: ResolvedConfig): Plugin[] {
|
||||
return virtualModuleNames.map((name) => {
|
||||
const virtualId: `${VirtualModuleId}?` = `virtual:wxt-${name}?`;
|
||||
const resolvedVirtualId = '\0' + virtualId;
|
||||
return {
|
||||
name: `wxt:resolve-virtual-${name}`,
|
||||
resolveId(id) {
|
||||
// Id doesn't start with prefix, it looks like this:
|
||||
// /path/to/project/virtual:wxt-background?/path/to/project/entrypoints/background.ts
|
||||
const index = id.indexOf(virtualId);
|
||||
if (index === -1) return;
|
||||
|
||||
const inputPath = normalizePath(id.substring(index + virtualId.length));
|
||||
return resolvedVirtualId + inputPath;
|
||||
},
|
||||
async load(id) {
|
||||
if (!id.startsWith(resolvedVirtualId)) return;
|
||||
|
||||
const inputPath = id.replace(resolvedVirtualId, '');
|
||||
const template = await fs.readFile(
|
||||
resolve(config.wxtModuleDir, `dist/virtual/${name}.js`),
|
||||
'utf-8',
|
||||
);
|
||||
return template.replace(`virtual:user-${name}`, inputPath);
|
||||
},
|
||||
};
|
||||
});
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
import { Plugin } from 'vite';
|
||||
import { ResolvedConfig, VirtualEntrypointType } from '~/types';
|
||||
import fs from 'fs-extra';
|
||||
import { resolve } from 'path';
|
||||
import { normalizePath } from '~/core/utils/paths';
|
||||
|
||||
/**
|
||||
* Wraps a user's entrypoint with a vitual version with additional logic.
|
||||
*/
|
||||
export function virtualEntrypoint(
|
||||
type: VirtualEntrypointType,
|
||||
config: Omit<ResolvedConfig, 'builder'>,
|
||||
): Plugin {
|
||||
const virtualId = `virtual:wxt-${type}?`;
|
||||
const resolvedVirtualId = `\0${virtualId}`;
|
||||
|
||||
return {
|
||||
name: `wxt:virtual-entrypoint`,
|
||||
resolveId(id) {
|
||||
// Id doesn't start with prefix, it looks like this:
|
||||
// /path/to/project/virtual:background?/path/to/project/entrypoints/background.ts
|
||||
const index = id.indexOf(virtualId);
|
||||
if (index === -1) return;
|
||||
|
||||
const inputPath = normalizePath(id.substring(index + virtualId.length));
|
||||
return resolvedVirtualId + inputPath;
|
||||
},
|
||||
async load(id) {
|
||||
if (!id.startsWith(resolvedVirtualId)) return;
|
||||
|
||||
const inputPath = id.replace(resolvedVirtualId, '');
|
||||
const template = await fs.readFile(
|
||||
resolve(config.wxtModuleDir, `dist/virtual/${type}-entrypoint.js`),
|
||||
'utf-8',
|
||||
);
|
||||
return template.replace(`virtual:user-${type}`, inputPath);
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -26,7 +26,10 @@ import pc from 'picocolors';
|
||||
import { relative } from 'node:path';
|
||||
import { registerWxt, wxt } from './wxt';
|
||||
import { unnormalizePath } from './utils/paths';
|
||||
import { mapWxtOptionsToRegisteredContentScript } from './utils/content-scripts';
|
||||
import {
|
||||
getContentScriptJs,
|
||||
mapWxtOptionsToRegisteredContentScript,
|
||||
} from './utils/content-scripts';
|
||||
|
||||
/**
|
||||
* Creates a dev server and pre-builds all the files that need to exist before loading the extension.
|
||||
@@ -232,7 +235,7 @@ function reloadContentScripts(steps: BuildStepOutput[], server: WxtDevServer) {
|
||||
const entry = step.entrypoints;
|
||||
if (Array.isArray(entry) || entry.type !== 'content-script') return;
|
||||
|
||||
const js = [getEntrypointBundlePath(entry, wxt.config.outDir, '.js')];
|
||||
const js = getContentScriptJs(wxt.config, entry);
|
||||
const cssMap = getContentScriptsCssMap(server.currentOutput, [entry]);
|
||||
const css = getContentScriptCssFiles([entry], cssMap);
|
||||
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
import { describe, it } from 'vitest';
|
||||
import {
|
||||
VirtualModuleId,
|
||||
VirtualModuleName,
|
||||
VirtualEntrypointType,
|
||||
VirtualEntrypointModuleName,
|
||||
} from '../virtual-modules';
|
||||
|
||||
describe('Virtual Modules', () => {
|
||||
it('should resolve types to litteral values, not string', () => {
|
||||
// @ts-expect-error
|
||||
const _c: VirtualEntrypointType = '';
|
||||
// @ts-expect-error
|
||||
const _d: VirtualEntrypointModuleName = '';
|
||||
// @ts-expect-error
|
||||
const _b: VirtualModuleName = '';
|
||||
// @ts-expect-error
|
||||
const _a: VirtualModuleId = '';
|
||||
});
|
||||
});
|
||||
@@ -21,3 +21,14 @@ export function some<T>(
|
||||
if (predicate(array[i], i)) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert an item or array to an array.
|
||||
*/
|
||||
export function toArray<T>(a: T | T[]): T[] {
|
||||
return Array.isArray(a) ? a : [a];
|
||||
}
|
||||
|
||||
export function filterTruthy<T>(array: Array<T | undefined>): T[] {
|
||||
return array.filter((item) => !!item) as T[];
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import { dirname, resolve } from 'path';
|
||||
import type { Ora } from 'ora';
|
||||
import pc from 'picocolors';
|
||||
import { wxt } from '../../wxt';
|
||||
import { toArray } from '../arrays';
|
||||
|
||||
export async function buildEntrypoints(
|
||||
groups: EntrypointGroup[],
|
||||
@@ -13,7 +14,7 @@ export async function buildEntrypoints(
|
||||
const steps: BuildStepOutput[] = [];
|
||||
for (let i = 0; i < groups.length; i++) {
|
||||
const group = groups[i];
|
||||
const groupNames = [group].flat().map((e) => e.name);
|
||||
const groupNames = toArray(group).map((e) => e.name);
|
||||
const groupNameColored = groupNames.join(pc.dim(', '));
|
||||
spinner.text =
|
||||
pc.dim(`[${i + 1}/${groups.length}]`) + ` ${groupNameColored}`;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import type { Manifest, Scripting } from '~/browser';
|
||||
import { ContentScriptEntrypoint } from '~/types';
|
||||
import { ContentScriptEntrypoint, ResolvedConfig } from '~/types';
|
||||
import { getEntrypointBundlePath } from './entrypoints';
|
||||
|
||||
/**
|
||||
* Returns a unique and consistent string hash based on a content scripts options.
|
||||
@@ -83,3 +84,10 @@ export function mapWxtOptionsToRegisteredContentScript(
|
||||
world: options.world,
|
||||
};
|
||||
}
|
||||
|
||||
export function getContentScriptJs(
|
||||
config: ResolvedConfig,
|
||||
entrypoint: ContentScriptEntrypoint,
|
||||
): string[] {
|
||||
return [getEntrypointBundlePath(entrypoint, config.outDir, '.js')];
|
||||
}
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
export const virtualEntrypointTypes = [
|
||||
'content-script-main-world' as const,
|
||||
'content-script-isolated-world' as const,
|
||||
'background' as const,
|
||||
'unlisted-script' as const,
|
||||
];
|
||||
export type VirtualEntrypointType = (typeof virtualEntrypointTypes)[0];
|
||||
|
||||
/**
|
||||
* All the names of entrypoint files in the `src/virtual/` and `dist/virtual/` directories, minus the extension.
|
||||
*/
|
||||
export const virtualEntrypointModuleNames = virtualEntrypointTypes.map(
|
||||
(name) => `${name}-entrypoint` as const,
|
||||
);
|
||||
/**
|
||||
* Name of entrypoint files in the `src/virtual/` and `dist/virtual/` directories, minus the extension.
|
||||
*/
|
||||
export type VirtualEntrypointModuleName =
|
||||
(typeof virtualEntrypointModuleNames)[0];
|
||||
|
||||
/**
|
||||
* All the names of files in the `src/virtual/` and `dist/virtual/` directories, minus the extension.
|
||||
*/
|
||||
export const virtualModuleNames = [
|
||||
...virtualEntrypointModuleNames,
|
||||
'mock-browser' as const,
|
||||
'reload-html' as const,
|
||||
];
|
||||
/**
|
||||
* Name of files in the `src/virtual/` and `dist/virtual/` directories, minus the extension.
|
||||
*/
|
||||
export type VirtualModuleName = (typeof virtualModuleNames)[0];
|
||||
|
||||
/**
|
||||
* Import alias used for importing a virtual module
|
||||
*/
|
||||
export type VirtualModuleId = `virtual:wxt-${VirtualModuleName}`;
|
||||
+2
-1
@@ -8,6 +8,7 @@
|
||||
import { Storage, browser } from '~/browser';
|
||||
import { dequal } from 'dequal/lite';
|
||||
import { logger } from './sandbox/utils/logger';
|
||||
import { toArray } from './core/utils/arrays';
|
||||
|
||||
export const storage = createStorage();
|
||||
|
||||
@@ -107,7 +108,7 @@ function createStorage(): WxtStorage {
|
||||
await driver.removeItem(metaKey);
|
||||
} else {
|
||||
const newFields = getMetaValue(await driver.getItem(metaKey));
|
||||
[properties].flat().forEach((field) => delete newFields[field]);
|
||||
toArray(properties).forEach((field) => delete newFields[field]);
|
||||
await driver.setItem(metaKey, newFields);
|
||||
}
|
||||
};
|
||||
|
||||
+1
-7
@@ -173,7 +173,7 @@ export interface InlineConfig {
|
||||
*
|
||||
* @example
|
||||
* [
|
||||
* "coverage", // Ignore the coverage directory in the `sourcesRoot`
|
||||
* "coverage", // Include the coverage directory in the `sourcesRoot`
|
||||
* ]
|
||||
*/
|
||||
excludeSources?: string[];
|
||||
@@ -1103,12 +1103,6 @@ export interface ExtensionRunner {
|
||||
closeBrowser(): Promise<void>;
|
||||
}
|
||||
|
||||
export type VirtualEntrypointType =
|
||||
| 'content-script-main-world'
|
||||
| 'content-script-isolated-world'
|
||||
| 'background'
|
||||
| 'unlisted-script';
|
||||
|
||||
export type EslintGlobalsPropValue =
|
||||
| boolean
|
||||
| 'readonly'
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import definition from 'virtual:user-background';
|
||||
import definition from 'virtual:user-background-entrypoint';
|
||||
import { setupWebSocket } from './utils/setup-web-socket';
|
||||
import { logger } from '../sandbox/utils/logger';
|
||||
import { browser } from 'wxt/browser';
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import definition from 'virtual:user-content-script-isolated-world';
|
||||
import definition from 'virtual:user-content-script-isolated-world-entrypoint';
|
||||
import { logger } from '../sandbox/utils/logger';
|
||||
import { ContentScriptContext } from 'wxt/client';
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import definition from 'virtual:user-content-script-main-world';
|
||||
import definition from 'virtual:user-content-script-main-world-entrypoint';
|
||||
import { logger } from '../sandbox/utils/logger';
|
||||
|
||||
(async () => {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import definition from 'virtual:user-unlisted-script';
|
||||
import definition from 'virtual:user-unlisted-script-entrypoint';
|
||||
import { logger } from '../sandbox/utils/logger';
|
||||
|
||||
(async () => {
|
||||
|
||||
+4
-4
@@ -1,11 +1,11 @@
|
||||
// Types required to make the virtual modules happy.
|
||||
|
||||
declare module 'virtual:user-background' {
|
||||
declare module 'virtual:user-background-entrypoint' {
|
||||
const definition: { main: () => void };
|
||||
export default definition;
|
||||
}
|
||||
|
||||
declare module 'virtual:user-content-script-isolated-world' {
|
||||
declare module 'virtual:user-content-script-isolated-world-entrypoint' {
|
||||
const definition: {
|
||||
main: (
|
||||
ctx: import('wxt/client').ContentScriptContext,
|
||||
@@ -14,12 +14,12 @@ declare module 'virtual:user-content-script-isolated-world' {
|
||||
export default definition;
|
||||
}
|
||||
|
||||
declare module 'virtual:user-content-script-main-world' {
|
||||
declare module 'virtual:user-content-script-main-world-entrypoint' {
|
||||
const definition: { main: () => void | Promise<void> };
|
||||
export default definition;
|
||||
}
|
||||
|
||||
declare module 'virtual:user-unlisted-script' {
|
||||
declare module 'virtual:user-unlisted-script-entrypoint' {
|
||||
const definition: { main: () => void | Promise<void> };
|
||||
export default definition;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user