Skip to content

Commit

Permalink
feat!: support file:// resolution (#18422)
Browse files Browse the repository at this point in the history
  • Loading branch information
hi-ogawa authored Oct 28, 2024
1 parent 1e5703b commit 6a7e313
Show file tree
Hide file tree
Showing 9 changed files with 122 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export default 'ok'
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"type": "module"
}
98 changes: 98 additions & 0 deletions packages/vite/src/node/__tests__/resolve.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import { join } from 'node:path'
import { describe, expect, onTestFinished, test } from 'vitest'
import { createServer } from '../server'
import { createServerModuleRunner } from '../ssr/runtime/serverModuleRunner'
import type { InlineConfig } from '../config'
import { build } from '../build'

describe('import and resolveId', () => {
async function createTestServer() {
Expand Down Expand Up @@ -50,3 +53,98 @@ describe('import and resolveId', () => {
])
})
})

describe('file url', () => {
const fileUrl = new URL('./fixtures/file-url/entry.js', import.meta.url)

function getConfig(): InlineConfig {
return {
configFile: false,
root: join(import.meta.dirname, 'fixtures/file-url'),
logLevel: 'error',
server: {
middlewareMode: true,
},
plugins: [
{
name: 'virtual-file-url',
resolveId(source) {
if (source.startsWith('virtual:test-dep/')) {
return '\0' + source
}
},
load(id) {
if (id === '\0virtual:test-dep/static') {
return `
import * as dep from ${JSON.stringify(fileUrl.href)};
export default dep;
`
}
if (id === '\0virtual:test-dep/non-static') {
return `
const dep = await import(/* @vite-ignore */ String(${JSON.stringify(fileUrl.href)}));
export default dep;
`
}
},
},
],
}
}

test('dev', async () => {
const server = await createServer(getConfig())
onTestFinished(() => server.close())

const runner = createServerModuleRunner(server.environments.ssr, {
hmr: {
logger: false,
},
sourcemapInterceptor: false,
})

const mod = await runner.import('/entry.js')
expect(mod.default).toEqual('ok')

const mod2 = await runner.import(fileUrl.href)
expect(mod2).toBe(mod)

const mod3 = await runner.import('virtual:test-dep/static')
expect(mod3.default).toBe(mod)

const mod4 = await runner.import('virtual:test-dep/non-static')
expect(mod4.default).toBe(mod)
})

test('build', async () => {
await build({
...getConfig(),
build: {
ssr: true,
outDir: 'dist/basic',
rollupOptions: {
input: { index: fileUrl.href },
},
},
})
const mod1 = await import(
join(import.meta.dirname, 'fixtures/file-url/dist/basic/index.js')
)
expect(mod1.default).toBe('ok')

await build({
...getConfig(),
build: {
ssr: true,
outDir: 'dist/virtual',
rollupOptions: {
input: { index: 'virtual:test-dep/static' },
},
},
})
const mod2 = await import(
join(import.meta.dirname, 'fixtures/file-url/dist/virtual/index.js')
)
expect(mod2.default.default).toBe('ok')
})
})
6 changes: 6 additions & 0 deletions packages/vite/src/node/plugins/resolve.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import fs from 'node:fs'
import path from 'node:path'
import { fileURLToPath } from 'node:url'
import colors from 'picocolors'
import type { PartialResolvedId } from 'rollup'
import { exports, imports } from 'resolve.exports'
Expand Down Expand Up @@ -364,6 +365,11 @@ export function resolvePlugin(
}
}

// file url as path
if (id.startsWith('file://')) {
id = fileURLToPath(id)
}

// drive relative fs paths (only windows)
if (isWindows && id[0] === '/') {
const basedir = importer ? path.dirname(importer) : process.cwd()
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 @@ -123,6 +123,10 @@ test('absolute path', async () => {
expect(await page.textContent('.absolute')).toMatch('[success]')
})

test('file url', async () => {
expect(await page.textContent('.file-url')).toMatch('[success]')
})

test('browser field', async () => {
expect(await page.textContent('.browser')).toMatch('[success]')
})
Expand Down
1 change: 1 addition & 0 deletions playground/resolve/file-url.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export default '[success] file-url'
3 changes: 3 additions & 0 deletions playground/resolve/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,9 @@ <h2>Resolve drive-relative path (Windows only)</h2>
<h2>Resolve absolute path</h2>
<p class="absolute">fail</p>

<h2>Resolve file url</h2>
<p class="file-url">fail</p>

<h2>Browser Field</h2>
<p class="browser">fail</p>

Expand Down
4 changes: 4 additions & 0 deletions playground/resolve/vite.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ const generatedContentImports = [
specifier: normalizePath(path.resolve(__dirname, './absolute.js')),
elementQuery: '.absolute',
},
{
specifier: new URL('file-url.js', import.meta.url),
elementQuery: '.file-url',
},
]

export default defineConfig({
Expand Down
2 changes: 2 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 6a7e313

Please sign in to comment.