feat: import public non-asset URL (#13422)

This commit is contained in:
翠 / green 2023-06-09 21:09:21 +09:00 committed by GitHub
parent ebb8e2914b
commit 3a98558f78
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 57 additions and 15 deletions

View File

@ -29,7 +29,7 @@ import { FS_PREFIX } from '../constants'
export const assetUrlRE = /__VITE_ASSET__([a-z\d]+)__(?:\$_(.*?)__)?/g
const rawRE = /(?:\?|&)raw(?:&|$)/
const urlRE = /(\?|&)url(?:&|$)/
export const urlRE = /(\?|&)url(?:&|$)/
const jsSourceMapRE = /\.[cm]?js\.map$/
const unnededFinalQueryCharRE = /[?&]$/
@ -147,7 +147,7 @@ export function assetPlugin(config: ResolvedConfig): Plugin {
},
resolveId(id) {
if (!config.assetsInclude(cleanUrl(id))) {
if (!config.assetsInclude(cleanUrl(id)) && !urlRE.test(id)) {
return
}
// imports to absolute urls pointing to files in /public

View File

@ -55,7 +55,7 @@ import {
} from '../ssr/ssrExternal'
import { getDepsOptimizer, optimizedDepNeedsInterop } from '../optimizer'
import { ERR_CLOSED_SERVER } from '../server/pluginContainer'
import { checkPublicFile } from './asset'
import { checkPublicFile, urlRE } from './asset'
import {
ERR_OUTDATED_OPTIMIZED_DEP,
throwOutdatedRequest,
@ -507,14 +507,20 @@ export function importAnalysisPlugin(config: ResolvedConfig): Plugin {
// warn imports to non-asset /public files
if (
specifier[0] === '/' &&
!config.assetsInclude(cleanUrl(specifier)) &&
!specifier.endsWith('.json') &&
!(
config.assetsInclude(cleanUrl(specifier)) ||
urlRE.test(specifier)
) &&
checkPublicFile(specifier, config)
) {
throw new Error(
`Cannot import non-asset file ${specifier} which is inside /public.` +
`Cannot import non-asset file ${specifier} which is inside /public. ` +
`JS/CSS files inside /public are copied as-is on build and ` +
`can only be referenced via <script src> or <link href> in html.`,
`can only be referenced via <script src> or <link href> in html. ` +
`If you want to get the URL of that file, use ${injectQuery(
specifier,
'url',
)} instead.`,
)
}

View File

@ -37,6 +37,7 @@ import {
} from '../../plugins/optimizedDeps'
import { ERR_CLOSED_SERVER } from '../pluginContainer'
import { getDepsOptimizer } from '../../optimizer'
import { urlRE } from '../../plugins/asset'
const debugCache = createDebugger('vite:cache')
@ -136,14 +137,22 @@ export function transformMiddleware(
if (isImportRequest(url)) {
const rawUrl = removeImportQuery(url)
warning =
'Assets in public cannot be imported from JavaScript.\n' +
`Instead of ${colors.cyan(
rawUrl,
)}, put the file in the src directory, and use ${colors.cyan(
rawUrl.replace(publicPath, '/src/'),
)} instead.`
if (urlRE.test(url)) {
warning =
`Assets in the public directory are served at the root path.\n` +
`Instead of ${colors.cyan(rawUrl)}, use ${colors.cyan(
rawUrl.replace(publicPath, '/'),
)}.`
} else {
warning =
'Assets in public directory cannot be imported from JavaScript.\n' +
`If you intend to import that asset, put the file in the src directory, and use ${colors.cyan(
rawUrl.replace(publicPath, '/src/'),
)} instead of ${colors.cyan(rawUrl)}.\n` +
`If you intend to use the URL of that asset, use ${colors.cyan(
injectQuery(rawUrl.replace(publicPath, '/'), 'url'),
)}.`
}
} else {
warning =
`files in the public directory are served at the root path.\n` +

View File

@ -100,6 +100,19 @@ describe('asset imports from js', () => {
test('from /public', async () => {
expect(await page.textContent('.public-import')).toMatch(iconMatch)
})
test('from /public (json)', async () => {
expect(await page.textContent('.public-json-import')).toMatch(
'/foo/foo.json',
)
expect(await page.textContent('.public-json-import-content'))
.toMatchInlineSnapshot(`
"{
\\"foo\\": \\"bar\\"
}
"
`)
})
})
describe('css url() references', () => {

View File

@ -26,6 +26,10 @@
<li>Relative: <code class="asset-import-relative"></code></li>
<li>Absolute: <code class="asset-import-absolute"></code></li>
<li>From publicDir: <code class="public-import"></code></li>
<li>
From publicDir (json): <code class="public-json-import"></code> Content:
<code class="public-json-import-content"></code>
</li>
</ul>
<h2>CSS url references</h2>
@ -378,6 +382,13 @@
import publicUrl from '/icon.png'
text('.public-import', publicUrl)
import publicJsonUrl from '/foo.json?url'
text('.public-json-import', publicJsonUrl)
;(async () => {
const res = await fetch(publicJsonUrl)
text('.public-json-import-content', await res.text())
})()
import svgFrag from './nested/fragment.svg'
text('.svg-frag-import-path', svgFrag)
document.querySelector('.svg-frag-import').src = svgFrag + '#icon-heart-view'

View File

@ -0,0 +1,3 @@
{
"foo": "bar"
}