nextjs 如何将静态资源发布到 CDN

nextjs 如何将静态资源发布到 CDN

蚊子前端博客
发布于 2019-09-17 21:24
nextjs 是基于 react 的服务端同构指出框架,在使用的过程中也多多少少遇到过几个问题,其中最大的问题就是静态资源的发布了

nextjs 是基于 react 的服务端同构指出框架,在使用的过程中也多多少少遇到过几个问题,其中最大的问题就是静态资源的发布了。

1. 如何基于文件内容进行 hash 命名

Next.js uses a constant generated at build time to identify which version of your application is being served. This can cause problems in multi-server deployments when next build is ran on every server. In order to keep a static build id between builds you can provide the generateBuildId function:

按照官网上的说法,每次发布都会生成新的 hash 路径,即使当前没有任何的变动。例如某次发布的路径是/_next/static/tZonUgEY-GPCEExGbFapL/pages/index.js,那么下次的 hash 必然不是这个值。这样导致的一个问题是:如果在多台机器上发布并 build 时,会导致每次 build 产生的值不同。如果想固定某个值或者使用某个值,一个是可以先 build 完成后后再分发,或者,可以在next.config.js中自定义generateBuildId

COPYJAVASCRIPT

// 来自官网上的例子 // next.config.js module.exports = { generateBuildId: async () => { return "my-build-id"; }, };

npm 上也有提供相应的安装包,可以使用当前 git 提交的 hash 值作为 buildId:next-build-id

可是这种存在的一个问题就是:即使文件没有发生变动,或者我只修改了首页的代码,发布完成后,pages 下所有的资源都需要重新加载,有用户建议使用内容的 hash 值作为每个资源的路径,但官方好像好像不太情愿,说实现起来比较困难,详情可以看这个 issue: use content hash in pages chunk name。在这条 issue 中,有用户自己实现一个插件,不过我还没用过,有兴趣的同学可以尝试下。

2. 路径的拼接规则

静态资源上传到 CDN,这是存在目前存在的最大的问题,虽然在next.config.js中可以配置assetPrefix字段,但实际使用起来还是非常困难。

打包后的 js 和 css,引用路由均为/_next/static开头:

nextjs中静态资源上传到CDN-蚊子的前端博客

如图片中所示,带有 data-next-page 属性的,实际上访问的是.next/server/static/[hash]/pages/_app.js;不带这个属性的,访问的路径是.next/static/runtime/webpack-[hash].js

我们以 2019/09/16 提交的 nextjs 源码为例:pages_document,里面有全局脱水数据的注入,页面相关的 js 和静态资源的 js 的拼接:

COPYJAVASCRIPT

// 页面相关的js // assetPrefix为我们在next.config.js中配置的前缀 // ${buildId}即为每次打包生成的hash值,在本地环境下值为development // _devOnlyInvalidateCacheQueryString: 变动的时间戳,正式环境中为空, _devOnlyInvalidateCacheQueryString: process.env.NODE_ENV !== 'production' ? '?ts=' + Date.now() : '' src={assetPrefix + encodeURI(`/_next/static/${buildId}/pages${getPageFile(page)}`) + _devOnlyInvalidateCacheQueryString} // 静态资源的js src={`${assetPrefix}/_next/${file}${_devOnlyInvalidateCacheQueryString}`}

全局脱水数据的注入

COPYJSX

从第 2 部分中能看到,代码中使用assetPrefix作为静态资源的前缀时,只是单纯的拼接到了最前面而已,拼接后的地址是:

COPYHTML

中间多出了/_next/static的路径,最后的结果是页面需要加载的资源和上传的资源路径不一致,就会各种 404。这里我的解决方案很简单粗暴,读取编译后的文件,然后执行 node 程序,将里面的字符替换掉:

COPYJAVASCRIPT

const fs = require("fs"); const glob = require("glob"); const list = glob.sync(".next"); list.forEach((file) => { let data = fs.readFileSync(file, "utf8"); if (file.indexOf("_document.js") > -1) { data = data.replace(/\/_next\//g, "/").replace(/static\/" \+ buildId/g, '" + buildId'); fs.writeFileSync(file, data); console.log(file, "success"); } else if (file.indexOf("build-manifest.json") > -1) { data = data.replace(/static\//g, ""); fs.writeFileSync(file, data); console.log(file, "success"); } else if (data.indexOf("/_next/static") > -1) { data = data.replace(/\/_next\/static\//g, "/"); fs.writeFileSync(file, data); console.log(file, "success"); } });

这样就能就可以保证项目的 CDN 地址和真正上传的地址是一致的了。

标签:

阅读(3246)

公众号:

qrcode

微信公众号:前端小茶馆

版权声明:
作者:Joker 链接:https://hooper.eu.org/archives/47623
文章版权归作者所有,转载请注明出处。
THE END
分享
二维码
打赏
< <上一篇
下一篇>>