这阵子在折腾 next.js,用来做 node 服务端渲染真心不错,然而一路捣腾下来,坑也是不少,有四个比较大的坑。
- isomorphic-fetch(解决)
- node 端代码打包(未解决)
- js 放到 cdn 或者 oss(解决)
- static 目录下的图片 hash(临时方案)
这四个坑,1 和 3 是必须解决的,2 和 4 可选。
1
fetch 本来不是什么问题,但是涉及到请求签名,就来了点麻烦,需要区分是服务端还是客户端,客户端用 cookie 存储 token,服务端用变量。
2
node 代码其实不需要打包,因为是运行在服务端,不过为了节省 docker 镜像的大小,尝试了打包,主要是想把 node_modules 也打包进去。先是用 webpack,能打包成功,但是运行失败。后面又用 rollup,同样是打包成功,运行失败。可能是因为 nextjs 本身就包含了 webpack,而用打包工具来打包自己,估计 webpack 和 rollup 都没有想过会有这样的场景出现。于是放弃。
3
这个比较坑,所以重点说一下。
nextjs 提供了 assetPrefix 参数,但是这个参数基本没什么用。需要解决两个问题,一是打包目录要把 hash 带进去,把原来的 bundles/pages/xxx.js 目录结构改成 [hash]/xxx.js,这一步可以在打包脚本里处理,通过 BUILD_ID 和 build-stats.json 拿到 hash,直接上代码:
rm -r -f build mkdir build # move pages buildId=$(cat _next/BUILD_ID) mkdir build/${buildId} mv _next/bundles/pages/* build/${buildId} rm -r _next/bundles # move app.js appHash=$(cat _next/build-stats.json) appHash=${appHash#*hash\":\"} appHash=${appHash%\"*} mv _next/app.js build/app.${appHash}.js
其中,_next 是 nextjs 的 distDir,build 是需要上传到 cdn 的目录。
接下来在 server.js 里重写 router,用了 express,参考 https://github.com/zeit/next.js/issues/257
const cdnPrefix = 'https://mycdn.com' server.use('/_next/**/app.js', (req, res) => { const appHash = req.originalUrl.replace('/_next/', '').replace('/app.js', '') const newUrl = `${cdnPrefix}/build/app.${appHash}.js` res.redirect(newUrl) }) server.use('/_next/**/page/**', (req, res) => { const buildHash = req.originalUrl.replace('/_next/', '').replace(/\/page\/.*/, '') const pageName = req.originalUrl.replace(/.*page\//, '') || 'index' const newUrl = `${cdnPrefix}/build/${buildHash}/${pageName}.js` res.redirect(newUrl) })
4
static 目录下的图片 hash,这个问题也比较次要,暂时可以通过 githooks 来处理图片修改的问题,对于图片只允许增量提交。
.git/hooks/pre-commit
#!/bin/sh STAGED_IMAGES=$(git diff --cached --name-only --diff-filter=M | grep -E ".(jpg|jpeg|png|gif)$") if [[ $STAGED_IMAGES ]]; then echo $STAGED_IMAGES exit 1 fi
还有一些小坑,比如 process.env.NODE_ENV 的问题(如果有三种以上的环境),比如 scss 里面因不同环境插入不同 cdn 地址图片的问题,等等,就不列了。
楼主,项目运行,vendor.js很大,导致首页加载很慢。怎么解决的
受到博主的启发,后来自己又研究了下。
assetPrefix这个参数可以用来当做publicPath使用,配合url-loader,可以给文件添加hash。然后将构建出来文件的目标路径修改为express.static的目录,就不用像博主那样去server.js修改了。
赞
可以给下 问题1 的解决方案代码么
我现在遇到类似的问题
时间长了,代码木有印象了。后来我们不用next了,坑太多。
客户端的 fetch 请求,注意在请求 Header 添加 credentials: ‘include’, 服务端(nextjs)的请求因为不能自动获取到浏览器的 cookie,可以通过 getInitialProps 钩子函数手动传入cookie (req.headers.cookie). 可以参考 https://github.com/BaoXuebin/xdbin-react-app/blob/master/src/utils/Net.js