Skip to content

Commit da632bf

Browse files
authored
refactor(types): bundle client types (#9966)
1 parent bafccf5 commit da632bf

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

72 files changed

+2216
-2032
lines changed

.eslintignore

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
dist
22
playground-temp
33
temp
4-
4+
packages/vite/client/types.d.ts

.eslintrc.cjs

+1-1
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ module.exports = defineConfig({
131131
}
132132
},
133133
{
134-
files: ['packages/vite/types/**', '*.spec.ts'],
134+
files: ['packages/vite/src/dep-types/**', '*.spec.ts'],
135135
rules: {
136136
'node/no-extraneous-import': 'off'
137137
}

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
*.local
66
*.log
77
/.vscode/
8+
/packages/vite/client/types.d.ts
89
/packages/vite/LICENSE
910
dist
1011
dist-ssr

.prettierignore

+1
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,4 @@ playground/tsconfig-json-load-error/has-error/tsconfig.json
99
playground/html/invalid.html
1010
playground/html/valid.html
1111
playground/worker/classic-worker.js
12+
packages/vite/client/types.d.ts

CONTRIBUTING.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,7 @@ Avoid deps with large transitive dependencies that result in bloated size compar
218218

219219
Vite aims to be fully usable as a dependency in a TypeScript project (e.g. it should provide proper typings for VitePress), and also in `vite.config.ts`. This means technically a dependency whose types are exposed needs to be part of `dependencies` instead of `devDependencies`. However, this also means we won't be able to bundle it.
220220

221-
To get around this, we inline some of these dependencies' types in `packages/vite/types`. This way, we can still expose the typing but bundle the dependency's source code.
221+
To get around this, we inline some of these dependencies' types in `packages/vite/src/dep-types`. This way, we can still expose the typing but bundle the dependency's source code.
222222

223223
Use `pnpm run check-dist-types` to check that the bundled types do not rely on types in `devDependencies`. If you are adding `dependencies`, make sure to configure `tsconfig.check.json`.
224224

docs/guide/api-plugin.md

+15-6
Original file line numberDiff line numberDiff line change
@@ -595,12 +595,21 @@ It is possible to type custom events by extending the `CustomEventMap` interface
595595

596596
```ts
597597
// events.d.ts
598-
import 'vite/types/customEvent'
598+
import 'vite'
599+
import 'vite/client/types'
599600
600-
declare module 'vite/types/customEvent' {
601-
interface CustomEventMap {
602-
'custom:foo': { msg: string }
603-
// 'event-key': payload
604-
}
601+
interface MyCustomEventMap {
602+
'custom:foo': { msg: string }
603+
// 'event-key': payload
604+
}
605+
606+
// extend interface for server-side
607+
declare module 'vite' {
608+
interface CustomEventMap extends MyCustomEventMap {}
609+
}
610+
611+
// extend interface for client-side
612+
declare module 'vite/client/types' {
613+
interface CustomEventMap extends MyCustomEventMap {}
605614
}
606615
```

packages/plugin-legacy/tsconfig.json

-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
"noUnusedLocals": true,
1313
"esModuleInterop": true,
1414
"paths": {
15-
"types/*": ["../vite/types/*"],
1615
"vite": ["../vite/src/node/index.js"]
1716
}
1817
}

packages/plugin-react/tsconfig.json

-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
"noUnusedLocals": true,
1313
"esModuleInterop": true,
1414
"paths": {
15-
"types/*": ["../vite/types/*"],
1615
"vite": ["../vite/src/node/index.js"]
1716
}
1817
}

packages/plugin-vue-jsx/tsconfig.json

-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
"noUnusedLocals": true,
1313
"esModuleInterop": true,
1414
"paths": {
15-
"types/*": ["../vite/types/*"],
1615
"vite": ["../vite/src/node/index.js"]
1716
}
1817
}

packages/plugin-vue/tsconfig.json

-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
"esModuleInterop": true,
1515
"baseUrl": ".",
1616
"paths": {
17-
"types/*": ["../vite/types/*"],
1817
"vite": ["../vite/src/node/index.js"]
1918
}
2019
}
+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
{
2+
"$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json",
3+
4+
"projectFolder": "./src/client",
5+
6+
"mainEntryPointFilePath": "./src/client-types.d.ts",
7+
8+
"dtsRollup": {
9+
"enabled": true,
10+
"untrimmedFilePath": "",
11+
"publicTrimmedFilePath": "./client/types.d.ts"
12+
},
13+
14+
"apiReport": {
15+
"enabled": false
16+
},
17+
18+
"docModel": {
19+
"enabled": false
20+
},
21+
22+
"tsdocMetadata": {
23+
"enabled": false
24+
},
25+
26+
"messages": {
27+
"compilerMessageReporting": {
28+
"default": {
29+
"logLevel": "warning"
30+
}
31+
},
32+
33+
"extractorMessageReporting": {
34+
"default": {
35+
"logLevel": "warning",
36+
"addToApiReportFile": true
37+
},
38+
39+
"ae-missing-release-tag": {
40+
"logLevel": "none"
41+
}
42+
},
43+
44+
"tsdocMessageReporting": {
45+
"default": {
46+
"logLevel": "warning"
47+
},
48+
49+
"tsdoc-undefined-tag": {
50+
"logLevel": "none"
51+
}
52+
}
53+
}
54+
}

