diff --git a/packages/playground/data-uri/__tests__/data-uri.spec.ts b/packages/playground/data-uri/__tests__/data-uri.spec.ts new file mode 100644 index 00000000000000..e1d488c931e7c1 --- /dev/null +++ b/packages/playground/data-uri/__tests__/data-uri.spec.ts @@ -0,0 +1,16 @@ +import { isBuild, findAssetFile } from '../../testUtils' + +test('plain', async () => { + expect(await page.textContent('.plain')).toBe('hi') +}) + +test('base64', async () => { + expect(await page.textContent('.base64')).toBe('hi') +}) + +if (isBuild) { + test('should compile away the import for build', async () => { + const file = findAssetFile('index') + expect(file).not.toMatch('import') + }) +} diff --git a/packages/playground/data-uri/index.html b/packages/playground/data-uri/index.html new file mode 100644 index 00000000000000..80e0fc6fcc6c17 --- /dev/null +++ b/packages/playground/data-uri/index.html @@ -0,0 +1,10 @@ +
+ + + diff --git a/packages/playground/data-uri/package.json b/packages/playground/data-uri/package.json new file mode 100644 index 00000000000000..6197cbb29e7589 --- /dev/null +++ b/packages/playground/data-uri/package.json @@ -0,0 +1,10 @@ +{ + "name": "test-data-uri", + "private": true, + "version": "0.0.0", + "scripts": { + "dev": "vite", + "build": "vite build", + "debug": "node --inspect-brk ../../vite/bin/vite" + } +} \ No newline at end of file diff --git a/packages/vite/src/node/plugins/dataUri.ts b/packages/vite/src/node/plugins/dataUri.ts new file mode 100644 index 00000000000000..a4b1df82df5a65 --- /dev/null +++ b/packages/vite/src/node/plugins/dataUri.ts @@ -0,0 +1,56 @@ +// This is based on @rollup/plugin-data-uri +// MIT Licensed https://github.com/rollup/plugins/blob/master/LICENSE +// ref https://github.com/vitejs/vite/issues/1428#issuecomment-757033808 +import { Plugin } from '../plugin' +import { URL } from 'url' + +const dataUriRE = /^([^/]+\/[^;,]+)(;base64)?,([\s\S]*)$/ + +const dataUriPrefix = `/@data-uri/` + +export function dataURIPlugin(): Plugin { + const resolved: { + [key: string]: string + } = {} + + return { + name: 'vite:data-uri', + resolveId(id) { + if (!dataUriRE.test(id)) { + return null + } + + const uri = new URL(id) + if (uri.protocol !== 'data:') { + return null + } + + const match = uri.pathname.match(dataUriRE) + if (!match) { + return null + } + + const [, mime, format, data] = match + if (mime !== 'text/javascript') { + throw new Error( + `data URI with non-JavaScript mime type is not supported.` + ) + } + + // decode data + const base64 = format && /base64/i.test(format.substring(1)) + const content = base64 + ? Buffer.from(data, 'base64').toString('utf-8') + : data + resolved[id] = content + return dataUriPrefix + id + }, + + load(id) { + if (id.startsWith(dataUriPrefix)) { + id = id.slice(dataUriPrefix.length) + return resolved[id] || null + } + } + } +} diff --git a/packages/vite/src/node/plugins/index.ts b/packages/vite/src/node/plugins/index.ts index 4281ede5a69cb4..12c0aeb6d095af 100644 --- a/packages/vite/src/node/plugins/index.ts +++ b/packages/vite/src/node/plugins/index.ts @@ -12,6 +12,7 @@ import { htmlPlugin } from './html' import { wasmPlugin } from './wasm' import { webWorkerPlugin } from './worker' import { dynamicImportPolyfillPlugin } from './dynamicImportPolyfill' +import { dataURIPlugin } from './dataUri' export async function resolvePlugins( config: ResolvedConfig, @@ -44,6 +45,7 @@ export async function resolvePlugins( preferConst: true, namedExports: true }), + isBuild ? dataURIPlugin() : null, wasmPlugin(config), webWorkerPlugin(config), assetPlugin(config), diff --git a/packages/vite/src/node/plugins/resolve.ts b/packages/vite/src/node/plugins/resolve.ts index 6ea302595907d9..6bbebfd9c658f1 100644 --- a/packages/vite/src/node/plugins/resolve.ts +++ b/packages/vite/src/node/plugins/resolve.ts @@ -8,12 +8,12 @@ import { createDebugger, deepImportRE, injectQuery, - isDataUrl, isExternalUrl, isObject, normalizePath, fsPathFromId, - resolveFrom + resolveFrom, + isDataUrl } from '../utils' import { ResolvedConfig, ViteDevServer } from '..' import slash from 'slash' @@ -131,13 +131,19 @@ export function resolvePlugin({ } // external - if (isExternalUrl(id) || isDataUrl(id)) { + if (isExternalUrl(id)) { return { id, external: true } } + // data uri: pass through (this only happens during build and will be + // handled by dedicated plugin) + if (isDataUrl(id)) { + return null + } + // bare package imports, perform node resolve if (bareImportRE.test(id)) { // externalize node built-ins only when building for ssr