理解静态资源服务

Nuxt 使用 vue-loaderfile-loaderurl-loader 这些 webpack 加载器来处理你应用程序中的静态资源。首先,Nuxt 会使用 vue-loader 处理 <template><style> 块,并结合 css-loadervue-template-compiler 将这些块中的元素(如 <img src="…​">background-image: URL(…​)CSS @import)编译成模块依赖。看下面的例子:

// pages/index.vue
<template>
  <img src="~/assets/sample-1.jpg">
</template>

<style>
.container {
  background-image: url("~assets/sample-2.jpg");
}
</style>

上面的 <template><style> 块中的图片元素和静态资源将被编译并转换为以下代码和模块依赖:

createElement('img', { attrs: { src: require('~/assets/sample-1.jpg') }})
require('~/assets/sample-2.jpg')

请注意,从 Nuxt 2.0 开始,~/ 别名在你的样式中可能无法正确解析,所以请使用 ~assets@/ 别名代替。

在完成上述编译和转换后,Nuxt 接下来会使用 file-loaderimport/require 的模块依赖解析为一个 URL,并将这些静态资源发出(复制粘贴)到输出目录中;或者,如果资源小于 1 KB,则使用 url-loader 将其转换为 Base64 URI。但是,如果资源大于 1 KB 的阈值,它将回退到 file-loader。这意味着任何小于 1 KB 的文件都将通过 url-loader 内联为 Base64 数据 URL,如下所示:

<img src="data:image/png;base64,iVBO...">

这可以让你更好地控制应用程序向服务器发出的 HTTP 请求数量。内联资源可以减少 HTTP 请求,而任何大于 1 KB 的文件都将被复制粘贴到输出目标,并使用版本哈希进行命名,以实现更好的缓存。例如,前面 <template><style> 块中的图像将按如下方式发出(通过 npm run build):

img/04983cb.jpg 67.3 KiB [emitted]
img/cc6fc31.jpg 85.8 KiB [emitted]

你将在浏览器的前端看到如下所示的图像:

<div class="links">
  <img src="/_nuxt/img/04983cb.jpg">
</div>

以下是这两个 webpack 加载器(url-loaderfile-loader)的默认配置:

[
  {
    test: /\.(png|jpe?g|gif|svg|webp)$/i,
    use: [{
      loader: 'url-loader',
      options: Object.assign(
        this.loaders.imgUrl,
        { name: this.getFileName('img') }
      )
    }]
  },
  {
    test: /\.(woff2?|eot|ttf|otf)(\?.)?$/i,
    use: [{
      loader: 'url-loader',
      options: Object.assign(
        this.loaders.fontUrl,
        { name: this.getFileName('font') }
      )
    }]
  },
  {
    test: /\.(webm|mp4|ogv)$/i,
    use: [{
      loader: 'file-loader',
      options: Object.assign(
        this.loaders.file,
        { name: this.getFileName('video') }
      )
    }]
  }
]

你可以像我们在前一个主题中使用 build 选项进行 webpack 配置一样,自定义此默认配置。

有关 file-loaderurl-loader 的更多信息,请访问 https://webpack.js.org/loaders/file-loader/https://webpack.js.org/loaders/url-loader/。

有关 vue-loadervue-template-compiler 的更多信息,请访问 https://vue-loader.vuejs.org/https://www.npmjs.com/package/vue-template-compiler。

如果你是 webpack 的新手,请访问 https://webpack.js.org/concepts/。另请访问 https://webpack.js.org/guides/asset-management/ 以获取其资源管理指南。简而言之,webpackJavaScript 应用程序的静态模块打包器。其主要目的是打包 JavaScript 文件,但它也可以用于转换 HTMLCSS、图像和字体等资源。如果你不想以 webpack 为你处理资源的方式提供资源,你也可以像我们在前面的 “理解目录结构” 部分中提到的那样,使用 /static/ 目录来存放静态资源。但是,使用 webpack 提供资源也有其好处。让我们在下一节中了解它们是什么。

webpack 资源 vs 静态资源

使用 webpack 进行资源服务的一个好处是,它可以为生产环境优化这些资源,无论是图像、字体还是预处理样式(如 LessSassStylus)。webpack 可以将 LessSassStylus 转换为通用的 CSS,而静态文件夹只是一个你可以放置所有永远不会被 webpack 处理的静态资源的地方。在 Nuxt 中,如果你不想为你的项目使用 /assets/ 目录中的 webpack 资源,你可以使用 /static/ 目录代替。

例如,我们可以使用 /static/ 目录中的静态图像,如下所示:

// pages/index.vue
<template>
  <img src="/sample-1.jpg"/>
</template>

另一个很好的例子是 Nuxt 配置文件中的 favicon 文件:

// nuxt.config.js
export default {
  head: {
    link: [
      { rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }
    ]
  }
}

请注意,如果你使用 ~ 别名来链接 /static/ 目录中的资源,webpack 将像处理 /assets/ 目录中的资源一样处理这些资源,如下所示:

// pages/index.vue
<template>
  <img src="~/static/sample-1.jpg"/>
</template>

我们将在第三章 “添加 UI 框架”、第四章 “添加视图、路由和过渡效果” 以及第五章 “添加 Vue 组件” 中大量使用 /assets/ 目录进行资源服务,以动态地提供资源。现在,让我们总结一下你在本章中学到的内容。

你可以在我们的 GitHub 仓库的 /chapter-2/assets/ 目录下找到一个从这两个目录提供资源和文件的示例应用程序。