mirror of
https://github.com/vitejs/vite.git
synced 2024-11-21 22:59:10 +00:00
feat: import public non-asset URL (#13422)
This commit is contained in:
parent
ebb8e2914b
commit
3a98558f78
@ -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
|
||||
|
@ -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.`,
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -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` +
|
||||
|
@ -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', () => {
|
||||
|
@ -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'
|
||||
|
3
playground/assets/static/foo.json
Normal file
3
playground/assets/static/foo.json
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"foo": "bar"
|
||||
}
|
Loading…
Reference in New Issue
Block a user