Skip to content

Commit

Permalink
feat(assets): allow new URL to resolve package assets (#7837)
Browse files Browse the repository at this point in the history
  • Loading branch information
kherock committed Sep 23, 2022
1 parent a32777f commit bafccf5
Show file tree
Hide file tree
Showing 14 changed files with 157 additions and 21 deletions.
2 changes: 0 additions & 2 deletions packages/vite/src/node/build.ts
Expand Up @@ -42,7 +42,6 @@ import {
getDepsCacheDir,
initDepsOptimizer
} from './optimizer'
import { assetImportMetaUrlPlugin } from './plugins/assetImportMetaUrl'
import { loadFallbackPlugin } from './plugins/loadFallback'
import type { PackageData } from './packages'
import { watchPackageDataPlugin } from './packages'
Expand Down Expand Up @@ -310,7 +309,6 @@ export function resolveBuildPlugins(config: ResolvedConfig): {
watchPackageDataPlugin(config),
...(usePluginCommonjs ? [commonjsPlugin(options.commonjsOptions)] : []),
dataURIPlugin(),
assetImportMetaUrlPlugin(config),
...(options.rollupOptions.plugins
? (options.rollupOptions.plugins.filter(Boolean) as Plugin[])
: [])
Expand Down
52 changes: 45 additions & 7 deletions packages/vite/src/node/plugins/assetImportMetaUrl.ts
Expand Up @@ -3,7 +3,13 @@ import MagicString from 'magic-string'
import { stripLiteral } from 'strip-literal'
import type { Plugin } from '../plugin'
import type { ResolvedConfig } from '../config'
import { transformStableResult } from '../utils'
import type { ResolveFn } from '../'
import {
isParentDirectory,
normalizePath,
slash,
transformStableResult
} from '../utils'
import { fileToUrl } from './asset'
import { preloadHelperId } from './importAnalysisBuild'

Expand All @@ -18,6 +24,9 @@ import { preloadHelperId } from './importAnalysisBuild'
* ```
*/
export function assetImportMetaUrlPlugin(config: ResolvedConfig): Plugin {
const normalizedPublicDir = normalizePath(config.publicDir)
let assetResolver: ResolveFn

return {
name: 'vite:asset-import-meta-url',
async transform(code, id, options) {
Expand Down Expand Up @@ -63,16 +72,45 @@ export function assetImportMetaUrlPlugin(config: ResolvedConfig): Plugin {
}

const url = rawUrl.slice(1, -1)
const file = path.resolve(path.dirname(id), url)
// Get final asset URL. Catch error if the file does not exist,
// in which we can resort to the initial URL and let it resolve in runtime
const builtUrl = await fileToUrl(file, config, this).catch(() => {
let file: string | undefined
if (url.startsWith('.')) {
file = slash(path.resolve(path.dirname(id), url))
} else {
assetResolver ??= config.createResolver({
extensions: [],
mainFields: [],
tryIndex: false,
preferRelative: true
})
file = await assetResolver(url, id)
file ??= url.startsWith('/')
? slash(path.join(config.publicDir, url))
: slash(path.resolve(path.dirname(id), url))
}

// Get final asset URL. If the file does not exist,
// we fall back to the initial URL and let it resolve in runtime
let builtUrl: string | undefined
if (file) {
try {
if (isParentDirectory(normalizedPublicDir, file)) {
const publicPath =
'/' + path.posix.relative(normalizedPublicDir, file)
builtUrl = await fileToUrl(publicPath, config, this)
} else {
builtUrl = await fileToUrl(file, config, this)
}
} catch {
// do nothing, we'll log a warning after this
}
}
if (!builtUrl) {
const rawExp = code.slice(index, index + exp.length)
config.logger.warnOnce(
`\n${rawExp} doesn't exist at build time, it will remain unchanged to be resolved at runtime`
)
return url
})
builtUrl = url
}
s.overwrite(
index,
index + exp.length,
Expand Down
2 changes: 2 additions & 0 deletions packages/vite/src/node/plugins/index.ts
Expand Up @@ -20,6 +20,7 @@ import { preAliasPlugin } from './preAlias'
import { definePlugin } from './define'
import { ssrRequireHookPlugin } from './ssrRequireHook'
import { workerImportMetaUrlPlugin } from './workerImportMetaUrl'
import { assetImportMetaUrlPlugin } from './assetImportMetaUrl'
import { ensureWatchPlugin } from './ensureWatch'
import { metadataPlugin } from './metadata'
import { dynamicImportVarsPlugin } from './dynamicImportVars'
Expand Down Expand Up @@ -88,6 +89,7 @@ export async function resolvePlugins(
isBuild && config.build.ssr ? ssrRequireHookPlugin(config) : null,
isBuild && buildHtmlPlugin(config),
workerImportMetaUrlPlugin(config),
assetImportMetaUrlPlugin(config),
...buildPlugins.pre,
dynamicImportVarsPlugin(config),
importGlobPlugin(config),
Expand Down
41 changes: 29 additions & 12 deletions packages/vite/src/node/plugins/workerImportMetaUrl.ts
Expand Up @@ -8,11 +8,12 @@ import type { Plugin } from '../plugin'
import {
cleanUrl,
injectQuery,
normalizePath,
parseRequest,
slash,
transformStableResult
} from '../utils'
import { getDepsOptimizer } from '../optimizer'
import type { ResolveFn } from '..'
import type { WorkerType } from './worker'
import { WORKER_FILE_ID, workerFileToUrl } from './worker'
import { fileToUrl } from './asset'
Expand Down Expand Up @@ -75,6 +76,7 @@ function getWorkerType(raw: string, clean: string, i: number): WorkerType {

export function workerImportMetaUrlPlugin(config: ResolvedConfig): Plugin {
const isBuild = config.command === 'build'
let workerResolver: ResolveFn

return {
name: 'vite:worker-import-meta-url',
Expand Down Expand Up @@ -116,22 +118,37 @@ export function workerImportMetaUrlPlugin(config: ResolvedConfig): Plugin {
cleanString,
index + allExp.length
)
const file = normalizePath(
path.resolve(path.dirname(id), rawUrl.slice(1, -1))
)
const url = rawUrl.slice(1, -1)
let file: string | undefined
if (url.startsWith('.')) {
file = path.resolve(path.dirname(id), url)
} else {
workerResolver ??= config.createResolver({
extensions: [],
tryIndex: false,
preferRelative: true
})
file = await workerResolver(url, id)
file ??= url.startsWith('/')
? slash(path.join(config.publicDir, url))
: slash(path.resolve(path.dirname(id), url))
}

let url: string
let builtUrl: string
if (isBuild) {
getDepsOptimizer(config, ssr)?.registerWorkersSource(id)
url = await workerFileToUrl(config, file, query)
builtUrl = await workerFileToUrl(config, file, query)
} else {
url = await fileToUrl(cleanUrl(file), config, this)
url = injectQuery(url, WORKER_FILE_ID)
url = injectQuery(url, `type=${workerType}`)
builtUrl = await fileToUrl(cleanUrl(file), config, this)
builtUrl = injectQuery(builtUrl, WORKER_FILE_ID)
builtUrl = injectQuery(builtUrl, `type=${workerType}`)
}
s.overwrite(urlIndex, urlIndex + exp.length, JSON.stringify(url), {
contentOnly: true
})
s.overwrite(
urlIndex,
urlIndex + exp.length,
`new URL(${JSON.stringify(builtUrl)}, self.location)`,
{ contentOnly: true }
)
}

if (s) {
Expand Down
10 changes: 10 additions & 0 deletions playground/assets/__tests__/assets.spec.ts
Expand Up @@ -281,6 +281,16 @@ test('new URL(..., import.meta.url)', async () => {
expect(await page.textContent('.import-meta-url')).toMatch(assetMatch)
})

test('new URL("@/...", import.meta.url)', async () => {
expect(await page.textContent('.import-meta-url-dep')).toMatch(assetMatch)
})

test('new URL("/...", import.meta.url)', async () => {
expect(await page.textContent('.import-meta-url-base-path')).toMatch(
iconMatch
)
})

test('new URL(`${dynamic}`, import.meta.url)', async () => {
expect(await page.textContent('.dynamic-import-meta-url-1')).toMatch(
isBuild ? 'data:image/png;base64' : '/foo/nested/icon.png'
Expand Down
18 changes: 18 additions & 0 deletions playground/assets/index.html
Expand Up @@ -182,6 +182,14 @@ <h2>new URL('...', import.meta.url)</h2>
<img class="import-meta-url-img" />
<code class="import-meta-url"></code>

<h2>new URL('@/...', import.meta.url)</h2>
<img class="import-meta-url-dep-img" />
<code class="import-meta-url-dep"></code>

<h2>new URL('/...', import.meta.url)</h2>
<img class="import-meta-url-base-path-img" />
<code class="import-meta-url-base-path"></code>

<h2>new URL('...', import.meta.url,) (with comma)</h2>
<img class="import-meta-url-img-comma" />
<code class="import-meta-url-comma"></code>
Expand Down Expand Up @@ -354,6 +362,16 @@ <h3>style in svg</h3>
text('.import-meta-url', metaUrl)
document.querySelector('.import-meta-url-img').src = metaUrl

const metaUrlDep = new URL('@/asset.png', import.meta.url)
text('.import-meta-url-dep', metaUrlDep)
document.querySelector('.import-meta-url-dep-img').src = metaUrlDep

// testing URLs for public assets served at the public base path
// equivalent to `new URL(`${import.meta.env.BASE_URL}/icon.png`, self.location)
const metaUrlBasePath = new URL('/icon.png', import.meta.url)
text('.import-meta-url-base-path', metaUrlBasePath)
document.querySelector('.import-meta-url-base-path-img').src = metaUrlBasePath

// prettier-ignore
const metaUrlWithComma = new URL('./nested/asset.png', import.meta.url,)
text('.import-meta-url-comma', metaUrlWithComma)
Expand Down
10 changes: 10 additions & 0 deletions playground/worker/__tests__/es/es-worker.spec.ts
Expand Up @@ -92,6 +92,16 @@ describe.runIf(isBuild)('build', () => {
})

test('module worker', async () => {
await untilUpdated(
() => page.textContent('.worker-import-meta-url'),
'A string',
true
)
await untilUpdated(
() => page.textContent('.worker-import-meta-url-resolve'),
'A string',
true
)
await untilUpdated(
() => page.textContent('.shared-worker-import-meta-url'),
'A string',
Expand Down
8 changes: 8 additions & 0 deletions playground/worker/__tests__/iife/iife-worker.spec.ts
Expand Up @@ -79,6 +79,14 @@ describe.runIf(isBuild)('build', () => {
})

test('module worker', async () => {
await untilUpdated(
() => page.textContent('.worker-import-meta-url'),
'A string'
)
await untilUpdated(
() => page.textContent('.worker-import-meta-url-resolve'),
'A string'
)
await untilUpdated(
() => page.textContent('.shared-worker-import-meta-url'),
'A string'
Expand Down
6 changes: 6 additions & 0 deletions playground/worker/index.html
Expand Up @@ -44,6 +44,12 @@ <h2 class="format-iife">format iife:</h2>
</p>
<code class="worker-import-meta-url"></code>

<p>
new Worker(new URL('@/url-worker', import.meta.url), { type: 'module' })
<span class="classname">.worker-import-meta-url-resolve</span>
</p>
<code class="worker-import-meta-url-resolve"></code>

<p>
new SharedWorker(new URL('./url-shared-worker.js', import.meta.url), { type:
'module' })
Expand Down
5 changes: 5 additions & 0 deletions playground/worker/vite.config-es.js
Expand Up @@ -4,6 +4,11 @@ const vite = require('vite')
module.exports = vite.defineConfig({
base: '/es/',
enforce: 'pre',
resolve: {
alias: {
'@': __dirname
}
},
worker: {
format: 'es',
plugins: [vueJsx()],
Expand Down
5 changes: 5 additions & 0 deletions playground/worker/vite.config-iife.js
Expand Up @@ -3,6 +3,11 @@ const vite = require('vite')

module.exports = vite.defineConfig({
base: '/iife/',
resolve: {
alias: {
'@': __dirname
}
},
worker: {
format: 'iife',
plugins: [
Expand Down
5 changes: 5 additions & 0 deletions playground/worker/vite.config-relative-base.js
Expand Up @@ -4,6 +4,11 @@ const vite = require('vite')

module.exports = vite.defineConfig({
base: './',
resolve: {
alias: {
'@': __dirname
}
},
worker: {
format: 'es',
plugins: [vueJsx()],
Expand Down
5 changes: 5 additions & 0 deletions playground/worker/vite.config-sourcemap.js
Expand Up @@ -10,6 +10,11 @@ module.exports = vite.defineConfig((sourcemap) => {
base: `/iife-${
typeof sourcemap === 'boolean' ? 'sourcemap' : 'sourcemap-' + sourcemap
}/`,
resolve: {
alias: {
'@': __dirname
}
},
worker: {
format: 'iife',
plugins: [vueJsx()],
Expand Down
9 changes: 9 additions & 0 deletions playground/worker/worker/main-module.js
Expand Up @@ -65,6 +65,15 @@ w.addEventListener('message', (ev) =>
text('.worker-import-meta-url', JSON.stringify(ev.data))
)

// url import worker with alias path
const wResolve = new Worker(
new URL('@/url-worker.js', import.meta.url),
/* @vite-ignore */ workerOptions
)
wResolve.addEventListener('message', (ev) =>
text('.worker-import-meta-url-resolve', JSON.stringify(ev.data))
)

const genWorkerName = () => 'module'
const w2 = new SharedWorker(
new URL('../url-shared-worker.js', import.meta.url),
Expand Down

0 comments on commit bafccf5

Please sign in to comment.