chore: Simplify virtual module setup (#581)

This commit is contained in:
Aaron
2024-03-30 12:44:27 -05:00
committed by GitHub
parent dcd175444a
commit 4c558d3eb6
13 changed files with 130 additions and 79 deletions
+12 -17
View File
@@ -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,
+11 -8
View File
@@ -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,
@@ -48,10 +51,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 +268,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;
}
+1 -1
View File
@@ -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);
},
};
}
@@ -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 = '';
});
});
+37
View File
@@ -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}`;
-6
View File
@@ -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 -1
View File
@@ -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 -1
View File
@@ -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
View File
@@ -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;
}