mock server端冗余模块优化next.js dev/build 性能
随着项目的增加,运行next dev时候电脑越来越卡了,注意到 next-server这个进程随着热更新的次数增加内存也占用的越来越大。
进行一些排查之后,发现了一个优化点:
就是在server端导入了比较多的冗余module,可以通过mock某些不需要在server导入的依赖,优化 next.js dev/build 性能。
实现原理
举个例子:
在某个页面需要调用依赖a,但是a不会在server中运行,运行a可能是在onClick中,或者某些强依赖browser的环境中。
那么此时对于server bundle来说,导入a就是多余的。
如果a的代码量非常大、模块数量非常多或者有很多a独有的依赖。势必会降低server 构建的性能以及可能的 server 运行的性能。
详见 example/next-js。
在这个例子中,我们使用了 @web3modal/ethers 和 ethers,但是这两个依赖并不会在服务端运行,他们依赖的browser。
所以我们可以尝试mock这两个依赖的导出,使得业务代码不用做任何更改,同时优化server端的性能。
如何 mock
通过指定webpack.resolve.alias来 mock 依赖。
例如:
在 server 构建时候,webpack 解析到如下代码:
import { createWeb3Modal } from "@web3modal/ethers/react"时。
通过 webpack.resolve.alias 指定 @web3modal/ethers/react 为 mock.js,
使其真正参与编译的时候被替换为 mock.js的实现。
// mock.js
function f() {}
function mockHooks() {
return {};
}
const mock = new Proxy(f, {
get(target, p, receiver) {
if (typeof p === "string") {
// 当做 react hooks 使用,确保返回值不是空的
if (p.startsWith("use")) {
return mockHooks;
}
if (p === "__esModule") {
return false;
}
}
// 默认返回自身,确保可以循环引用
return mock;
},
construct(target, argArray, newTarget) {
return mock;
},
});
// 只会在 server 中被导入,使用 cjs 导出
// 并且 es module 不支持 动态导出,需要声明清楚需要导出的 member
// 这里用 cjs 能很好的完成 mock module 这个任务
exports = mock;
module.exports = exports;
对比
这里给出部分对比数据,感兴趣可以运行 example/next-js 查看。
next dev
module count
- 常规

- 优化

访问同一页面next构建的module数量有所下降,即在server端没有去构建@web3modal/ethers和ethers。
memory usage
冷启动后
- 常规

- 优化

热更新多次后
- 常规

- 优化

next build
通过运行 node --heap-prof ./node_modules/next/dist/bin/next build 生成的 heapprofile 获取的内存数据
memory usage
- 常规

- 优化

bundle-analyzer
- 常规

- 优化

总结
从以上对比数据来看,mock掉在server中用不上的依赖确实能带来有效的性能提升。
最后
抛砖引玉,希望能看到更多的想法,当然也可能后续turbo pack稳定后也不需要乱七八糟的hack方法。
可以直接安装ssr-optimize试试咸淡。
转载自:https://juejin.cn/post/7353060906698014755