Skip to content

Commit

Permalink
fix(resolve): support resolving TS files by JS extension specifiers i…
Browse files Browse the repository at this point in the history
…n JS files (#18889)
  • Loading branch information
sapphi-red authored Jan 23, 2025
1 parent 2c2d521 commit 612332b
Show file tree
Hide file tree
Showing 6 changed files with 29 additions and 49 deletions.
35 changes: 7 additions & 28 deletions packages/vite/src/node/optimizer/scan.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,11 +105,6 @@ export function devToScanEnvironment(
} as unknown as ScanEnvironment
}

type ResolveIdOptions = Omit<
Parameters<EnvironmentPluginContainer['resolveId']>[2],
'environment'
>

const debug = createDebugger('vite:deps')

const htmlTypesRE = /\.(html|vue|svelte|astro|imba)$/
Expand Down Expand Up @@ -383,27 +378,19 @@ function esbuildScanPlugin(
async function resolveId(
id: string,
importer?: string,
options?: ResolveIdOptions,
): Promise<PartialResolvedId | null> {
return environment.pluginContainer.resolveId(
id,
importer && normalizePath(importer),
{
...options,
scan: true,
},
{ scan: true },
)
}
const resolve = async (
id: string,
importer?: string,
options?: ResolveIdOptions,
) => {
const resolve = async (id: string, importer?: string) => {
const key = id + (importer && path.dirname(importer))
if (seen.has(key)) {
return seen.get(key)
}
const resolved = await resolveId(id, importer, options)
const resolved = await resolveId(id, importer)
const res = resolved?.id
seen.set(key, res)
return res
Expand Down Expand Up @@ -633,18 +620,14 @@ function esbuildScanPlugin(
// avoid matching windows volume
filter: /^[\w@][^:]/,
},
async ({ path: id, importer, pluginData }) => {
async ({ path: id, importer }) => {
if (moduleListContains(exclude, id)) {
return externalUnlessEntry({ path: id })
}
if (depImports[id]) {
return externalUnlessEntry({ path: id })
}
const resolved = await resolve(id, importer, {
custom: {
depScan: { loader: pluginData?.htmlType?.loader },
},
})
const resolved = await resolve(id, importer)
if (resolved) {
if (shouldExternalizeDep(resolved, id)) {
return externalUnlessEntry({ path: id })
Expand Down Expand Up @@ -706,13 +689,9 @@ function esbuildScanPlugin(
{
filter: /.*/,
},
async ({ path: id, importer, pluginData }) => {
async ({ path: id, importer }) => {
// use vite resolver to support urls and omitted extensions
const resolved = await resolve(id, importer, {
custom: {
depScan: { loader: pluginData?.htmlType?.loader },
},
})
const resolved = await resolve(id, importer)
if (resolved) {
if (
shouldExternalizeDep(resolved, id) ||
Expand Down
20 changes: 2 additions & 18 deletions packages/vite/src/node/plugins/resolve.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ import {
isNonDriveRelativeAbsolutePath,
isObject,
isOptimizable,
isTsRequest,
normalizePath,
safeRealpathSync,
tryStatSync,
Expand Down Expand Up @@ -125,10 +124,7 @@ interface ResolvePluginOptions {
tryPrefix?: string
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.
/** @deprecated */
isFromTsImporter?: boolean
// True when resolving during the scan phase to discover dependencies
scan?: boolean
Expand Down Expand Up @@ -241,18 +237,6 @@ export function resolvePlugin(
}
}

if (importer) {
if (
isTsRequest(importer) ||
resolveOpts.custom?.depScan?.loader?.startsWith('ts')
) {
options.isFromTsImporter = true
} else {
const moduleLang = this.getModuleInfo(importer)?.meta.vite?.lang
options.isFromTsImporter = moduleLang && isTsRequest(`.${moduleLang}`)
}
}

let res: string | PartialResolvedId | undefined

// resolve pre-bundled deps requests, these could be resolved by
Expand Down Expand Up @@ -616,7 +600,7 @@ function tryCleanFsResolve(
let res: string | undefined

// If path.dirname is a valid directory, try extensions and ts resolution logic
const possibleJsToTs = options.isFromTsImporter && isPossibleTsOutput(file)
const possibleJsToTs = isPossibleTsOutput(file)
if (possibleJsToTs || options.extensions.length || tryPrefix) {
const dirPath = path.dirname(file)
if (isDirectory(dirPath)) {
Expand Down
3 changes: 0 additions & 3 deletions packages/vite/src/node/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -327,9 +327,6 @@ export const isJSRequest = (url: string): boolean => {
return false
}

const knownTsRE = /\.(?:ts|mts|cts|tsx)(?:$|\?)/
export const isTsRequest = (url: string): boolean => knownTsRE.test(url)

const importQueryRE = /(\?|&)import=?(?:&|$)/
const directRequestRE = /(\?|&)direct=?(?:&|$)/
const internalPrefixes = [
Expand Down
4 changes: 4 additions & 0 deletions playground/resolve/__tests__/resolve.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,10 @@ test('a ts module can import another ts module using its corresponding js file n
expect(await page.textContent('.ts-extension')).toMatch('[success]')
})

test('a js module can import another ts module using its corresponding js file name', async () => {
expect(await page.textContent('.js-ts-extension')).toMatch('[success]')
})

test('filename with dot', async () => {
expect(await page.textContent('.dot')).toMatch('[success]')
})
Expand Down
6 changes: 6 additions & 0 deletions playground/resolve/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,9 @@ <h2>
</h2>
<p class="cjs-extension">fail</p>

<h2>A js module can import TS modules using its corresponding js file name</h2>
<p class="js-ts-extension">fail</p>

<h2>Resolve file name containing dot</h2>
<p class="dot">fail</p>

Expand Down Expand Up @@ -304,6 +307,9 @@ <h2>utf8-bom-package</h2>
import { msgMjs as tsMjsExtensionWithQueryMsg } from './ts-extension?query=1'
text('.mjs-extension-with-query', tsMjsExtensionWithQueryMsg)

import { msg as jsTsExtensionMsg } from './ts-extension/index-js.js'
text('.js-ts-extension', jsTsExtensionMsg)

// filename with dot
import { bar } from './util/bar.util'
text('.dot', bar())
Expand Down
10 changes: 10 additions & 0 deletions playground/resolve/ts-extension/index-js.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { msg as msgJs } from './hello.js'
import { msgJsx } from './hellojsx.jsx'
import { msgTsx } from './hellotsx.js'
import { msgCjs } from './hellocjs.cjs'
import { msgMjs } from './hellomjs.mjs'

export const msg =
msgJs && msgJsx && msgTsx && msgCjs && msgMjs
? '[success] use .js / .jsx / .cjs / .mjs extension to import a TS modules'
: '[fail]'

0 comments on commit 612332b

Please sign in to comment.