Skip to content

Commit

Permalink
feat(build)!: inline SVGs
Browse files Browse the repository at this point in the history
  • Loading branch information
ArnaudBarre committed Oct 16, 2023
1 parent 4dcf9c4 commit 1db00cd
Show file tree
Hide file tree
Showing 8 changed files with 41 additions and 5 deletions.
33 changes: 29 additions & 4 deletions packages/vite/src/node/plugins/asset.ts
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,12 @@ function isGitLfsPlaceholder(content: Buffer): boolean {
// Check whether the content begins with the characteristic string of Git LFS placeholders
return GIT_LFS_PREFIX.compare(content, 0, GIT_LFS_PREFIX.length) === 0
}
// spaces in not supported in srcset
const svgDataURISupportedHexCode: Record<string, string> = {
'%3D': '=',
'%3A': ':',
'%2F': '/',
}

/**
* Register an asset to be emitted as part of the bundle (if necessary)
Expand Down Expand Up @@ -352,7 +358,8 @@ async function fileToBuiltUrl(
let url: string
if (
config.build.lib ||
(!file.endsWith('.svg') &&
// Don't inline SVG with fragments, as they are meant to be reused
(!(file.endsWith('.svg') && id.includes('#')) &&
!file.endsWith('.html') &&
content.length < Number(config.build.assetsInlineLimit) &&
!isGitLfsPlaceholder(content))
Expand All @@ -363,9 +370,27 @@ async function fileToBuiltUrl(
)
}

const mimeType = mrmime.lookup(file) ?? 'application/octet-stream'
// base64 inlined as a string
url = `data:${mimeType};base64,${content.toString('base64')}`
if (file.endsWith('.svg')) {
let dataUri = content.toString()
// If the SVG contains some text any transformation is unsafe, and given that double quotes would then
// need to be escaped, the gain to use a data URI would be ridiculous if not negative
if (dataUri.includes('<text')) {
url = `data:image/svg+xml;base64,${content.toString('base64')}`
} else {
// Simplified version of https:/tigt/mini-svg-data-uri without colors minification
// This kind of minification should be done ahead of time or with a plugin with other optimizations (using svgo for example)
dataUri = dataUri.trim().replace(/\s+/g, ' ').replaceAll('"', "'")
dataUri = encodeURIComponent(dataUri).replace(
/%[\dA-F]{2}/g,
(match) => svgDataURISupportedHexCode[match] || match.toLowerCase(),
)
url = 'data:image/svg+xml,' + dataUri
}
} else {
const mimeType = mrmime.lookup(file) ?? 'application/octet-stream'
// base64 inlined as a string
url = `data:${mimeType};base64,${content.toString('base64')}`
}
} else {
// emit as asset
const { search, hash } = parseUrl(id)
Expand Down
7 changes: 6 additions & 1 deletion playground/assets/__tests__/assets.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,12 @@ describe('svg fragments', () => {

test('from js import', async () => {
const img = await page.$('.svg-frag-import')
expect(await img.getAttribute('src')).toMatch(/svg#icon-heart-view$/)
expect(await img.getAttribute('src')).toMatch(
isBuild
? // Assert trimmed (data URI starts with < and ends with >)
/^data:image\/svg\+xml,%3c.*%3e#icon-heart-view$/
: /svg#icon-heart-view$/,
)
})
})

Expand Down
1 change: 1 addition & 0 deletions playground/legacy/vite.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export default defineConfig({
cssCodeSplit: false,
manifest: true,
sourcemap: true,
assetsInlineLimit: 100, // keep SVG as assets URL
rollupOptions: {
input: {
index: path.resolve(__dirname, 'index.html'),
Expand Down
1 change: 1 addition & 0 deletions playground/worker/vite.config-es.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export default defineConfig({
},
build: {
outDir: 'dist/es',
assetsInlineLimit: 100, // keep SVG as assets URL
rollupOptions: {
output: {
assetFileNames: 'assets/[name].[ext]',
Expand Down
1 change: 1 addition & 0 deletions playground/worker/vite.config-iife.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ export default defineConfig({
},
build: {
outDir: 'dist/iife',
assetsInlineLimit: 100, // keep SVG as assets URL
manifest: true,
rollupOptions: {
output: {
Expand Down
1 change: 1 addition & 0 deletions playground/worker/vite.config-relative-base-iife.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export default defineConfig({
},
build: {
outDir: 'dist/relative-base-iife',
assetsInlineLimit: 100, // keep SVG as assets URL
rollupOptions: {
output: {
assetFileNames: 'other-assets/[name]-[hash].[ext]',
Expand Down
1 change: 1 addition & 0 deletions playground/worker/vite.config-relative-base.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export default defineConfig({
},
build: {
outDir: 'dist/relative-base',
assetsInlineLimit: 100, // keep SVG as assets URL
rollupOptions: {
output: {
assetFileNames: 'other-assets/[name]-[hash].[ext]',
Expand Down
1 change: 1 addition & 0 deletions playground/worker/worker-sourcemap-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ export default (sourcemap) => {
},
build: {
outDir: `dist/iife-${typeName}/`,
assetsInlineLimit: 100, // keep SVG as assets URL
sourcemap: sourcemap,
rollupOptions: {
output: {
Expand Down

0 comments on commit 1db00cd

Please sign in to comment.