Skip to content

Commit 739c6fc

Browse files
committed
feat: support importing ts files using their corresponding js extesions
To align with `tsc` default behavior, mentioned in microsoft/TypeScript#46452 Fixes vitejs#3040
1 parent ab65045 commit 739c6fc

File tree

2 files changed

+41
-7
lines changed

2 files changed

+41
-7
lines changed

packages/vite/src/node/plugins/resolve.ts

+33-7
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,10 @@ import {
2525
cleanUrl,
2626
slash,
2727
nestedResolveFrom,
28-
isFileReadable
28+
isFileReadable,
29+
isTsRequest,
30+
isPossibleTsOutput,
31+
getTsSrcPath
2932
} from '../utils'
3033
import { ViteDevServer, SSROptions } from '..'
3134
import { createFilter } from '@rollup/pluginutils'
@@ -65,6 +68,11 @@ export interface InternalResolveOptions extends ResolveOptions {
6568
skipPackageJson?: boolean
6669
preferRelative?: boolean
6770
isRequire?: boolean
71+
// #3040
72+
// when the importer is a ts module,
73+
// if the specifier requests a non-existent `.js/jsx/mjs/cjs` file,
74+
// should also try import from `.ts/tsx/mts/cts` source file as fallback,
75+
isFromTsImporter?: boolean
6876
}
6977

7078
export function resolvePlugin(baseOptions: InternalResolveOptions): Plugin {
@@ -75,10 +83,6 @@ export function resolvePlugin(baseOptions: InternalResolveOptions): Plugin {
7583
ssrConfig,
7684
preferRelative = false
7785
} = baseOptions
78-
const requireOptions: InternalResolveOptions = {
79-
...baseOptions,
80-
isRequire: true
81-
}
8286
let server: ViteDevServer | undefined
8387

8488
const { target: ssrTarget, noExternal: ssrNoExternal } = ssrConfig ?? {}
@@ -104,13 +108,19 @@ export function resolvePlugin(baseOptions: InternalResolveOptions): Plugin {
104108
const targetWeb = !ssr || ssrTarget === 'webworker'
105109

106110
// this is passed by @rollup/plugin-commonjs
107-
const isRequire =
111+
const isRequire = !!(
108112
resolveOpts &&
109113
resolveOpts.custom &&
110114
resolveOpts.custom['node-resolve'] &&
111115
resolveOpts.custom['node-resolve'].isRequire
116+
)
112117

113-
const options = isRequire ? requireOptions : baseOptions
118+
const options: InternalResolveOptions = {
119+
...baseOptions,
120+
121+
isRequire,
122+
isFromTsImporter: isTsRequest(importer ?? '')
123+
}
114124

115125
const preserveSymlinks = !!server?.config.resolve.preserveSymlinks
116126

@@ -450,6 +460,22 @@ function tryResolveFile(
450460
if (index) return index + postfix
451461
}
452462
}
463+
464+
const tryTsExtension = options.isFromTsImporter && isPossibleTsOutput(file)
465+
if (tryTsExtension) {
466+
const tsSrcPath = getTsSrcPath(file)
467+
return tryResolveFile(
468+
tsSrcPath,
469+
postfix,
470+
options,
471+
tryIndex,
472+
targetWeb,
473+
preserveSymlinks,
474+
tryPrefix,
475+
skipPackageJson
476+
)
477+
}
478+
453479
if (tryPrefix) {
454480
const prefixed = `${path.dirname(file)}/${tryPrefix}${path.basename(file)}`
455481
return tryResolveFile(

packages/vite/src/node/utils.ts

+8
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,14 @@ export const isJSRequest = (url: string): boolean => {
164164
return false
165165
}
166166

167+
const knownTsRE = /\.(ts|mts|cts|tsx)$/
168+
const knownTsOutputRE = /\.(js|mjs|cjs|jsx)$/
169+
export const isTsRequest = (url: string) => knownTsRE.test(cleanUrl(url))
170+
export const isPossibleTsOutput = (url: string) =>
171+
knownTsOutputRE.test(cleanUrl(url))
172+
export const getTsSrcPath = (filename: string) =>
173+
filename.replace(/\.([cm])?(js)(x?)$/, '.$1ts$3')
174+
167175
const importQueryRE = /(\?|&)import=?(?:&|$)/
168176
const internalPrefixes = [
169177
FS_PREFIX,

0 commit comments

Comments
 (0)