diff --git a/docs/config/build-options.md b/docs/config/build-options.md index b2d9bf629a02b9..291135045560ce 100644 --- a/docs/config/build-options.md +++ b/docs/config/build-options.md @@ -53,8 +53,10 @@ Specify the directory to nest generated assets under (relative to `build.outDir` Imported or referenced assets that are smaller than this threshold will be inlined as base64 URLs to avoid extra http requests. Set to `0` to disable inlining altogether. +Git LFS placeholders are automatically excluded from inlining because they do not contain the content of the file they represent. + ::: tip Note -If you specify `build.lib`, `build.assetsInlineLimit` will be ignored and assets will always be inlined, regardless of file size. +If you specify `build.lib`, `build.assetsInlineLimit` will be ignored and assets will always be inlined, regardless of file size or being a Git LFS placeholder. ::: ## build.cssCodeSplit diff --git a/docs/guide/assets.md b/docs/guide/assets.md index a8fdf5e208249a..c0dba49a604f80 100644 --- a/docs/guide/assets.md +++ b/docs/guide/assets.md @@ -26,6 +26,8 @@ The behavior is similar to webpack's `file-loader`. The difference is that the i - Assets smaller in bytes than the [`assetsInlineLimit` option](/config/build-options.md#build-assetsinlinelimit) will be inlined as base64 data URLs. +- Git LFS placeholders are automatically excluded from inlining because they do not contain the content of the file they represent. To get inlining, make sure to download the file contents via Git LFS before building. + ### Explicit URL Imports Assets that are not included in the internal list or in `assetsInclude`, can be explicitly imported as a URL using the `?url` suffix. This is useful, for example, to import [Houdini Paint Worklets](https://houdini.how/usage). diff --git a/packages/vite/src/node/plugins/asset.ts b/packages/vite/src/node/plugins/asset.ts index c018ba56427fce..94c34a40f8d22e 100644 --- a/packages/vite/src/node/plugins/asset.ts +++ b/packages/vite/src/node/plugins/asset.ts @@ -1,6 +1,7 @@ import path from 'node:path' import { parse as parseUrl } from 'node:url' import fs, { promises as fsp } from 'node:fs' +import { Buffer } from 'node:buffer' import * as mrmime from 'mrmime' import type { NormalizedOutputOptions, @@ -10,6 +11,7 @@ import type { RenderedChunk } from 'rollup' import MagicString from 'magic-string' +import colors from 'picocolors' import { toOutputFilePathInString } from '../build' import type { Plugin } from '../plugin' import type { ResolvedConfig } from '../config' @@ -398,6 +400,13 @@ export function publicFileToBuiltUrl( return `__VITE_PUBLIC_ASSET__${hash}__` } +const GIT_LFS_PREFIX = Buffer.from('version https://git-lfs.github.com') +function isGitLfsPlaceholder(content: Buffer): boolean { + if (content.length < GIT_LFS_PREFIX.length) return false + // 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 +} + /** * Register an asset to be emitted as part of the bundle (if necessary) * and returns the resolved public URL @@ -426,8 +435,15 @@ async function fileToBuiltUrl( config.build.lib || (!file.endsWith('.svg') && !file.endsWith('.html') && - content.length < Number(config.build.assetsInlineLimit)) + content.length < Number(config.build.assetsInlineLimit) && + !isGitLfsPlaceholder(content)) ) { + if (config.build.lib && isGitLfsPlaceholder(content)) { + config.logger.warn( + colors.yellow(`Inlined file ${id} was not downloaded via Git LFS`) + ) + } + const mimeType = mrmime.lookup(file) ?? 'application/octet-stream' // base64 inlined as a string url = `data:${mimeType};base64,${content.toString('base64')}`