资源管理

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

Geprüfte Übersetzung ·0 % geprüft

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

  • public/ 目录中的内容会原样从服务器根目录提供。
  • app/assets/ 目录按照惯例包含你希望构建工具(Vite 或 webpack)处理的所有资源。

Public 目录

public/ 目录用作静态资源的公共服务器,可通过应用程序中定义的 URL 公开访问。

你可以在应用程序代码中,或在浏览器中通过根 URL / 获取 public/ 目录中的文件。

示例

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

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

Assets 目录

Nuxt 使用 Vite(默认)或 webpack 构建和打包你的应用。这些构建工具的主要功能是处理 JavaScript 文件,但它们可以通过 插件(针对 Vite)或 加载器(针对 webpack)扩展来处理其它类型的资源,比如样式表、字体或 SVG。这一步会转换原始文件,主要是为了性能或缓存目的(例如样式表压缩或浏览器缓存失效)。

按照惯例,Nuxt 使用 app/assets/ 目录存储这些文件,但此目录不会被自动扫描,你也可以使用任何其他名称。

在应用程序代码中,你可以使用 ~/assets/ 路径引用位于 app/assets/ 目录中的文件。

示例

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

app/app.vue
<template>
  <img
    src="~/assets/img/nuxt.png"
    alt="发现 Nuxt"
  >
</template>
Nuxt 不会通过 /assets/my-file.png 这样的静态 URL 提供 app/assets/ 目录中的文件。如果你需要静态 URL,请使用 public/ 目录。

静态 vs. 动态 src

当模板中的 src 是静态字符串字面量时,构建工具会将其重写为一个运行时辅助函数,以解析最终 URL。像 /img/nuxt.png 这样的公共路径会被包装,以便在页面渲染时应用你的 app.baseURL;像 ~/assets/img/nuxt.png 这样的打包路径还会变成一个导入,并解析为带哈希的输出文件。

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

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

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

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

因此,像 /img/${name}.png 这样在运行时构建的公共路径不会添加 app.baseURL 前缀。如果你的应用部署在源站根目录以下,请使用 useRuntimeConfig().app.baseURL 为其添加前缀(例如通过 joinURL)。

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

公共资源

如果文件不需要经过处理或添加哈希,请将它们放入 public/ 目录,并通过 URL 引用:

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 的默认构建器。

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

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 可以在构建时找到这两个文件,同时在运行时只加载选中的模块。

当很多文件共享同一个目录和扩展名时,使用 变量动态导入,而不是逐个列出每个文件:

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

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

对于更广泛的模式,或者用于显式映射可用文件,请使用 import.meta.glob:

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:

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

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

在将懒加载导入的 URL 用于服务端渲染的标记之前,请先等待其加载完成。Vite 的 new URL(..., import.meta.url) 模式 不适用于 SSR。