Skip to content

Commit 6a7e313

Browse files
authored
feat!: support file:// resolution (#18422)
1 parent 1e5703b commit 6a7e313

File tree

9 files changed

+122
-0
lines changed

9 files changed

+122
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export default 'ok'
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"type": "module"
3+
}

packages/vite/src/node/__tests__/resolve.spec.ts

+98
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
1+
import { join } from 'node:path'
12
import { describe, expect, onTestFinished, test } from 'vitest'
23
import { createServer } from '../server'
34
import { createServerModuleRunner } from '../ssr/runtime/serverModuleRunner'
5+
import type { InlineConfig } from '../config'
6+
import { build } from '../build'
47

58
describe('import and resolveId', () => {
69
async function createTestServer() {
@@ -50,3 +53,98 @@ describe('import and resolveId', () => {
5053
])
5154
})
5255
})
56+
57+
describe('file url', () => {
58+
const fileUrl = new URL('./fixtures/file-url/entry.js', import.meta.url)
59+
60+
function getConfig(): InlineConfig {
61+
return {
62+
configFile: false,
63+
root: join(import.meta.dirname, 'fixtures/file-url'),
64+
logLevel: 'error',
65+
server: {
66+
middlewareMode: true,
67+
},
68+
plugins: [
69+
{
70+
name: 'virtual-file-url',
71+
resolveId(source) {
72+
if (source.startsWith('virtual:test-dep/')) {
73+
return '\0' + source
74+
}
75+
},
76+
load(id) {
77+
if (id === '\0virtual:test-dep/static') {
78+
return `
79+
import * as dep from ${JSON.stringify(fileUrl.href)};
80+
export default dep;
81+
`
82+
}
83+
if (id === '\0virtual:test-dep/non-static') {
84+
return `
85+
const dep = await import(/* @vite-ignore */ String(${JSON.stringify(fileUrl.href)}));
86+
export default dep;
87+
`
88+
}
89+
},
90+
},
91+
],
92+
}
93+
}
94+
95+
test('dev', async () => {
96+
const server = await createServer(getConfig())
97+
onTestFinished(() => server.close())
98+
99+
const runner = createServerModuleRunner(server.environments.ssr, {
100+
hmr: {
101+
logger: false,
102+
},
103+
sourcemapInterceptor: false,
104+
})
105+
106+
const mod = await runner.import('/entry.js')
107+
expect(mod.default).toEqual('ok')
108+
109+
const mod2 = await runner.import(fileUrl.href)
110+
expect(mod2).toBe(mod)
111+
112+
const mod3 = await runner.import('virtual:test-dep/static')
113+
expect(mod3.default).toBe(mod)
114+
115+
const mod4 = await runner.import('virtual:test-dep/non-static')
116+
expect(mod4.default).toBe(mod)
117+
})
118+
119+
test('build', async () => {
120+
await build({
121+
...getConfig(),
122+
build: {
123+
ssr: true,
124+
outDir: 'dist/basic',
125+
rollupOptions: {
126+
input: { index: fileUrl.href },
127+
},
128+
},
129+
})
130+
const mod1 = await import(
131+
join(import.meta.dirname, 'fixtures/file-url/dist/basic/index.js')
132+
)
133+
expect(mod1.default).toBe('ok')
134+
135+
await build({
136+
...getConfig(),
137+
build: {
138+
ssr: true,
139+
outDir: 'dist/virtual',
140+
rollupOptions: {
141+
input: { index: 'virtual:test-dep/static' },
142+
},
143+
},
144+
})
145+
const mod2 = await import(
146+
join(import.meta.dirname, 'fixtures/file-url/dist/virtual/index.js')
147+
)
148+
expect(mod2.default.default).toBe('ok')
149+
})
150+
})

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

+6
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import fs from 'node:fs'
22
import path from 'node:path'
3+
import { fileURLToPath } from 'node:url'
34
import colors from 'picocolors'
45
import type { PartialResolvedId } from 'rollup'
56
import { exports, imports } from 'resolve.exports'
@@ -364,6 +365,11 @@ export function resolvePlugin(
364365
}
365366
}
366367

368+
// file url as path
369+
if (id.startsWith('file://')) {
370+
id = fileURLToPath(id)
371+
}
372+
367373
// drive relative fs paths (only windows)
368374
if (isWindows && id[0] === '/') {
369375
const basedir = importer ? path.dirname(importer) : process.cwd()

playground/resolve/__tests__/resolve.spec.ts

+4
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,10 @@ test('absolute path', async () => {
123123
expect(await page.textContent('.absolute')).toMatch('[success]')
124124
})
125125

126+
test('file url', async () => {
127+
expect(await page.textContent('.file-url')).toMatch('[success]')
128+
})
129+
126130
test('browser field', async () => {
127131
expect(await page.textContent('.browser')).toMatch('[success]')
128132
})

playground/resolve/file-url.js

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export default '[success] file-url'

playground/resolve/index.html

+3
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,9 @@ <h2>Resolve drive-relative path (Windows only)</h2>
122122
<h2>Resolve absolute path</h2>
123123
<p class="absolute">fail</p>
124124

125+
<h2>Resolve file url</h2>
126+
<p class="file-url">fail</p>
127+
125128
<h2>Browser Field</h2>
126129
<p class="browser">fail</p>
127130

playground/resolve/vite.config.js

+4
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@ const generatedContentImports = [
2222
specifier: normalizePath(path.resolve(__dirname, './absolute.js')),
2323
elementQuery: '.absolute',
2424
},
25+
{
26+
specifier: new URL('file-url.js', import.meta.url),
27+
elementQuery: '.file-url',
28+
},
2529
]
2630

2731
export default defineConfig({

pnpm-lock.yaml

+2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)