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
}