packages/vite/client.d.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/// <reference path="./types/importMeta.d.ts" />
1+
/// <reference path="./import-meta.d.ts" />
22

33
// CSS modules
44
type CSSModuleClasses = { readonly [key: string]: string }

packages/vite/import-meta.d.ts

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import type {
2+
ImportMeta as ViteImportMeta,
3+
ImportMetaEnv as ViteImportMetaEnv
4+
// eslint-disable-next-line node/no-missing-import -- use .js for `moduleResolution: "nodenext"`
5+
} from './client/types.js'
6+
7+
declare global {
8+
interface ImportMeta extends ViteImportMeta {}
9+
interface ImportMetaEnv extends ViteImportMetaEnv {}
10+
}

packages/vite/package.json

+18-7
Original file line numberDiff line numberDiff line change
@@ -20,16 +20,24 @@
2020
"./client": {
2121
"types": "./client.d.ts"
2222
},
23+
"./import-meta": {
24+
"types": "./import-meta.d.ts"
25+
},
26+
"./client/types": {
27+
"types": "./client/types.d.ts"
28+
},
2329
"./dist/client/*": "./dist/client/*",
2430
"./package.json": "./package.json"
2531
},
2632
"files": [
2733
"bin",
2834
"dist",
2935
"client.d.ts",
36+
"import-meta.d.ts",
3037
"index.cjs",
3138
"src/client",
32-
"types"
39+
"types",
40+
"client/types.d.ts"
3341
],
3442
"engines": {
3543
"node": "^14.18.0 || >=16.0.0"
@@ -47,11 +55,13 @@
4755
"dev": "rimraf dist && pnpm run build-bundle -w",
4856
"build": "rimraf dist && run-s build-bundle build-types",
4957
"build-bundle": "rollup --config rollup.config.ts --configPlugin typescript",
50-
"build-types": "run-s build-temp-types patch-types roll-types check-dist-types",
51-
"build-temp-types": "tsc --emitDeclarationOnly --outDir temp/node -p src/node",
52-
"patch-types": "tsx scripts/patchTypes.ts",
53-
"roll-types": "api-extractor run && rimraf temp",
54-
"check-dist-types": "tsc --project tsconfig.check.json",
58+
"build-types": "run-p build-node-types build-client-types",
59+
"build-node-types": "run-s build-node-types-temp build-node-types-patch build-node-types-roll build-node-types-check",
60+
"build-node-types-temp": "tsc --emitDeclarationOnly --outDir temp/node -p src/node",
61+
"build-node-types-patch": "tsx scripts/patchTypes.ts",
62+
"build-node-types-roll": "api-extractor run && rimraf temp",
63+
"build-node-types-check": "tsc --project tsconfig.check.json",
64+
"build-client-types": "api-extractor run -c api-extractor.client.json",
5565
"lint": "eslint --cache --ext .ts src/**",
5666
"format": "prettier --write --cache --parser typescript \"src/**/*.ts\"",
5767
"prepublishOnly": "npm run build"
@@ -117,7 +127,8 @@
117127
"strip-literal": "^0.4.2",
118128
"tsconfck": "^2.0.1",
119129
"tslib": "^2.4.0",
120-
"types": "link:./types",
130+
"dep-types": "link:./src/dep-types",
131+
"types": "link:./src/types",
121132
"ufo": "^0.8.5",
122133
"ws": "^8.9.0"
123134
},

packages/vite/scripts/patchTypes.ts

+30-15
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,20 @@ import { dirname, relative, resolve } from 'node:path'
33
import { fileURLToPath } from 'node:url'
44
import type { ParseResult } from '@babel/parser'
55
import { parse } from '@babel/parser'
6-
import type { File } from '@babel/types'
6+
import type { File, StringLiteral } from '@babel/types'
77
import colors from 'picocolors'
88
import MagicString from 'magic-string'
99

1010
const dir = dirname(fileURLToPath(import.meta.url))
1111
const tempDir = resolve(dir, '../temp/node')
12-
const typesDir = resolve(dir, '../types')
12+
const typesDir = resolve(dir, '../src/types')
13+
const depTypesDir = resolve(dir, '../src/dep-types')
1314

14-
// walk through the temp dts dir, find all import/export of types/*
15+
// walk through the temp dts dir, find all import/export of types/*, deps-types/*
1516
// and rewrite them into relative imports - so that api-extractor actually
1617
// includes them in the rolled-up final d.ts file.
1718
walkDir(tempDir)
18-
console.log(colors.green(colors.bold(`patched types/* imports`)))
19+
console.log(colors.green(colors.bold(`patched types/*, deps-types/* imports`)))
1920

