Skip to content

Commit

Permalink
feat: support importing ts files using their corresponding js extesions
Browse files Browse the repository at this point in the history
To align with `tsc` default behavior, mentioned in microsoft/TypeScript#46452

Fixes vitejs#3040
  • Loading branch information
haoqunjiang committed Nov 2, 2021
1 parent ab65045 commit 739c6fc
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 7 deletions.
40 changes: 33 additions & 7 deletions packages/vite/src/node/plugins/resolve.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,10 @@ import {
cleanUrl,
slash,
nestedResolveFrom,
isFileReadable
isFileReadable,
isTsRequest,
isPossibleTsOutput,
getTsSrcPath
} from '../utils'
import { ViteDevServer, SSROptions } from '..'
import { createFilter } from '@rollup/pluginutils'
Expand Down Expand Up @@ -65,6 +68,11 @@ export interface InternalResolveOptions extends ResolveOptions {
skipPackageJson?: boolean
preferRelative?: boolean
isRequire?: boolean
// #3040
// when the importer is a ts module,
// if the specifier requests a non-existent `.js/jsx/mjs/cjs` file,
// should also try import from `.ts/tsx/mts/cts` source file as fallback,
isFromTsImporter?: boolean
}

export function resolvePlugin(baseOptions: InternalResolveOptions): Plugin {
Expand All @@ -75,10 +83,6 @@ export function resolvePlugin(baseOptions: InternalResolveOptions): Plugin {
ssrConfig,
preferRelative = false
} = baseOptions
const requireOptions: InternalResolveOptions = {
...baseOptions,
isRequire: true
}
let server: ViteDevServer | undefined

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

// this is passed by @rollup/plugin-commonjs
const isRequire =
const isRequire = !!(
resolveOpts &&
resolveOpts.custom &&
resolveOpts.custom['node-resolve'] &&
resolveOpts.custom['node-resolve'].isRequire
)

const options = isRequire ? requireOptions : baseOptions
const options: InternalResolveOptions = {
...baseOptions,

isRequire,
isFromTsImporter: isTsRequest(importer ?? '')
}

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

Expand Down Expand Up @@ -450,6 +460,22 @@ function tryResolveFile(
if (index) return index + postfix
}
}

const tryTsExtension = options.isFromTsImporter && isPossibleTsOutput(file)
if (tryTsExtension) {
const tsSrcPath = getTsSrcPath(file)
return tryResolveFile(
tsSrcPath,
postfix,
options,
tryIndex,
targetWeb,
preserveSymlinks,
tryPrefix,
skipPackageJson
)
}

if (tryPrefix) {
const prefixed = `${path.dirname(file)}/${tryPrefix}${path.basename(file)}`
return tryResolveFile(
Expand Down
8 changes: 8 additions & 0 deletions packages/vite/src/node/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,14 @@ export const isJSRequest = (url: string): boolean => {
return false
}

const knownTsRE = /\.(ts|mts|cts|tsx)$/
const knownTsOutputRE = /\.(js|mjs|cjs|jsx)$/
export const isTsRequest = (url: string) => knownTsRE.test(cleanUrl(url))
export const isPossibleTsOutput = (url: string) =>
knownTsOutputRE.test(cleanUrl(url))
export const getTsSrcPath = (filename: string) =>
filename.replace(/\.([cm])?(js)(x?)$/, '.$1ts$3')

const importQueryRE = /(\?|&)import=?(?:&|$)/
const internalPrefixes = [
FS_PREFIX,
Expand Down

0 comments on commit 739c6fc

Please sign in to comment.