Next.js我说迁就迁了!
起因
Next.js
的优缺点就不再赘述了,这里列出在业务场景下迁移到Next.js
的一些原因。
- 在
Next.js
中文件即路由
的思想使我们不需要过多关注于路由,极大简化了相关的配置 - 支持静态页面导出(
SSG
),无服务器、渲染极快 webpack
完全可自定义,在项目起初没有选择cra
等脚手架的一大原因就是webpack
配置不自由- ...
迁移历程
期间经历了各种坑,大多是SSR
导致的各种限制,在使用Next.js
之前最好了解一些SSR
的概念,就不至于遇到问题时束手无策。
以下是迁移的过程、遇到的问题以及对应的解决方案。
路由系统
使用react-route-dom
我们需要这样组织我们的路由:
<BrowserRouter>
<Routes>
<Route path="/" element={<App />}>
<Route index element={<Home />} />
<Route path="teams" element={<Teams />}>
<Route path="new" element={<NewTeamForm />} />
</Route>
</Route>
</Routes>
</BrowserRouter>
在Next.js
中我们只需要把页面组件放到src/pages/*
即可,例如:
如果用到了api
路由则使用Next.js
提供的hooks
import { useRouter } from 'next/router'
环境变量
我们的项目区分多个平台需要在不同的平台加载不同的环境变量,在此之前Vite
允许我们自定义模式及其环境变量,但Next.js
只提供development``production``localtion
,所以我们在开发/构建之前通过执行脚本来动态生成配置文件。
// package.json
{
"scripts": {
"dev": "yarn dev:public",
"dev:dingtalk": "export APP_ENV=dingtalk && node loadEnv.js && next dev",
"dev:public": "export APP_ENV=public && node loadEnv.js && next dev",
}
}
// loadEnv.js
const fs = require('fs');
const APP_ENV = process.env.APP_ENV;
fs.writeFileSync(".env", `NEXT_PUBLIC_PLATFORM=${APP_ENV}`);
全局变量
由于Next.js
默认开启SSR
,服务端无法访问浏览器全局变量,所以应当检查window
等全局变量是否使用,如果有则对服务端兼容处理。
const isServer = _ => typeof window === 'undefined';
const composeEnhancers = !isServer() ? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose : compose;
同步服务端Redux Store
服务端也会创建一个Redux Store
,next-redux-wrapper
可以帮我们同步Redux Store
。
Redux Store 持久化
服务端渲染时服务端和客户端都会创建一个redux store
,所以我们需要next-redux-wrapper
保证两个store
保持相同的状态。
由于业务需要刷新页面之后要保证store
中的数据不丢失,我用到了redux-persist
来缓存store
中的数据,next-redux-wrapper
提供了和redux-persist
一起使用的文档,测试之后出现了页面空白的问题,经排查之后发现文档给出的示例代码存在书写错误导致组件没有挂载,顺便就提了个 PR。
反向代理
Next.js
提供了重写的相关配置,复杂的请求需要自定义服务器实现。
// next.config.js
export default {
async rewrites() {
return [
{
source: '/api/:path*',
destination: 'http://1xx.x.1xx.xx:1234/api/:path*',
},
];
},
};
依赖兼容
引入全局CSS
Next.js
禁止依赖加载全局CSS
,但是作为开发者我们无法保证所有依赖包都不加载全局CSS
,如果依赖引入了全局CSS``Next.js
会抛出异常。
RFC
已经提出一年多的时间了,目前还是没有进展,在了解背景之后我找到了一下两种解决方案(已测试可行):
next-global-css
next-transpile-modules
服务端导入依赖问题
极个别的依赖项在服务端引入时具有CJS
的特征,需要.default
才可以获取到依赖的值,暂时没搞明白原因,有懂哥的请告知,暂时的解决办法是进行兼容处理。
import logger from 'redux-logger';
import thunk from 'redux-thunk';
// 兼容处理
const thunkMiddleware = thunk.default ? thunk.default : thunk;
const loggerMiddleware = logger.default ? logger.default : logger;
CSS
为了防止命名冲突Next.js
只允许在pages/_app.js
中引入css
,或者可以使用css module
静态资源
需要放在/public
文件夹内,例:
/*
-public
--logo.png
*/
<Image src="/logo.png" width={16} height={16} />
SSG限制
生成静态页面之后,Next.js
无法进行对next/image
进行优化,需要在配置项中手动关闭。
// next.config.js
export default withTM({
reactStrictMode: true,
experimental: {
images: {
unoptimized: true,
},
}
});
转载自:https://juejin.cn/post/7140187608792956958