2021
function slash(p: string): string {
2122
return p.replace(/\\/g, '/')
@@ -49,20 +50,34 @@ function rewriteFile(file: string): void {
4950
}
5051
for (const statement of ast.program.body) {
5152
if (
52-
(statement.type === 'ImportDeclaration' ||
53-
statement.type === 'ExportNamedDeclaration' ||
54-
statement.type === 'ExportAllDeclaration') &&
55-
statement.source?.value.startsWith('types/')
53+
statement.type === 'ImportDeclaration' ||
54+
statement.type === 'ExportNamedDeclaration' ||
55+
statement.type === 'ExportAllDeclaration'
5656
) {
5757
const source = statement.source
58-
const absoluteTypePath = resolve(typesDir, source.value.slice(6))
59-
const relativeTypePath = slash(relative(dirname(file), absoluteTypePath))
60-
str.overwrite(
61-
source.start!,
62-
source.end!,
63-
JSON.stringify(relativeTypePath)
64-
)
58+
if (source?.value.startsWith('types/')) {
59+
rewriteSource(str, source, file, typesDir, 'types')
60+
} else if (source?.value.startsWith('dep-types/')) {
61+
rewriteSource(str, source, file, depTypesDir, 'dep-types')
62+
}
6563
}
6664
}
6765
writeFileSync(file, str.toString())
6866
}
67+
68+
function rewriteSource(
69+
str: MagicString,
70+
source: StringLiteral,
71+
rewritingFile: string,
72+
typesDir: string,
73+
typesDirName: string
74+
) {
75+
const absoluteTypePath = resolve(
76+
typesDir,
77+
source.value.slice(typesDirName.length + 1)
78+
)
79+
const relativeTypePath = slash(
80+
relative(dirname(rewritingFile), absoluteTypePath)
81+
)
82+
str.overwrite(source.start!, source.end!, JSON.stringify(relativeTypePath))
83+
}

packages/vite/src/client-types.d.ts

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
export type {
2+
CustomEventMap,
3+
InferCustomEventPayload
4+
} from './types/customEvent'
5+
export type {
6+
HMRPayload,
7+
ConnectedPayload,
8+
UpdatePayload,
9+
Update,
10+
PrunePayload,
11+
FullReloadPayload,
12+
CustomPayload,
13+
ErrorPayload
14+
} from './types/hmrPayload'
15+
export type { ModuleNamespace, ViteHotContext } from './types/hot'
16+
export type {
17+
ImportGlobOptions,
18+
GeneralImportGlobOptions,
19+
KnownAsTypeMap,
20+
ImportGlobFunction,
21+
ImportGlobEagerFunction
22+
} from './types/importGlob'
23+
export type { ImportMetaEnv, ImportMeta } from './types/importMeta'

packages/vite/src/client/tsconfig.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"extends": "../../tsconfig.base.json",
3-
"include": ["./", "../../types"],
3+
"include": ["./", "../types"],
44
"compilerOptions": {
55
"types": [],
66
"target": "ES2019",
+59
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/**
2+
Types from https://github.com/rollup/plugins/blob/master/packages/alias/types/index.d.ts
3+
Inlined because the plugin is bundled.
4+
5+
https://github.com/rollup/plugins/blob/master/LICENSE
6+
7+
The MIT License (MIT)
8+
9+
Copyright (c) 2019 RollupJS Plugin Contributors (https://github.com/rollup/plugins/graphs/contributors)
10+
11+
Permission is hereby granted, free of charge, to any person obtaining a copy
12+
of this software and associated documentation files (the "Software"), to deal
13+
in the Software without restriction, including without limitation the rights
14+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15+
copies of the Software, and to permit persons to whom the Software is
16+
furnished to do so, subject to the following conditions:
17+
18+
The above copyright notice and this permission notice shall be included in
19+
all copies or substantial portions of the Software.
20+
21+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
27+
THE SOFTWARE.
28+
*/
29+
30+
import type { PluginHooks } from 'rollup'
31+
32+
export interface Alias {
33+
find: string | RegExp
34+
replacement: string
35+
/**
36+
* Instructs the plugin to use an alternative resolving algorithm,
37+
* rather than the Rollup's resolver.
38+
* @default null
39+
*/
40+
customResolver?: ResolverFunction | ResolverObject | null
41+
}
42+
43+
export type ResolverFunction = PluginHooks['resolveId']
44+
45+
export interface ResolverObject {
46+
buildStart?: PluginHooks['buildStart']
47+
resolveId: ResolverFunction
48+
}
49+
50+
/**
51+
* Specifies an `Object`, or an `Array` of `Object`,
52+
* which defines aliases used to replace values in `import` or `require` statements.
53+
* With either format, the order of the entries is important,
54+
* in that the first defined rules are applied first.
55+
*
56+
* This is passed to \@rollup/plugin-alias as the "entries" field
57+
* https://github.com/rollup/plugins/tree/master/packages/alias#entries
58+
*/
59+
export type AliasOptions = readonly Alias[] | { [find: string]: string }
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
export type AnymatchFn = (testString: string) => boolean
2+
export type AnymatchPattern = string | RegExp | AnymatchFn
3+
type AnymatchMatcher = AnymatchPattern | AnymatchPattern[]
4+
5+
export { AnymatchMatcher as Matcher }

0 commit comments

Comments
 (0)