小明搞到一台服务器,用 Nextjs 搭建了一个简单的网页应用,部署到了服务器上。由于服务器带宽低,访问网页发现脚本加载很慢,于是小明考虑将静态资源上传到 CDN,减轻服务器压力,还能享受 CDN 带来的其他好处。

以 Nextjs13 版本为例,在部署项目之前,我们都会执行一次 next build 命令,这个命令会生成一个 .next 目录,里面存放了很多脚本。

../images/2023-09-05-oidn.png

部署好之后,访问页面,会发现 script 标签的 src 属性,都以 /_next/static/ 开头。

../images/2023-09-05-obzl.png

这个路径其实对应 .next/static/ 目录。比如 /_next/static/chunks/10361123-9db6883597b575ca.js ,对应的是 .next/static/chunks/10361123-9db6883597b575ca.js 文件。

现在我们要想办法把 .next/static/ 目录下的东西,上传到 CDN 上,然后把 src 修改为 CDN 地址。

# 修改脚本地址

打开 next.config.js 文件,新加一个 assetPrefix 字段:

const isProd = process.env.NODE_ENV === "production";

module.exports = {
  assetPrefix: isProd ? "https://cdn.mydomain.com" : undefined,
};

重新构建、部署,访问页面,会发现脚本的地址变了:

../images/2023-09-05-omjh.png

说白了就是 /_next/static/ 路径前面拼上了 assetPrefix

assetPrefix 除了写域名,也可以在域名后面加上其他东西,比如 https://cdn.mydomain.com/tag_1.0 ,这样最终生成的脚本地址就以 https://cdn.mydomain.com/tag_1.0/_next/static/ 开头。

这里的域名 https://cdn.mydomain.com ,只是个示例,要换成 CDN 厂商实际给的真实域名。

现在我们已经修改好路径了, /static/chunks/10361123-9db6883597b575ca.js 变成了 https://cdn.mydomain.com/_next/static/chunks/10361123-9db6883597b575ca.js 。接下来就要上传脚本到 CDN,实现可以通过 https://cdn.mydomain.com/_next/static/chunks/10361123-9db6883597b575ca.js 访问到脚本。

# 上传资源到 CDN

很多云服务商提供对象存储服务,可能需要额外花钱,但如果网站访问量小,一个月才花几毛钱到几块钱。这里以阿里云 OSS 为例,阿里云 OSS 是什么?怎么搞?这里就不多讲了,搞好之后你应该会拿到 accessKeyId,accessKeySecret,region,bucket 这四样东西。

如果你的阿里云 OSS 的加速域名为 your-cdn.oss-accelerate.aliyuncs.com ,将 assetPrefix 设置为 https://your-cdn.oss-accelerate.aliyuncs.com

Nextjs 用的是 webpack 构建脚本的,所以我们需要写一个,或者找一个 webpack 插件,用来将构建好的脚本上传到阿里云 OSS,就用 next-oss-webpack-plugin 插件吧,先安装一下 npm i next-oss-webpack-plugin --save-dev

打开 next.config.js 文件,加入如下代码

const NextOSSPlugin = require("next-oss-webpack-plugin");
const isProd = process.env.NODE_ENV === "production";
const assetPrefix = isProd
  ? "https://your-cdn.oss-accelerate.aliyuncs.com"
  : undefined;
module.exports = {
  //...
  assetPrefix,
  webpack(config, { buildId }) {
    if (isProd && buildId) {
      config.plugins.push(
        new NextOSSPlugin({
          region: "", // bucket 所在区域,比如 oss-cn-hangzhou
          accessKeyId: "",
          accessKeySecret: "",
          bucket: "", // bucket 的名称,比如 my-cdn
          filter: (assert) => /^static\/.*/.test(assert),
          assetPrefix: `${assetPrefix}/_next/`, // 上传资源前缀
        })
      );
    }
    return config;
  },
  //...
};

上面 accessKeyId,accessKeySecret,region,bucket 都可以在阿里云里拿到。执行 next build 的时候,这个插件会把 .next/static/ 目录下的资源(不仅仅是脚本,还有 json 文件等),上传到阿里云 OSS 上,这样就可以通过加速域名或者 CDN 域名访问到脚本了。

其他云服务厂商实现方式大同小异,唯一需要注意的是上传之后的路径要有 /_next/static/ ,比如上面的 https://your-cdn.oss-accelerate.aliyuncs.com/_next/static/chunks/10361123-9db6883597b575ca.js

不能上传为 https://your-cdn.oss-accelerate.aliyuncs.com/chunks/10361123-9db6883597b575ca.js 或者 https://your-cdn.oss-accelerate.aliyuncs.com/10361123-9db6883597b575ca.js ,错误的上传路径会导致 404 not found。