静态资源内联

静态资源内联是一种优化网页性能的方法,它指的是将静态资源直接内联到 HTML 或 JS 文件中,而不是使用外部文件引用的方式。这样做的好处是减少了浏览器发起的请求数,从而提高页面的加载速度。

不过,静态资源内联也有一些缺点,比如增加了单个文件的体积,可能会导致加载变慢。所以在实际应用中,需要根据具体情况来决定是否使用静态资源内联。

Modern.js 默认会自动内联体积小于 10KB 的静态资源,但有时候你可能需要手动控制某些特殊资源,让其强制内联或者强制不内联,这篇文档阐述了如何进行精确地控制静态资源内联行为。

自动内联

默认情况下,当图片、字体、媒体等类型的文件体积小于阈值(默认为 10KB)时,Modern.js 会将资源进行内联处理,资源内联后,会被转换成一个 Base64 编码的字符串,不再会发送独立的 HTTP 请求。当文件体积大于或等于该阈值时,则会被作为单独的资源文件,通过独立的 HTTP 请求来加载。

自动内联的体积阈值可以通过 output.dataUriLimit 配置项修改。例如,修改图片资源的阈值为 5000 字节,设置视频资源不内联:

export default {
  output: {
    dataUriLimit: {
      image: 5000,
      media: 0,
    },
  },
};

强制内联

你可以通过在引入资源时添加 inline URL 参数来强制内联该资源,无论该资源的体积是否小于阈值。

import React from 'react';
import img from './foo.png?inline';

export default function Foo() {
  return <img src={img} />;
}

在上面这个例子中,foo.png 图片将始终被内联,无论该图片的大小是否大于阈值。

除了 inline 参数以外,你也可以使用 __inline 参数来强制内联该资源:

import img from './foo.png?__inline';

从 CSS 文件中引用

当你在 CSS 文件中引用静态资源时,同样可以通过 inline__inline 参数来强制内联资源。

.foo {
  background-image: url('./icon.png?inline');
}
你真的需要强制内联吗?

内联体积过大的资源时,会显著增加页面的白屏时间或首次可交互时间,这会损害用户体验。并且当你将一个静态资源多次内联到 CSS 文件中时,base64 内容会重复注入,导致产物体积增大。因此,请酌情使用强制内联。

强制不内联

当你想把一些资源始终作为单独的资源文件来处理,无论该资源的体积多小时,你可以添加 url URL 参数来强制不内联该资源。

import React from 'react';
import img from './foo.png?url';

export default function Foo() {
  return <img src={img} />;
}

在上面这个例子中,foo.png 图片将始终通过单独的资源文件加载,无论该图片的大小是否小于阈值。

除了 url 参数以外,你也可以使用 __inline=false 参数来强制不内联该资源:

import img from './foo.png?__inline=false';

从 CSS 文件中引用

当你在 CSS 文件中引用静态资源时,同样可以通过 url__inline=false 参数来强制不内联资源。

.foo {
  background-image: url('./icon.png?url');
}
你真的需要把资源排除内联吗?

将资源排除内联将增加 Web App 需要加载的资源数量,这对于弱网环境,或是未开启 HTTP2 的场景下,将会降低资源加载效率,因此,请酌情使用强制不内联。

内联 JS 文件

除了将静态资源文件内联到 JS 文件里,Modern.js 也支持将 JS 文件内联到 HTML 文件中。

只需要开启 output.enableInlineScripts 配置项,构建生成的 JS 文件将不会被写入产物目录下,而是会直接内联到对应的 HTML 文件中。

export default {
  output: {
    enableInlineScripts: true,
  },
};
TIP

内联 JS 文件可能会导致 HTML 单文件体积过大,并且不利于静态资源缓存,请酌情使用。

内联 CSS 文件

你也可以将 CSS 文件内联到 HTML 文件中。

只需要开启 output.enableInlineStyles 配置项,构建生成的 CSS 文件将不会被写入产物目录下,而是会直接内联到对应的 HTML 文件中。

export default {
  output: {
    enableInlineStyles: true,
  },
};

添加类型声明

当你在 TypeScript 代码中使用 ?inline?url 等 URL 参数时,TypeScript 可能会提示该模块缺少类型定义:

TS2307: Cannot find module './logo.png?inline' or its corresponding type declarations.

此时你需要为这些 URL 参数添加类型声明,请在项目中创建 src/global.d.ts 文件,并添加以下类型声明:

declare module '*?inline' {
  const content: string;
  export default content;
}

declare module '*?inline' {
  const content: string;
  export default content;
}

declare module '*?__inline' {
  const content: string;
  export default content;
}

declare module '*?inline=false' {
  const content: string;
  export default content;
}