Next.js使用getServerSideProps时全局CSS生产环境不加载问题
问题:Next.js生产环境下全局样式与_app.tsx未生效(自定义Express服务器)
场景复现
- 全局样式定义在
/styles/globals.css,并在_app.tsx中导入:
// import default style import "../styles/globals.css"; function MyApp({ Component, pageProps }) { return <Component {...pageProps} />; } export default MyApp;
- pages目录下
pages/index.tsx代码:
export async function getServerSideProps({req, res }) { // Some fetch here return { props: { someProps: objectFromFetchThere, }, }; } const Home: NextPage<{ someProps: SomeProps[] }> = ({ someProps }) => { return ( <> <Head> <title>Home page</title> <meta name="description" content="Generated by create next app" /> <link rel="icon" href="/favicon.ico" /> </Head> <Layout> // More code here </Layout> </> ); };
问题现象
- 开发环境执行
next dev:样式正常加载,getServerSideProps正常调用,功能完全正常。 - 生产环境执行
next build && NODE_ENV=production ts-node src/server.ts:全局样式未加载,_app.tsx完全不生效。
疑问:曾怀疑使用getServerSideProps的页面无法使用全局样式,但Next.js文档未找到相关限制说明。
自定义Express服务器代码
(async () => { try { const expressServer = express(); await app.prepare(); // Some custom routes defined over there like /facility - nothing that can overlap with styles. // Error middleware has to be used after other custom routes expressServer.use( (err: Error, req: Request, res: Response, next: NextFunction) => { console.error(err.stack); res.status(500).send("Unexpected error occurred."); } ); expressServer.all("*", async (req: Request, res: Response) => { try { await handle(req, res); } catch (e) { console.error("Error occurred handling", req.url, e); res.statusCode = 500; res.end("internal server error"); } }); expressServer.listen(port, (err?: any) => { if (err) throw err; console.log( `> Ready on localhost:${port} - env ${process.env.NODE_ENV}` ); }); } catch (e) { console.error(e); process.exit(1); } })();
问题根源
你的自定义Express服务器错误地将错误中间件放在了Next.js请求处理逻辑之前。Next.js的handle需要优先处理所有请求(包括静态资源请求,比如编译后的全局样式文件),而错误中间件的位置错误会导致请求被提前拦截,静态资源无法被正确解析,同时_app.tsx的全局逻辑也无法正常执行。
修复方案
调整中间件顺序,将错误处理中间件移到所有路由(包括Next.js的通配符路由)之后:
(async () => { try { const expressServer = express(); await app.prepare(); // 自定义路由放在最前面 // Some custom routes defined over there like /facility - nothing that can overlap with styles. // 先注册Next.js的请求处理逻辑 expressServer.all("*", async (req: Request, res: Response) => { try { await handle(req, res); } catch (e) { console.error("Error occurred handling", req.url, e); res.statusCode = 500; res.end("internal server error"); } }); // 错误中间件放在最后 expressServer.use( (err: Error, req: Request, res: Response, next: NextFunction) => { console.error(err.stack); res.status(500).send("Unexpected error occurred."); } ); expressServer.listen(port, (err?: any) => { if (err) throw err; console.log( `> Ready on localhost:${port} - env ${process.env.NODE_ENV}` ); }); } catch (e) { console.error(e); process.exit(1); } })();
额外说明
getServerSideProps与全局样式完全不冲突,Next.js中所有页面(无论使用哪种数据获取方式)都可以正常使用_app.tsx导入的全局样式。- 生产环境下Next.js会将全局样式编译为静态资源,自定义服务器必须保证这些请求能被
handle正确处理,中间件顺序错误会直接阻断静态资源的加载逻辑。
内容的提问来源于stack exchange,提问作者lukhol
相关产品推荐
相关产品推荐

