diff --git a/docs/.vitepress/plugins/generate-config-docs.ts b/docs/.vitepress/plugins/generate-config-docs.ts index 825ab65b..aff71ad6 100644 --- a/docs/.vitepress/plugins/generate-config-docs.ts +++ b/docs/.vitepress/plugins/generate-config-docs.ts @@ -23,11 +23,16 @@ const LEAF_PATHS = ['imports', 'vite', 'server']; /** * Override any types that resolve to `import(...)` instead of their type names when calling - * `type.getText()` + * `type.getText()`. + * + * This also stops any further type inspection for objects, meaning the object will be documented, + * not it's properties. */ const CUSTOM_TYPES = { manifest: 'Manifest | Promise | () => Manifest | () => Promise', + imports: "false | Partial", + vite: "Omit", }; export function generateConfigDocs() { @@ -61,18 +66,12 @@ export function generateConfigDocs() { throw Error('Unsupported type node: ' + node.getKindName()); } - if (type.isObject() && !type.isArray()) { - return ( - type - .getProperties() - // .sort((l, r) => l.getName().localeCompare(r.getName())) - .flatMap((property) => { - const childPath = [...path, property.getName()]; - if (LEAF_PATHS.includes(childPath.join('.'))) return []; + if (type.isObject() && !type.isArray() && !CUSTOM_TYPES[pathStr]) { + return type.getProperties().flatMap((property) => { + const childPath = [...path, property.getName()]; - return getDocsFor(childPath, property.getDeclarations()[0]); - }) - ); + return getDocsFor(childPath, property.getDeclarations()[0]); + }); } if ('getJsDocs' in node) { diff --git a/e2e/tests/auto-imports.test.ts b/e2e/tests/auto-imports.test.ts index f689acd1..25283ca1 100644 --- a/e2e/tests/auto-imports.test.ts +++ b/e2e/tests/auto-imports.test.ts @@ -2,60 +2,87 @@ import { describe, it, expect } from 'vitest'; import { TestProject } from '../utils'; describe('Auto Imports', () => { - it('should output types for entrypoint paths', async () => { - const project = new TestProject(); - project.addFile( - 'entrypoints/background.ts', - 'export default defineBackground(() => {})', - ); - project.addFile( - 'entrypoints/overlay.content.ts', - 'export default defineContentScript(() => {})', - ); - project.addFile('entrypoints/popup.html', ''); + describe('imports: { ... }', () => { + it('should generate a declaration file, imports.d.ts, for auto-imports', async () => { + const project = new TestProject(); + project.addFile('entrypoints/popup.html', ``); - await project.build(); + await project.build(); - expect(await project.serializeFile('.wxt/types/paths.d.ts')) - .toMatchInlineSnapshot(` - ".wxt/types/paths.d.ts + expect(await project.serializeFile('.wxt/types/imports.d.ts')) + .toMatchInlineSnapshot(` + ".wxt/types/imports.d.ts + ---------------------------------------- + // Generated by wxt + export {} + declare global { + const browser: typeof import('wxt/browser')['browser'] + const defineBackground: typeof import('wxt/client')['defineBackground'] + const defineConfig: typeof import('wxt')['defineConfig'] + const defineContentScript: typeof import('wxt/client')['defineContentScript'] + const mountContentScriptUi: typeof import('wxt/client')['mountContentScriptUi'] + } + " + `); + }); + + it('should include auto-imports in the project', async () => { + const project = new TestProject(); + project.addFile('entrypoints/popup.html', ``); + + await project.build(); + + expect(await project.serializeFile('.wxt/wxt.d.ts')) + .toMatchInlineSnapshot(` + ".wxt/wxt.d.ts ---------------------------------------- // Generated by wxt - import \\"wxt/browser\\"; - - declare module \\"wxt/browser\\" { - type PublicPath = - | \\"/background.js\\" - | \\"/content-scripts/overlay.js\\" - | \\"/popup.html\\" - export interface WxtRuntime extends Runtime.Static { - getURL(path: PublicPath): string; - } - } + /// + /// + /// + /// + /// " `); + }); }); - it('should make some client utils auto-importable', async () => { - const project = new TestProject(); - project.addFile('entrypoints/popup.html', ``); + describe('imports: false', () => { + it('should not generate a imports.d.ts file', async () => { + const project = new TestProject(); + project.setConfigFileConfig({ + imports: false, + }); + project.addFile('entrypoints/popup.html', ``); - await project.build(); + await project.build(); - expect(await project.serializeFile('.wxt/types/imports.d.ts')) - .toMatchInlineSnapshot(` - ".wxt/types/imports.d.ts + expect(await project.fileExists('.wxt/types/imports.d.ts')).toBe(false); + }); + + it('should not include imports.d.ts in the type references', async () => { + const project = new TestProject(); + project.setConfigFileConfig({ + imports: false, + }); + project.addFile('entrypoints/popup.html', ``); + + await project.build(); + + expect( + await project.serializeFile('.wxt/wxt.d.ts'), + ).toMatchInlineSnapshot( + ` + ".wxt/wxt.d.ts ---------------------------------------- // Generated by wxt - export {} - declare global { - const browser: typeof import('wxt/browser')['browser'] - const defineBackground: typeof import('wxt/client')['defineBackground'] - const defineConfig: typeof import('wxt')['defineConfig'] - const defineContentScript: typeof import('wxt/client')['defineContentScript'] - const mountContentScriptUi: typeof import('wxt/client')['mountContentScriptUi'] - } + /// + /// + /// + /// " - `); + `, + ); + }); }); }); diff --git a/e2e/tests/typescript-project.test.ts b/e2e/tests/typescript-project.test.ts index f6844729..7bad6702 100644 --- a/e2e/tests/typescript-project.test.ts +++ b/e2e/tests/typescript-project.test.ts @@ -27,28 +27,6 @@ describe('TypeScript Project', () => { `); }); - it('should define auto-import globals', async () => { - const project = new TestProject(); - - await project.build(); - - const output = await project.serializeFile('.wxt/types/imports.d.ts'); - expect(output).toMatchInlineSnapshot(` - ".wxt/types/imports.d.ts - ---------------------------------------- - // Generated by wxt - export {} - declare global { - const browser: typeof import('wxt/browser')['browser'] - const defineBackground: typeof import('wxt/client')['defineBackground'] - const defineConfig: typeof import('wxt')['defineConfig'] - const defineContentScript: typeof import('wxt/client')['defineContentScript'] - const mountContentScriptUi: typeof import('wxt/client')['mountContentScriptUi'] - } - " - `); - }); - it('should augment the types for browser.runtime.getURL', async () => { const project = new TestProject(); project.addFile('entrypoints/popup.html'); @@ -295,7 +273,7 @@ describe('TypeScript Project', () => { `); }); - it('should correct path aliases for a custom srcDir', async () => { + it('should generate correct path aliases for a custom srcDir', async () => { const project = new TestProject(); project.setConfigFileConfig({ srcDir: 'src', diff --git a/src/core/build/generateTypesDir.ts b/src/core/build/generateTypesDir.ts index 7302b251..1cddca87 100644 --- a/src/core/build/generateTypesDir.ts +++ b/src/core/build/generateTypesDir.ts @@ -1,4 +1,4 @@ -import { createUnimport } from 'unimport'; +import { UnimportOptions, createUnimport } from 'unimport'; import { Entrypoint, InternalConfig } from '../types'; import fs from 'fs-extra'; import { relative, resolve } from 'path'; @@ -21,7 +21,12 @@ export async function generateTypesDir( await fs.ensureDir(config.typesDir); const references: string[] = []; - references.push(await writeImportsDeclarationFile(config)); + + const imports = getUnimportOptions(config); + if (imports !== false) { + references.push(await writeImportsDeclarationFile(config, imports)); + } + references.push(await writePathsDeclarationFile(entrypoints, config)); references.push(await writeI18nDeclarationFile(config)); references.push(await writeGlobalsDeclarationFile(config)); @@ -32,9 +37,10 @@ export async function generateTypesDir( async function writeImportsDeclarationFile( config: InternalConfig, + unimportOptions: Partial, ): Promise { const filePath = resolve(config.typesDir, 'imports.d.ts'); - const unimport = createUnimport(getUnimportOptions(config)); + const unimport = createUnimport(unimportOptions); // Load project imports into unimport memory so they are output via generateTypeDeclarations await unimport.scanImportsFromDir(undefined, { cwd: config.srcDir }); diff --git a/src/core/types/external.ts b/src/core/types/external.ts index 7468b146..b7306180 100644 --- a/src/core/types/external.ts +++ b/src/core/types/external.ts @@ -32,7 +32,7 @@ export interface InlineConfig { /** * > Only available when using the JS API. Not available in `wxt.config.ts` files * - * Path to `"wxt.config.ts"` file or false to disable config file discovery. + * Path to `wxt.config.ts` file or `false` to disable config file discovery. * * @default "wxt.config.ts" */ @@ -57,9 +57,19 @@ export interface InlineConfig { */ mode?: string; /** - * Customize auto-import options. + * Customize auto-import options. Set to `false` to disable auto-imports. + * + * For example, to add a directory to auto-import from, you can use: + * + * ```ts + * export default defineConfig({ + * imports: { + * dirs: ["some-directory"] + * } + * }) + * ``` */ - imports?: Partial; + imports?: Partial | false; /** * Explicitly set a browser to build for. This will override the default browser for each command, * and can be overridden by the command line `--browser` option. @@ -81,7 +91,9 @@ export interface InlineConfig { */ logger?: Logger; /** - * Custom Vite options. + * Custom Vite options, see . + * + * [`root`](#root), [`configFile`](#configfile), and [`mode`](#mode) should be set in WXT's config. */ vite?: Omit; /** @@ -89,10 +101,6 @@ export interface InlineConfig { * object or promise. */ manifest?: UserManifest | Promise | UserManifestFn; - /** - * Custom server options. - */ - server?: WxtDevServer; /** * Custom runner options. Options set here can be overridden in a `web-ext.config.ts` file. */ diff --git a/src/core/types/internal.ts b/src/core/types/internal.ts index 129cd5af..297b941a 100644 --- a/src/core/types/internal.ts +++ b/src/core/types/internal.ts @@ -31,7 +31,7 @@ export interface InternalConfig { browser: TargetBrowser; manifestVersion: TargetManifestVersion; logger: Logger; - imports: Partial; + imports: false | Partial; vite: vite.InlineConfig; manifest: UserManifest; fsCache: FsCache; diff --git a/src/core/utils/auto-imports.ts b/src/core/utils/auto-imports.ts index 7617f97e..b521df58 100644 --- a/src/core/utils/auto-imports.ts +++ b/src/core/utils/auto-imports.ts @@ -4,7 +4,9 @@ import { mergeConfig } from 'vite'; export function getUnimportOptions( config: InternalConfig, -): Partial { +): Partial { + if (config.imports === false) return false; + const defaultOptions: Partial = { debugLog: config.logger.debug, imports: [{ name: 'defineConfig', from: 'wxt' }], diff --git a/src/core/vite-plugins/unimport.ts b/src/core/vite-plugins/unimport.ts index 9b8c2818..00736294 100644 --- a/src/core/vite-plugins/unimport.ts +++ b/src/core/vite-plugins/unimport.ts @@ -1,7 +1,7 @@ import { createUnimport } from 'unimport'; import { InternalConfig } from '../types'; import { getUnimportOptions } from '../utils/auto-imports'; -import { Plugin } from 'vite'; +import * as vite from 'vite'; import { extname } from 'path'; const ENABLED_EXTENSIONS: Record = { @@ -16,8 +16,10 @@ const ENABLED_EXTENSIONS: Record = { /** * Inject any global imports defined by unimport */ -export function unimport(config: InternalConfig): Plugin { +export function unimport(config: InternalConfig): vite.PluginOption { const options = getUnimportOptions(config); + if (options === false) return []; + const unimport = createUnimport(options); return {