---
title: "资源管理"
description: "Nuxt 为你的资源提供两种选项。"
canonical_url: "https://nuxt.zhcndoc.com/docs/4.x/getting-started/assets"
---
# 资源管理

> Nuxt 为你的资源提供两种选项。

Nuxt 使用两个目录来处理诸如样式表、字体或图像之类的资源。

- [`public/`](https://nuxt.zhcndoc.com/docs/4.x/directory-structure/public) 目录中的内容会原样从服务器根目录提供。
- [`app/assets/`](https://nuxt.zhcndoc.com/docs/4.x/directory-structure/app/assets) 目录按照惯例包含你希望构建工具（Vite 或 webpack）处理的所有资源。

## Public 目录

[`public/`](https://nuxt.zhcndoc.com/docs/4.x/directory-structure/public) 目录用作静态资源的公共服务器，可通过应用程序中定义的 URL 公开访问。

你可以在应用程序代码中，或在浏览器中通过根 URL `/` 获取 [`public/`](https://nuxt.zhcndoc.com/docs/4.x/directory-structure/public) 目录中的文件。

### 示例

例如，引用 `public/img/` 目录中的图像文件，该文件可通过静态 URL `/img/nuxt.png` 访问：

```vue [app/app.vue]
<template>
  <img
    src="/img/nuxt.png"
    alt="发现 Nuxt"
  >
</template>
```

## Assets 目录

Nuxt 使用 [Vite](https://vite.dev/guide/assets)（默认）或 [webpack](https://webpack.js.org/guides/asset-management/) 构建和打包你的应用。这些构建工具的主要功能是处理 JavaScript 文件，但它们可以通过 [插件](https://vite.dev/plugins/)（针对 Vite）或 [加载器](https://webpack.js.org/loaders/)（针对 webpack）扩展来处理其它类型的资源，比如样式表、字体或 SVG。这一步会转换原始文件，主要是为了性能或缓存目的（例如样式表压缩或浏览器缓存失效）。

按照惯例，Nuxt 使用 [`app/assets/`](https://nuxt.zhcndoc.com/docs/4.x/directory-structure/app/assets) 目录存储这些文件，但此目录不会被自动扫描，你也可以使用任何其他名称。

在应用程序代码中，你可以使用 `~/assets/` 路径引用位于 [`app/assets/`](https://nuxt.zhcndoc.com/docs/4.x/directory-structure/app/assets) 目录中的文件。

### 示例

例如，引用一个图像文件，如果构建工具配置了处理该文件扩展名，则此文件将被处理：

```vue [app/app.vue]
<template>
  <img
    src="~/assets/img/nuxt.png"
    alt="发现 Nuxt"
  >
</template>
```

<note>

Nuxt 不会通过 `/assets/my-file.png` 这样的静态 URL 提供 [`app/assets/`](https://nuxt.zhcndoc.com/docs/4.x/directory-structure/app/assets) 目录中的文件。如果你需要静态 URL，请使用 [`public/`](https://nuxt.zhcndoc.com/docs/4.x/getting-started/assets#public-directory) 目录。

</note>

### 静态 vs. 动态 `src`

当模板中的 `src` 是静态字符串字面量时，构建工具会将其重写为一个运行时辅助函数，用于解析最终 URL。像 `/img/nuxt.png` 这样的公共路径会被包装，以便在页面渲染时应用 [`app.baseURL`](https://nuxt.zhcndoc.com/docs/4.x/api/nuxt-config#baseurl)；而像 `~/assets/img/nuxt.png` 这样的打包路径还会变成一个导入，并解析为带哈希的输出文件。

```vue
<template>
  <!-- 静态路径会被重写：app.baseURL 会在运行时应用，打包文件会带哈希。 -->
  <img src="/img/nuxt.png">
  <img src="~/assets/img/nuxt.png">
</template>
```

由于 `app.baseURL` 是在运行时应用的，即使基础 URL 只在部署时才知道（例如通过 `NUXT_APP_BASE_URL` 设置），静态公共路径也能正常工作，而且无论文件是否经过构建处理都可以使用。这种解析只会发生在构建工具能够看到的字面量路径上。

一个值在运行时拼接出来的绑定 `:src` 对构建工具来说是不可见的，因此不会发生这些重写。该字符串会原样使用：

```vue
<template>
  <!-- 这不会生效：路径是在运行时拼接的，所以 Vite 从未将其视为导入。 -->
  <img :src="`~/assets/img/${name}.png`">
</template>
```

因此，像 `/img/${name}.png` 这样在运行时构建的公共路径**不会**加上 [`app.baseURL`](https://nuxt.zhcndoc.com/docs/4.x/api/nuxt-config#baseurl) 前缀。如果你的应用部署在源站根目录以下，请使用 [`useRuntimeConfig().app.baseURL`](https://nuxt.zhcndoc.com/docs/4.x/api/composables/use-runtime-config) 为其添加前缀（例如通过 [`joinURL`](https://github.com/unjs/ufo#joinurl)）。

下面的各节将介绍当路径只在运行时才知道时，如何处理每种情况。

#### 公共资源

如果文件不需要经过处理或添加哈希，请将它们放入 [`public/`](https://nuxt.zhcndoc.com/docs/4.x/directory-structure/public) 目录，并通过 URL 引用：

```vue [app/app.vue]
<script setup lang="ts">
const props = defineProps<{
  name: string
}>()

const imageUrl = computed(() => `/img/${props.name}.png`)
</script>

<template>
  <img
    :src="imageUrl"
    :alt="props.name"
  >
</template>
```

`public/` 中的文件会保留原始文件名。

#### 使用 Vite 的打包资源

下面的方法专用于 Vite，也就是 Nuxt 的默认构建器。

当可能的文件是已知的时，请显式列出它们的导入：

```vue [app/app.vue]
<script setup lang="ts">
const props = defineProps<{
  theme: 'light' | 'dark'
}>()

const logos = {
  light: () => import('./assets/img/logo-light.png?url'),
  dark: () => import('./assets/img/logo-dark.png?url'),
}

const logoUrl = (await logos[props.theme]()).default
</script>

<template>
  <img
    :src="logoUrl"
    alt="Nuxt"
  >
</template>
```

每个导入都使用字面量路径，因此 Vite 可以在构建时找到这两个文件，同时在运行时只加载选中的模块。

当很多文件共享同一个目录和扩展名时，使用 [变量动态导入](https://vite.dev/guide/features.html#dynamic-import)，而不是逐个列出每个文件：

```ts
async function getImageUrl (name: string) {
  const image = await import(`./assets/img/${name}.png?url`)
  return image.default
}
```

在这个示例中，只有文件名可以是动态的。在导入中保留目录和扩展名，可以让 Vite 在构建时找到可能的文件。

对于更广泛的模式，或者用于显式映射可用文件，请使用 [`import.meta.glob`](https://vite.dev/guide/features.html#glob-import)：

```ts
const images = import.meta.glob<string>('./assets/img/*.{png,jpg,svg}', {
  query: '?url',
  import: 'default',
})

async function getImageUrl (name: string) {
  const load = images[`./assets/img/${name}.png`]

  if (!load) {
    throw new Error(`Unknown image: ${name}`)
  }

  return await load()
}
```

Glob 导入默认是懒加载的。如果 URL 必须同步可用，请添加 `eager: true`：

```ts
const images = import.meta.glob<string>('./assets/img/*.{png,jpg,svg}', {
  query: '?url',
  import: 'default',
  eager: true,
})
```

每个匹配到的资源仍然会包含在构建输出中。懒加载导入会按需加载每个匹配项，而急切加载的 glob 会预先加载所有匹配项，可能会增加初始 JavaScript 体积，或将小型资源内联。

<warning>

在将懒加载导入的 URL 用于服务端渲染的标记之前，请先等待其加载完成。Vite 的 [`new URL(..., import.meta.url)` 模式](https://vite.dev/guide/assets.html#new-url-url-import-meta-url) 不适用于 SSR。

</warning>


## Sitemap

See the full [sitemap](https://nuxt.zhcndoc.com/sitemap.md) for all pages.
