@typed/vite-plugin 1.0.0-beta.1 → 1.0.0-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -89,6 +89,7 @@ export default defineConfig({
89
89
  | `routerVmOptions` | `RouterVirtualModulePluginOptions` | `{}` | Options for the router VM plugin. |
90
90
  | `apiVmOptions` | `HttpApiVirtualModulePluginOptions` | — | When set, enables the HttpApi VM plugin. |
91
91
  | `createTypeInfoApiSession` | `CreateTypeInfoApiSession` | — | Required for router VM type-checking in dev. |
92
+ | `tsconfig` | `string` | — | Path to `tsconfig.json` (relative to cwd or absolute). When set, both the Language Service session and vite-tsconfig-paths use this tsconfig. Default: auto-discovered from project root. |
92
93
  | `tsconfigPaths` | `boolean \| object` | `true` | Enable tsconfig path resolution. |
93
94
  | `analyze` | `boolean \| object` | `process.env.ANALYZE === '1'` | Enable bundle analyzer (dist/stats.html). |
94
95
  | `warnOnError` | `boolean` | `true` | Log virtual module resolution errors. |
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Debug plugin for tracing build failures. Enabled when DEBUG_TYPED_BUILD=1.
3
+ * Logs config resolution and module resolution to diagnose realworld/counter build issues.
4
+ */
5
+ import type { Plugin } from "vite";
6
+ export declare function createDebugBuildPlugin(): Plugin;
7
+ //# sourceMappingURL=debugBuildPlugin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"debugBuildPlugin.d.ts","sourceRoot":"","sources":["../src/debugBuildPlugin.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAsBnC,wBAAgB,sBAAsB,IAAI,MAAM,CAmC/C"}
@@ -0,0 +1,54 @@
1
+ const LOG_URL = "http://127.0.0.1:7563/ingest/ae4c829f-512d-4a3a-9ef6-9b34461b49d9";
2
+ const SESSION = "d02fd1";
3
+ function log(msg, data, hypothesisId) {
4
+ // #region agent log
5
+ fetch(LOG_URL, {
6
+ method: "POST",
7
+ headers: { "Content-Type": "application/json", "X-Debug-Session-Id": SESSION },
8
+ body: JSON.stringify({
9
+ sessionId: SESSION,
10
+ location: "debugBuildPlugin.ts",
11
+ message: msg,
12
+ data,
13
+ timestamp: Date.now(),
14
+ hypothesisId,
15
+ }),
16
+ }).catch(() => { });
17
+ // #endregion
18
+ }
19
+ export function createDebugBuildPlugin() {
20
+ return {
21
+ name: "typed:debug-build",
22
+ enforce: "pre",
23
+ config(config) {
24
+ // #region agent log
25
+ log("config() received", { hasBuild: !!config.build, hasRoot: !!config.root, base: config.base }, "H-counter-1");
26
+ // #endregion
27
+ return null;
28
+ },
29
+ configResolved(viteConfig) {
30
+ // #region agent log
31
+ log("configResolved", {
32
+ root: viteConfig.root,
33
+ base: viteConfig.base,
34
+ outDir: viteConfig.build?.outDir,
35
+ rollupInput: viteConfig.build?.rollupOptions?.input,
36
+ assetsDir: viteConfig.build?.assetsDir,
37
+ }, "H-counter-2");
38
+ // #endregion
39
+ },
40
+ resolveId(id, importer) {
41
+ if (id.includes("virtual-modules") || id.includes("@typed/virtual-modules")) {
42
+ // #region agent log
43
+ log("resolveId: virtual-modules requested", { id, importer: importer?.slice(-120) }, "H-realworld-1");
44
+ // #endregion
45
+ }
46
+ if (importer && importer.includes("node_modules/@typed/app") && !id.startsWith(".") && !id.startsWith("/")) {
47
+ // #region agent log
48
+ log("resolveId: from @typed/app", { id: id.slice(0, 80), importer: importer.slice(-100) }, "H-realworld-2");
49
+ // #endregion
50
+ }
51
+ return null;
52
+ },
53
+ };
54
+ }
package/dist/index.d.ts CHANGED
@@ -1,17 +1,6 @@
1
- /**
2
- * @typed/vite-plugin — One-stop Vite preset: tsconfig paths, bundle analyzer,
3
- * Brotli compression, virtual-modules Vite plugin, and @typed/app VM plugins.
4
- */
5
- import type { Plugin } from "vite";
1
+ import { HttpApiVirtualModulePluginOptions, RouterVirtualModulePluginOptions } from "@typed/app";
6
2
  import type { CreateTypeInfoApiSession, VirtualModuleResolver } from "@typed/virtual-modules";
7
- /**
8
- * Options passed through to the HttpApi virtual-module plugin when enabled.
9
- * Forwarded to createHttpApiVirtualModulePlugin from the package that provides it
10
- * (e.g. @typed/app when the export is added). See httpapi-virtual-module-plugin spec.
11
- */
12
- export interface HttpApiVirtualModulePluginOptions {
13
- readonly [key: string]: unknown;
14
- }
3
+ import type { Plugin } from "vite";
15
4
  /** Options for vite-plugin-compression when compression is enabled. */
16
5
  export type TypedViteCompressionOptions = boolean | {
17
6
  readonly algorithm?: "gzip" | "brotliCompress" | "deflate" | "deflateRaw";
@@ -23,7 +12,7 @@ export interface TypedVitePluginOptions {
23
12
  /**
24
13
  * Options for the router VM plugin from @typed/app.
25
14
  */
26
- readonly routerVmOptions?: import("@typed/app").RouterVirtualModulePluginOptions;
15
+ readonly routerVmOptions?: RouterVirtualModulePluginOptions;
27
16
  /**
28
17
  * Options for the HttpApi VM plugin from @typed/app. HttpApi VM plugin is always
29
18
  * registered (router first, then HttpApi). Use this to customize its behavior.
@@ -35,6 +24,12 @@ export interface TypedVitePluginOptions {
35
24
  * Override for custom session setup.
36
25
  */
37
26
  readonly createTypeInfoApiSession?: CreateTypeInfoApiSession;
27
+ /**
28
+ * Path to tsconfig.json (relative to cwd or absolute). When set, both the
29
+ * Language Service session and vite-tsconfig-paths use this tsconfig.
30
+ * Default: auto-discovered from project root.
31
+ */
32
+ readonly tsconfig?: string;
38
33
  /**
39
34
  * Enable tsconfig path resolution. Default true.
40
35
  */
@@ -70,9 +65,8 @@ export declare function createTypedViteResolver(options?: TypedVitePluginOptions
70
65
  * Returns Vite plugins: tsconfig paths, virtual modules (@typed/app), and optional bundle analyzer.
71
66
  * Use as: `defineConfig({ plugins: typedVitePlugin() })`.
72
67
  *
73
- * When createTypeInfoApiSession is not provided, the plugin automatically creates a
74
- * Language Service-backed session from the project's tsconfig. The type program evolves
75
- * as files change during dev. Pass createTypeInfoApiSession to override.
68
+ * When called with no arguments, auto-discovers `typed.config.ts` in the project root.
69
+ * When called with explicit options, those take full precedence (config file is not loaded).
76
70
  */
77
71
  export declare function typedVitePlugin(options?: TypedVitePluginOptions): Plugin[];
78
72
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AACnC,OAAO,KAAK,EAAE,wBAAwB,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AAgB9F;;;;GAIG;AACH,MAAM,WAAW,iCAAiC;IAChD,QAAQ,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACjC;AAED,uEAAuE;AACvE,MAAM,MAAM,2BAA2B,GACnC,OAAO,GACP;IACE,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,gBAAgB,GAAG,SAAS,GAAG,YAAY,CAAC;IAC1E,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACjC,CAAC;AAEN,MAAM,WAAW,sBAAsB;IACrC;;OAEG;IACH,QAAQ,CAAC,eAAe,CAAC,EAAE,OAAO,YAAY,EAAE,gCAAgC,CAAC;IAEjF;;;OAGG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,iCAAiC,CAAC;IAE1D;;;;OAIG;IACH,QAAQ,CAAC,wBAAwB,CAAC,EAAE,wBAAwB,CAAC;IAE7D;;OAEG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAE3D;;OAEG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,GAAG;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,OAAO,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAEtF;;OAEG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,OAAO,CAAC;IAE/B;;;OAGG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,2BAA2B,CAAC;CACpD;AAED,kFAAkF;AAClF,MAAM,WAAW,6BAA6B;IAC5C,gCAAgC,CAAC,EAAE,CACjC,IAAI,EAAE,iCAAiC,KACpC,OAAO,wBAAwB,EAAE,mBAAmB,CAAC;CAC3D;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,CACrC,OAAO,GAAE,sBAA2B,EACpC,YAAY,CAAC,EAAE,6BAA6B,GAC3C,qBAAqB,CASvB;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,OAAO,GAAE,sBAA2B,GAAG,MAAM,EAAE,CAuE9E"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAKA,OAAO,EAGL,iCAAiC,EAEjC,gCAAgC,EACjC,MAAM,YAAY,CAAC;AACpB,OAAO,KAAK,EAAE,wBAAwB,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AAW9F,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAInC,uEAAuE;AACvE,MAAM,MAAM,2BAA2B,GACnC,OAAO,GACP;IACE,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,gBAAgB,GAAG,SAAS,GAAG,YAAY,CAAC;IAC1E,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACjC,CAAC;AAEN,MAAM,WAAW,sBAAsB;IACrC;;OAEG;IACH,QAAQ,CAAC,eAAe,CAAC,EAAE,gCAAgC,CAAC;IAE5D;;;OAGG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,iCAAiC,CAAC;IAE1D;;;;OAIG;IACH,QAAQ,CAAC,wBAAwB,CAAC,EAAE,wBAAwB,CAAC;IAE7D;;;;OAIG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAE3B;;OAEG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAE3D;;OAEG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,GAAG;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,OAAO,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAEtF;;OAEG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,OAAO,CAAC;IAE/B;;;OAGG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,2BAA2B,CAAC;CACpD;AAED,kFAAkF;AAClF,MAAM,WAAW,6BAA6B;IAC5C,gCAAgC,CAAC,EAAE,CACjC,IAAI,EAAE,iCAAiC,KACpC,OAAO,wBAAwB,EAAE,mBAAmB,CAAC;CAC3D;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,CACrC,OAAO,GAAE,sBAA2B,EACpC,YAAY,CAAC,EAAE,6BAA6B,GAC3C,qBAAqB,CAQvB;AAgBD;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,OAAO,CAAC,EAAE,sBAAsB,GAAG,MAAM,EAAE,CAgG1E"}
package/dist/index.js CHANGED
@@ -1,43 +1,70 @@
1
+ import { createHttpApiVirtualModulePlugin, createRouterVirtualModulePlugin, loadTypedConfig, } from "@typed/app";
1
2
  import { collectTypeTargetSpecsFromPlugins, createLanguageServiceSessionFactory, PluginManager, } from "@typed/virtual-modules";
2
- import { createHttpApiVirtualModulePlugin, createRouterVirtualModulePlugin, } from "@typed/app";
3
3
  import { virtualModulesVitePlugin } from "@typed/virtual-modules-vite";
4
- import ts from "typescript";
5
- import tsconfigPaths from "vite-tsconfig-paths";
4
+ import { dirname, relative, resolve } from "node:path";
5
+ import process from "node:process";
6
6
  import { visualizer } from "rollup-plugin-visualizer";
7
+ import ts from "typescript";
7
8
  import viteCompression from "vite-plugin-compression";
9
+ import tsconfigPaths from "vite-tsconfig-paths";
8
10
  /**
9
11
  * Invariant: ALL @typed/app VM plugins are always registered. There are no optional
10
12
  * or conditional app plugins. When adding a new VM plugin to @typed/app, add it here.
11
13
  */
12
14
  export function createTypedViteResolver(options = {}, dependencies) {
13
- const httpApiFactory = dependencies?.createHttpApiVirtualModulePlugin ??
14
- createHttpApiVirtualModulePlugin;
15
+ const httpApiFactory = dependencies?.createHttpApiVirtualModulePlugin ?? createHttpApiVirtualModulePlugin;
15
16
  const plugins = [
16
17
  createRouterVirtualModulePlugin(options.routerVmOptions ?? {}),
17
18
  httpApiFactory(options.apiVmOptions ?? {}),
18
19
  ];
19
20
  return new PluginManager(plugins);
20
21
  }
22
+ function optionsFromTypedConfig(config) {
23
+ return {
24
+ routerVmOptions: config.router ? { prefix: config.router.prefix } : undefined,
25
+ apiVmOptions: config.api
26
+ ? { prefix: config.api.prefix, pathPrefix: config.api.pathPrefix }
27
+ : undefined,
28
+ tsconfig: config.tsconfig,
29
+ tsconfigPaths: config.tsconfigPaths,
30
+ analyze: config.analyze,
31
+ warnOnError: config.warnOnError,
32
+ compression: config.compression,
33
+ };
34
+ }
21
35
  /**
22
36
  * Returns Vite plugins: tsconfig paths, virtual modules (@typed/app), and optional bundle analyzer.
23
37
  * Use as: `defineConfig({ plugins: typedVitePlugin() })`.
24
38
  *
25
- * When createTypeInfoApiSession is not provided, the plugin automatically creates a
26
- * Language Service-backed session from the project's tsconfig. The type program evolves
27
- * as files change during dev. Pass createTypeInfoApiSession to override.
39
+ * When called with no arguments, auto-discovers `typed.config.ts` in the project root.
40
+ * When called with explicit options, those take full precedence (config file is not loaded).
28
41
  */
29
- export function typedVitePlugin(options = {}) {
30
- const resolver = createTypedViteResolver(options);
31
- const analyze = options.analyze ?? (process.env.ANALYZE === "1" ? true : false);
32
- let createTypeInfoApiSession = options.createTypeInfoApiSession;
42
+ export function typedVitePlugin(options) {
43
+ const resolvedOptions = (() => {
44
+ if (options)
45
+ return options;
46
+ const result = loadTypedConfig({ projectRoot: process.cwd(), ts });
47
+ if (result.status === "loaded")
48
+ return optionsFromTypedConfig(result.config);
49
+ return {};
50
+ })();
51
+ const resolver = createTypedViteResolver(resolvedOptions);
52
+ const analyze = resolvedOptions.analyze ?? (process.env.ANALYZE === "1" ? true : false);
53
+ let createTypeInfoApiSession = resolvedOptions.createTypeInfoApiSession;
33
54
  if (createTypeInfoApiSession === undefined) {
34
55
  try {
35
56
  const manager = resolver;
36
57
  const typeTargetSpecs = collectTypeTargetSpecsFromPlugins(manager.plugins);
58
+ const cwd = process.cwd();
59
+ const tsconfigPath = resolvedOptions.tsconfig
60
+ ? resolve(cwd, resolvedOptions.tsconfig)
61
+ : undefined;
62
+ const projectRoot = tsconfigPath ? dirname(tsconfigPath) : cwd;
37
63
  createTypeInfoApiSession = createLanguageServiceSessionFactory({
38
64
  ts,
39
- projectRoot: process.cwd(),
65
+ projectRoot,
40
66
  typeTargetSpecs,
67
+ tsconfigPath,
41
68
  });
42
69
  }
43
70
  catch {
@@ -45,14 +72,25 @@ export function typedVitePlugin(options = {}) {
45
72
  }
46
73
  }
47
74
  const plugins = [];
48
- if (options.tsconfigPaths !== false) {
49
- const pathsOpts = typeof options.tsconfigPaths === "object" ? options.tsconfigPaths : {};
75
+ if (resolvedOptions.tsconfigPaths !== false) {
76
+ const basePathsOpts = typeof resolvedOptions.tsconfigPaths === "object" ? resolvedOptions.tsconfigPaths : {};
77
+ const cwd = process.cwd();
78
+ const resolvedTsconfig = resolvedOptions.tsconfig
79
+ ? resolve(cwd, resolvedOptions.tsconfig)
80
+ : undefined;
81
+ const pathsOpts = resolvedTsconfig !== undefined
82
+ ? {
83
+ ...basePathsOpts,
84
+ root: cwd,
85
+ projects: [relative(cwd, resolvedTsconfig)],
86
+ }
87
+ : basePathsOpts;
50
88
  plugins.push(tsconfigPaths(pathsOpts));
51
89
  }
52
90
  plugins.push(virtualModulesVitePlugin({
53
91
  resolver,
54
92
  createTypeInfoApiSession,
55
- warnOnError: options.warnOnError ?? true,
93
+ warnOnError: resolvedOptions.warnOnError ?? true,
56
94
  }));
57
95
  if (analyze) {
58
96
  const vizOpts = typeof analyze === "object"
@@ -64,7 +102,7 @@ export function typedVitePlugin(options = {}) {
64
102
  template: vizOpts.template ?? "treemap",
65
103
  }));
66
104
  }
67
- const compression = options.compression ?? true;
105
+ const compression = resolvedOptions.compression ?? true;
68
106
  if (compression !== false) {
69
107
  const compressionOpts = typeof compression === "object"
70
108
  ? {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@typed/vite-plugin",
3
- "version": "1.0.0-beta.1",
3
+ "version": "1.0.0-beta.2",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": {
@@ -11,23 +11,19 @@
11
11
  "publishConfig": {
12
12
  "access": "public"
13
13
  },
14
- "scripts": {
15
- "build": "[ -d dist ] || rm -f tsconfig.tsbuildinfo; tsc",
16
- "test": "vitest run --passWithNoTests"
17
- },
18
14
  "dependencies": {
19
- "@typed/app": "workspace:*",
20
- "@typed/virtual-modules": "workspace:*",
21
- "@typed/virtual-modules-vite": "workspace:*",
22
15
  "rollup-plugin-visualizer": "^5.12.0",
23
16
  "vite-plugin-compression": "^0.5.1",
24
- "vite-tsconfig-paths": "^6.1.0"
17
+ "vite-tsconfig-paths": "^6.1.0",
18
+ "@typed/app": "1.0.0-beta.2",
19
+ "@typed/virtual-modules-vite": "1.0.0-beta.2",
20
+ "@typed/virtual-modules": "1.0.0-beta.2"
25
21
  },
26
22
  "devDependencies": {
27
23
  "@types/node": "^25.3.0",
28
- "typescript": "catalog:",
24
+ "typescript": "5.9.3",
29
25
  "vite": "^7.3.1",
30
- "vitest": "catalog:"
26
+ "vitest": "4.0.18"
31
27
  },
32
28
  "peerDependencies": {
33
29
  "typescript": ">=5.0.0",
@@ -36,5 +32,9 @@
36
32
  "files": [
37
33
  "dist",
38
34
  "src"
39
- ]
40
- }
35
+ ],
36
+ "scripts": {
37
+ "build": "[ -d dist ] || rm -f tsconfig.tsbuildinfo; tsc",
38
+ "test": "vitest run --passWithNoTests"
39
+ }
40
+ }
package/src/index.ts CHANGED
@@ -2,31 +2,28 @@
2
2
  * @typed/vite-plugin — One-stop Vite preset: tsconfig paths, bundle analyzer,
3
3
  * Brotli compression, virtual-modules Vite plugin, and @typed/app VM plugins.
4
4
  */
5
- import type { Plugin } from "vite";
5
+ import type { TypedConfig } from "@typed/app";
6
+ import {
7
+ createHttpApiVirtualModulePlugin,
8
+ createRouterVirtualModulePlugin,
9
+ HttpApiVirtualModulePluginOptions,
10
+ loadTypedConfig,
11
+ RouterVirtualModulePluginOptions,
12
+ } from "@typed/app";
6
13
  import type { CreateTypeInfoApiSession, VirtualModuleResolver } from "@typed/virtual-modules";
7
14
  import {
8
15
  collectTypeTargetSpecsFromPlugins,
9
16
  createLanguageServiceSessionFactory,
10
17
  PluginManager,
11
18
  } from "@typed/virtual-modules";
12
- import {
13
- createHttpApiVirtualModulePlugin,
14
- createRouterVirtualModulePlugin,
15
- } from "@typed/app";
16
19
  import { virtualModulesVitePlugin } from "@typed/virtual-modules-vite";
17
- import ts from "typescript";
18
- import tsconfigPaths from "vite-tsconfig-paths";
20
+ import { dirname, relative, resolve } from "node:path";
21
+ import process from "node:process";
19
22
  import { visualizer } from "rollup-plugin-visualizer";
23
+ import ts from "typescript";
24
+ import type { Plugin } from "vite";
20
25
  import viteCompression from "vite-plugin-compression";
21
-
22
- /**
23
- * Options passed through to the HttpApi virtual-module plugin when enabled.
24
- * Forwarded to createHttpApiVirtualModulePlugin from the package that provides it
25
- * (e.g. @typed/app when the export is added). See httpapi-virtual-module-plugin spec.
26
- */
27
- export interface HttpApiVirtualModulePluginOptions {
28
- readonly [key: string]: unknown;
29
- }
26
+ import tsconfigPaths from "vite-tsconfig-paths";
30
27
 
31
28
  /** Options for vite-plugin-compression when compression is enabled. */
32
29
  export type TypedViteCompressionOptions =
@@ -42,7 +39,7 @@ export interface TypedVitePluginOptions {
42
39
  /**
43
40
  * Options for the router VM plugin from @typed/app.
44
41
  */
45
- readonly routerVmOptions?: import("@typed/app").RouterVirtualModulePluginOptions;
42
+ readonly routerVmOptions?: RouterVirtualModulePluginOptions;
46
43
 
47
44
  /**
48
45
  * Options for the HttpApi VM plugin from @typed/app. HttpApi VM plugin is always
@@ -57,6 +54,13 @@ export interface TypedVitePluginOptions {
57
54
  */
58
55
  readonly createTypeInfoApiSession?: CreateTypeInfoApiSession;
59
56
 
57
+ /**
58
+ * Path to tsconfig.json (relative to cwd or absolute). When set, both the
59
+ * Language Service session and vite-tsconfig-paths use this tsconfig.
60
+ * Default: auto-discovered from project root.
61
+ */
62
+ readonly tsconfig?: string;
63
+
60
64
  /**
61
65
  * Enable tsconfig path resolution. Default true.
62
66
  */
@@ -95,8 +99,7 @@ export function createTypedViteResolver(
95
99
  dependencies?: TypedViteResolverDependencies,
96
100
  ): VirtualModuleResolver {
97
101
  const httpApiFactory =
98
- dependencies?.createHttpApiVirtualModulePlugin ??
99
- createHttpApiVirtualModulePlugin;
102
+ dependencies?.createHttpApiVirtualModulePlugin ?? createHttpApiVirtualModulePlugin;
100
103
  const plugins: import("@typed/virtual-modules").VirtualModulePlugin[] = [
101
104
  createRouterVirtualModulePlugin(options.routerVmOptions ?? {}),
102
105
  httpApiFactory(options.apiVmOptions ?? {}),
@@ -104,30 +107,55 @@ export function createTypedViteResolver(
104
107
  return new PluginManager(plugins);
105
108
  }
106
109
 
110
+ function optionsFromTypedConfig(config: TypedConfig): TypedVitePluginOptions {
111
+ return {
112
+ routerVmOptions: config.router ? { prefix: config.router.prefix } : undefined,
113
+ apiVmOptions: config.api
114
+ ? { prefix: config.api.prefix, pathPrefix: config.api.pathPrefix }
115
+ : undefined,
116
+ tsconfig: config.tsconfig,
117
+ tsconfigPaths: config.tsconfigPaths,
118
+ analyze: config.analyze,
119
+ warnOnError: config.warnOnError,
120
+ compression: config.compression,
121
+ };
122
+ }
123
+
107
124
  /**
108
125
  * Returns Vite plugins: tsconfig paths, virtual modules (@typed/app), and optional bundle analyzer.
109
126
  * Use as: `defineConfig({ plugins: typedVitePlugin() })`.
110
127
  *
111
- * When createTypeInfoApiSession is not provided, the plugin automatically creates a
112
- * Language Service-backed session from the project's tsconfig. The type program evolves
113
- * as files change during dev. Pass createTypeInfoApiSession to override.
128
+ * When called with no arguments, auto-discovers `typed.config.ts` in the project root.
129
+ * When called with explicit options, those take full precedence (config file is not loaded).
114
130
  */
115
- export function typedVitePlugin(options: TypedVitePluginOptions = {}): Plugin[] {
116
- const resolver = createTypedViteResolver(options);
117
- const analyze =
118
- options.analyze ?? (process.env.ANALYZE === "1" ? true : false);
131
+ export function typedVitePlugin(options?: TypedVitePluginOptions): Plugin[] {
132
+ const resolvedOptions: TypedVitePluginOptions = (() => {
133
+ if (options) return options;
134
+ const result = loadTypedConfig({ projectRoot: process.cwd(), ts });
135
+ if (result.status === "loaded") return optionsFromTypedConfig(result.config);
136
+ return {};
137
+ })();
138
+
139
+ const resolver = createTypedViteResolver(resolvedOptions);
140
+ const analyze = resolvedOptions.analyze ?? (process.env.ANALYZE === "1" ? true : false);
119
141
 
120
142
  let createTypeInfoApiSession: CreateTypeInfoApiSession | undefined =
121
- options.createTypeInfoApiSession;
143
+ resolvedOptions.createTypeInfoApiSession;
122
144
 
123
145
  if (createTypeInfoApiSession === undefined) {
124
146
  try {
125
147
  const manager = resolver as PluginManager;
126
148
  const typeTargetSpecs = collectTypeTargetSpecsFromPlugins(manager.plugins);
149
+ const cwd = process.cwd();
150
+ const tsconfigPath = resolvedOptions.tsconfig
151
+ ? resolve(cwd, resolvedOptions.tsconfig)
152
+ : undefined;
153
+ const projectRoot = tsconfigPath ? dirname(tsconfigPath) : cwd;
127
154
  createTypeInfoApiSession = createLanguageServiceSessionFactory({
128
155
  ts,
129
- projectRoot: process.cwd(),
156
+ projectRoot,
130
157
  typeTargetSpecs,
158
+ tsconfigPath,
131
159
  });
132
160
  } catch {
133
161
  // Graceful degradation: no session, plugins get noop TypeInfoApi
@@ -136,9 +164,21 @@ export function typedVitePlugin(options: TypedVitePluginOptions = {}): Plugin[]
136
164
 
137
165
  const plugins: Plugin[] = [];
138
166
 
139
- if (options.tsconfigPaths !== false) {
167
+ if (resolvedOptions.tsconfigPaths !== false) {
168
+ const basePathsOpts =
169
+ typeof resolvedOptions.tsconfigPaths === "object" ? resolvedOptions.tsconfigPaths : {};
170
+ const cwd = process.cwd();
171
+ const resolvedTsconfig = resolvedOptions.tsconfig
172
+ ? resolve(cwd, resolvedOptions.tsconfig)
173
+ : undefined;
140
174
  const pathsOpts =
141
- typeof options.tsconfigPaths === "object" ? options.tsconfigPaths : {};
175
+ resolvedTsconfig !== undefined
176
+ ? {
177
+ ...basePathsOpts,
178
+ root: cwd,
179
+ projects: [relative(cwd, resolvedTsconfig)],
180
+ }
181
+ : basePathsOpts;
142
182
  plugins.push(tsconfigPaths(pathsOpts) as Plugin);
143
183
  }
144
184
 
@@ -146,7 +186,7 @@ export function typedVitePlugin(options: TypedVitePluginOptions = {}): Plugin[]
146
186
  virtualModulesVitePlugin({
147
187
  resolver,
148
188
  createTypeInfoApiSession,
149
- warnOnError: options.warnOnError ?? true,
189
+ warnOnError: resolvedOptions.warnOnError ?? true,
150
190
  }),
151
191
  );
152
192
 
@@ -159,12 +199,13 @@ export function typedVitePlugin(options: TypedVitePluginOptions = {}): Plugin[]
159
199
  visualizer({
160
200
  filename: vizOpts.filename ?? "dist/stats.html",
161
201
  open: vizOpts.open ?? false,
162
- template: (vizOpts.template as "treemap" | "sunburst" | "flamegraph" | "network") ?? "treemap",
202
+ template:
203
+ (vizOpts.template as "treemap" | "sunburst" | "flamegraph" | "network") ?? "treemap",
163
204
  }) as Plugin,
164
205
  );
165
206
  }
166
207
 
167
- const compression = options.compression ?? true;
208
+ const compression = resolvedOptions.compression ?? true;
168
209
  if (compression !== false) {
169
210
  const compressionOpts =
170
211
  typeof compression === "object"