首页
/ Vite 如何用 ?url 与 ?inline 显式控制资源的导入或内联?

Vite 如何用 ?url 与 ?inline 显式控制资源的导入或内联?

2026-09-08 16:31:44作者:平淮齐Percy

在 Vite 项目里导入静态资源时,默认行为是按文件大小自动决定“内联成 base64 data URL”还是“输出为带 hash 的独立文件”。当你导入一个不在内置资源类型列表里的文件(比如 Houdini Paint Worklet 脚本、自定义扩展名的文件),或者你希望某个资源无视 build.assetsInlineLimit 强制内联/强制不内联时,就需要用 ?url?inline?no-inline 这类后缀查询参数显式控制导入行为。本文基于 docs/guide/assets.md 及其引用的配置文档,说明这三种参数的用法和如何验证生效。

默认行为:先理解“自动内联”的边界

导入静态资源会返回服务时的 resolved public URL(引自 docs/guide/assets.md 的文档示例):

import 'vite/client'
import imgUrl from './img.png'
document.getElementById('hero-img').src = imgUrl

imgUrl 在开发时是 /src/img.png,在生产构建中会变成类似 /assets/img.2d8efhg.png 的带 hash 文件名。是否内联由 build.assetsInlineLimit 决定:

  • 类型:number | ((filePath: string, content: Buffer) => boolean | undefined),默认 4096(4 KiB);
  • 小于该阈值的资源被内联为 base64 URL,设为 0 则完全禁用内联;
  • 传入回调函数时,返回布尔值可针对单个文件 opt-in 或 opt-out,不返回值则走默认逻辑;
  • 指定了 build.libbuild.assetsInlineLimit 会被忽略,资源总是被内联,与文件大小和 Git LFS 占位符状态无关。

两个直接影响“是否被当作资源处理”的条件:

  1. 常见的图片、媒体、字体类型会被自动识别为资源,内置列表可用 assetsInclude 选项扩展,例如:
export default defineConfig({
  assetsInclude: ['**/*.gltf'],
})

命中 assetsInclude 的文件从 JS 中导入时会返回 resolved URL 字符串。

  1. 被引用的资源会进入构建资源图,获得 hash 文件名,并可以被插件处理。例外是 Git LFS 占位符:因为不包含真实文件内容,会自动被排除在内联之外;想让它们被内联,需要在构建前通过 Git LFS 下载真实内容。

用 ?url 显式导入为 URL

不在内置列表、也没配 assetsInclude 的文件,可以用 ?url 后缀显式作为 URL 导入。文档给出的典型场景是导入 Houdini Paint Worklet(引自 docs/guide/assets.md):

import 'vite/client'
import workletURL from 'extra-scalloped-border/worklet.js?url'
CSS.paintWorklet.addModule(workletURL)

docs/guide/features.md 中也展示了同样的用法,并标注 ?url 导入的资源“automatically inlined depending on the file size”(仍按文件大小自动内联),即 ?url 本身不改变内联策略:

import 'vite/client'
// Explicitly load assets as URL (automatically inlined depending on the file size)
import assetAsURL from './asset.js?url'

另一个文档给出的组合场景是 WebAssembly:用 ?url 拿到 wasm 文件的 URL 后自行 fetchinstantiateStreaming

import 'vite/client'
import wasmUrl from 'foo.wasm?url'

const main = async () => {
  const responsePromise = fetch(wasmUrl)
  const { module, instance } =
    await WebAssembly.instantiateStreaming(responsePromise)
  /* ... */
}

用 ?inline 与 ?no-inline 显式控制是否内联

?inline?no-inline 分别强制内联和强制不内联,这是文档为“绕过 4 KiB 阈值”提供的显式开关(引自 docs/guide/assets.md):

import 'vite/client'
import imgUrl1 from './img.svg?no-inline' // 即使小于 assetsInlineLimit 也输出为独立文件
import imgUrl2 from './img.png?inline'    // 即使大于 assetsInlineLimit 也内联为 data URL

packages/vite/client.d.ts 中的类型声明还定义了组合形式 *?url&inline*?url&no-inline,默认导出类型同样是 string,即“URL 导入 + 显式内联策略”可以叠加:

declare module '*?url&inline' {
  const src: string
  export default src
}

declare module '*?url&no-inline' {
  const src: string
  export default src
}

注意 TypeScript 默认不识别静态资源导入,以上写法都需要把 vite/client 纳入类型。docs/guide/features.md 给出两种方式:在 tsconfig.jsoncompilerOptions.types 中加入 "vite/client",或者在声明文件中写 /// <reference types="vite/client" />

?inline 在 CSS 导入上是另一个含义

同一个 ?inline 后缀作用于 CSS 文件时,含义变为“关闭自动注入”:处理后的 CSS 字符串照常作为模块默认导出返回,但不会注入到页面(引自 docs/guide/features.md):

import 'vite/client'
import './foo.css' // will be injected into the page
import otherStyles from './bar.css?inline' // will not be injected

该文档同时提示:自 Vite 5 起,CSS 文件的默认导入和命名导入(如 import style from './foo.css')已被移除,需要用 ?inline 查询替代。也就是说,静态资源上的 ?inline 与 CSS 上的 ?inline 是两套语义,按导入对象区分即可。

如何验证参数生效

文档本身给出的可核对判据(均来自文档正文与仓库内测试 playground/assets/tests/assets.spec.ts):

  • ?url 导入:开发时得到基于项目根的路径(如 /foo/bar/foo.js);生产构建时,若文件小于内联阈值,会得到 data:text/javascript;base64,... 形式的 data URL,否则得到带 hash 的 assets/ 路径。
  • ?inline 导入:返回值以 data: 前缀开头,例如 PNG 会得到 data:image/png;base64,... 开头、未知扩展名会得到 data:application/octet-stream; 开头的字符串——这是文档测试断言的匹配模式,可直接作为自己页面的验证依据。
  • ?no-inline 导入:生产构建时返回值是带 hash 的独立资源路径(形如 /assets/fragment-xxxxxxxx.svg),不会变成 data URL。

实操上最短的验证路径是:在项目里加一行 console.log(yourImport),分别跑 vite(开发,见 docs/guide/cli.md)与 vite build,对照上面三组形态判断参数是否按预期生效。若返回值既不是 data: 前缀也不是可访问路径,先确认文件是否落在 root 内、扩展名是否命中内置列表或 assetsInclude

限制与注意事项

  • ?url 不控制内联:它只解决“非资源类型无法被识别”的问题,内联与否仍由文件大小阈值(或显式的 ?inline/?no-inline)决定。
  • 库模式下内联策略失效:指定 build.libbuild.assetsInlineLimit 被忽略,资源总是内联(见 docs/config/build-options.md 的 Note)。
  • Git LFS 占位符永远不被内联,除非先通过 Git LFS 拉取真实内容。
  • build.assetsInlineLimit 回调可精控:如果你需要按文件路径而非逐个导入语句写 ?inline,在配置里传回调函数返回布尔值即可,两种方式可混用。

参考文档

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.14 K
2.75 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
857
1.35 K
docsdocs
暂无描述
Markdown
898
5.82 K
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
921
1.84 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.8 K
1.02 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
531
596
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
1.02 K
519
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.36 K
1.46 K
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
548
391