diff --git a/demo/tsconfig.json b/demo/tsconfig.json index de6d2ff3..a6fe065e 100644 --- a/demo/tsconfig.json +++ b/demo/tsconfig.json @@ -1,3 +1,3 @@ { - "extends": ["../tsconfig.base.json", "./src/.wxt/tsconfig.json"] + "extends": ["../tsconfig.base.json", "./.wxt/tsconfig.json"] } diff --git a/e2e/tests/typescript-project.test.ts b/e2e/tests/typescript-project.test.ts new file mode 100644 index 00000000..1ffba8df --- /dev/null +++ b/e2e/tests/typescript-project.test.ts @@ -0,0 +1,182 @@ +import { describe, it, expect } from 'vitest'; +import { TestProject } from '../utils'; + +describe('TypeScript Project', () => { + it('should generate defined constants correctly', async () => { + const project = new TestProject(); + + await project.build(); + + const output = await project.serializeFile('.wxt/types/globals.d.ts'); + expect(output).toMatchInlineSnapshot(` + ".wxt/types/globals.d.ts + ---------------------------------------- + // Generated by wxt + export {} + declare global { + const __MANIFEST_VERSION__: 2 | 3; + const __BROWSER__: string; + const __IS_CHROME__: boolean; + const __IS_FIREFOX__: boolean; + const __IS_SAFARI__: boolean; + const __IS_EDGE__: boolean; + const __IS_OPERA__: boolean; + const __COMMAND__: \\"build\\" | \\"serve\\"; + } + " + `); + }); + + 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'); + project.addFile('entrypoints/options.html'); + project.addFile('entrypoints/sandbox.html'); + + await project.build(); + + const output = await project.serializeFile('.wxt/types/paths.d.ts'); + expect(output).toMatchInlineSnapshot(` + ".wxt/types/paths.d.ts + ---------------------------------------- + // Generated by wxt + import \\"wxt/browser\\"; + + declare module \\"wxt/browser\\" { + type PublicPath = + | \\"/options.html\\" + | \\"/popup.html\\" + | \\"/sandbox.html\\" + export interface ProjectRuntime extends Runtime.Static { + getURL(path: PublicPath): string; + } + } + " + `); + }); + + it('should reference all the required types in a single declaration file', async () => { + const project = new TestProject(); + + await project.build(); + + const output = await project.serializeFile('.wxt/wxt.d.ts'); + expect(output).toMatchInlineSnapshot(` + ".wxt/wxt.d.ts + ---------------------------------------- + // Generated by wxt + /// + /// + /// + /// + " + `); + }); + + it('should generate a TSConfig file for the project', async () => { + const project = new TestProject(); + + await project.build(); + + const output = await project.serializeFile('.wxt/tsconfig.json'); + expect(output).toMatchInlineSnapshot(` + ".wxt/tsconfig.json + ---------------------------------------- + { + \\"compilerOptions\\": { + \\"target\\": \\"ESNext\\", + \\"module\\": \\"ESNext\\", + \\"moduleResolution\\": \\"Bundler\\", + \\"noEmit\\": true, + \\"esModuleInterop\\": true, + \\"forceConsistentCasingInFileNames\\": true, + \\"resolveJsonModule\\": true, + \\"strict\\": true, + \\"lib\\": [\\"DOM\\", \\"WebWorker\\"], + \\"skipLibCheck\\": true, + \\"paths\\": { + \\"@@\\": [\\"..\\"], + \\"@@/*\\": [\\"../*\\"], + \\"~~\\": [\\"..\\"], + \\"~~/*\\": [\\"../*\\"], + \\"@\\": [\\"..\\"], + \\"@/*\\": [\\"../*\\"], + \\"~\\": [\\"..\\"], + \\"~/*\\": [\\"../*\\"] + } + }, + \\"include\\": [ + \\"../**/*\\", + \\"./wxt.d.ts\\" + ], + \\"exclude\\": [\\"../.output\\"] + }" + `); + }); + + it('should correct path aliases for a custom srcDir', async () => { + const project = new TestProject(); + project.setConfigFileConfig({ + srcDir: 'src', + }); + + await project.build(); + + const output = await project.serializeFile('.wxt/tsconfig.json'); + expect(output).toMatchInlineSnapshot(` + ".wxt/tsconfig.json + ---------------------------------------- + { + \\"compilerOptions\\": { + \\"target\\": \\"ESNext\\", + \\"module\\": \\"ESNext\\", + \\"moduleResolution\\": \\"Bundler\\", + \\"noEmit\\": true, + \\"esModuleInterop\\": true, + \\"forceConsistentCasingInFileNames\\": true, + \\"resolveJsonModule\\": true, + \\"strict\\": true, + \\"lib\\": [\\"DOM\\", \\"WebWorker\\"], + \\"skipLibCheck\\": true, + \\"paths\\": { + \\"@@\\": [\\"..\\"], + \\"@@/*\\": [\\"../*\\"], + \\"~~\\": [\\"..\\"], + \\"~~/*\\": [\\"../*\\"], + \\"@\\": [\\"../src\\"], + \\"@/*\\": [\\"../src/*\\"], + \\"~\\": [\\"../src\\"], + \\"~/*\\": [\\"../src/*\\"] + } + }, + \\"include\\": [ + \\"../**/*\\", + \\"./wxt.d.ts\\" + ], + \\"exclude\\": [\\"../.output\\"] + }" + `); + }); +}); diff --git a/package.json b/package.json index afb699c9..439ddd8d 100644 --- a/package.json +++ b/package.json @@ -83,7 +83,6 @@ "prompts": "^2.4.2", "unimport": "^3.1.0", "vite": "^4.4.7", - "vite-tsconfig-paths": "^4.2.0", "web-ext-run": "^0.1.0", "webextension-polyfill": "^0.10.0", "zip-dir": "^2.0.0" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b1d2af6a..8a63724e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -68,9 +68,6 @@ importers: vite: specifier: ^4.4.7 version: 4.4.9(@types/node@20.5.0) - vite-tsconfig-paths: - specifier: ^4.2.0 - version: 4.2.0(typescript@5.1.6)(vite@4.4.9) web-ext-run: specifier: ^0.1.0 version: 0.1.0 @@ -2333,10 +2330,6 @@ packages: slash: 3.0.0 dev: true - /globrex@0.1.2: - resolution: {integrity: sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==} - dev: false - /gopd@1.0.1: resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==} dependencies: @@ -4195,19 +4188,6 @@ packages: code-block-writer: 12.0.0 dev: true - /tsconfck@2.1.1(typescript@5.1.6): - resolution: {integrity: sha512-ZPCkJBKASZBmBUNqGHmRhdhM8pJYDdOXp4nRgj/O0JwUwsMq50lCDRQP/M5GBNAA0elPrq4gAeu4dkaVCuKWww==} - engines: {node: ^14.13.1 || ^16 || >=18} - hasBin: true - peerDependencies: - typescript: ^4.3.5 || ^5.0.0 - peerDependenciesMeta: - typescript: - optional: true - dependencies: - typescript: 5.1.6 - dev: false - /tslib@2.6.0: resolution: {integrity: sha512-7At1WUettjcSRHXCyYtTselblcHl9PJFFVKiCAy/bY97+BPZXSQ2wbq0P9s8tK2G7dFQfNnlJnPAiArVBVBsfA==} dev: false @@ -4300,6 +4280,7 @@ packages: resolution: {integrity: sha512-zaWCozRZ6DLEWAWFrVDz1H6FVXzUSfTy5FUMWsQlU8Ym5JP9eO4xkTIROFCQvhQf61z6O/G6ugw3SgAnvvm+HA==} engines: {node: '>=14.17'} hasBin: true + dev: true /ufo@1.1.2: resolution: {integrity: sha512-TrY6DsjTQQgyS3E3dBaOXf0TpPD8u9FVrVYmKVegJuFw51n/YB9XPt+U6ydzFG5ZIN7+DIjPbNmXoBj9esYhgQ==} @@ -4427,23 +4408,6 @@ packages: - terser dev: true - /vite-tsconfig-paths@4.2.0(typescript@5.1.6)(vite@4.4.9): - resolution: {integrity: sha512-jGpus0eUy5qbbMVGiTxCL1iB9ZGN6Bd37VGLJU39kTDD6ZfULTTb1bcc5IeTWqWJKiWV5YihCaibeASPiGi8kw==} - peerDependencies: - vite: '*' - peerDependenciesMeta: - vite: - optional: true - dependencies: - debug: 4.3.4 - globrex: 0.1.2 - tsconfck: 2.1.1(typescript@5.1.6) - vite: 4.4.9(@types/node@20.5.0) - transitivePeerDependencies: - - supports-color - - typescript - dev: false - /vite@4.4.9(@types/node@20.5.0): resolution: {integrity: sha512-2mbUn2LlUmNASWwSCNSJ/EG2HuSRTnVNaydp6vMCm5VIqJsjMfbIWtbH2kDuwUVW5mMUKKZvGPX/rqeqVvv1XA==} engines: {node: ^14.18.0 || >=16.0.0} diff --git a/src/core/build/generateTypesDir.ts b/src/core/build/generateTypesDir.ts index d6c1ebe7..43561408 100644 --- a/src/core/build/generateTypesDir.ts +++ b/src/core/build/generateTypesDir.ts @@ -128,6 +128,8 @@ async function writeTsConfigFile( config: InternalConfig, ) { const dir = config.wxtDir; + const rootPath = normalizePath(relative(dir, config.root)); + const srcPath = normalizePath(relative(dir, config.srcDir)); await fs.writeFile( resolve(dir, 'tsconfig.json'), `{ @@ -142,16 +144,15 @@ async function writeTsConfigFile( "strict": true, "lib": ["DOM", "WebWorker"], "skipLibCheck": true, - "baseUrl": "${normalizePath(relative(dir, config.root))}", "paths": { - "@@": ["."], - "@@/*": ["./*"], - "~~": ["."], - "~~/*": ["./*"], - "@": ["${normalizePath(relative(config.root, config.srcDir))}"], - "@/*": ["${normalizePath(relative(config.root, config.srcDir))}/*"], - "~": ["${normalizePath(relative(config.root, config.srcDir))}"], - "~/*": ["${normalizePath(relative(config.root, config.srcDir))}/*"] + "@@": ["${rootPath}"], + "@@/*": ["${rootPath}/*"], + "~~": ["${rootPath}"], + "~~/*": ["${rootPath}/*"], + "@": ["${srcPath}"], + "@/*": ["${srcPath}/*"], + "~": ["${srcPath}"], + "~/*": ["${srcPath}/*"] } }, "include": [ diff --git a/src/core/utils/getInternalConfig.ts b/src/core/utils/getInternalConfig.ts index 1846b0d2..0358c14c 100644 --- a/src/core/utils/getInternalConfig.ts +++ b/src/core/utils/getInternalConfig.ts @@ -84,7 +84,7 @@ export async function getInternalConfig( userConfig.entrypointsDir ?? 'entrypoints', ); const publicDir = resolve(root, userConfig.publicDir ?? 'public'); - const wxtDir = resolve(srcDir, '.wxt'); + const wxtDir = resolve(root, '.wxt'); const typesDir = resolve(wxtDir, 'types'); // Merge manifest sources diff --git a/src/core/vite-plugins/tsconfigPaths.ts b/src/core/vite-plugins/tsconfigPaths.ts index dd3ea3b9..a595f68b 100644 --- a/src/core/vite-plugins/tsconfigPaths.ts +++ b/src/core/vite-plugins/tsconfigPaths.ts @@ -1,10 +1,20 @@ import { InternalConfig } from '../types'; -import paths from 'vite-tsconfig-paths'; +import * as vite from 'vite'; -export function tsconfigPaths(config: InternalConfig) { - const fn: typeof paths = - typeof paths === 'function' ? paths : (paths as any).default; - return fn({ - root: config.root, - }); +export function tsconfigPaths(config: InternalConfig): vite.Plugin { + return { + name: 'wxt:aliases', + async config() { + return { + resolve: { + alias: { + '@@': config.root, + '~~': config.root, + '@': config.srcDir, + '~': config.srcDir, + }, + }, + }; + }, + }; } diff --git a/templates/svelte/tsconfig.json b/templates/svelte/tsconfig.json index 9ecb7858..32296447 100644 --- a/templates/svelte/tsconfig.json +++ b/templates/svelte/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "./src/.wxt/tsconfig.json", + "extends": "./.wxt/tsconfig.json", "compilerOptions": { "useDefineForClassFields": true }