使用create-react-app和react-router在自定义根路径/app部署React应用遇问题
咱先把你遇到的问题掰明白:你想把React应用部署在/app子路径下,用serve启动构建后的产物时,访问/app/出现空白页面且无网络请求,手动在build目录下创建app/static才恢复正常。其实这背后是资源路径解析和路由配置的双重问题,我给你一步步拆解清楚:
问题到底出在哪?
当你在package.json里设置homepage: "/app"后,CRA会自动把构建产物里所有静态资源(JS、CSS、图片等)的引用路径改成/app/static/xxx。但默认情况下,CRA构建出来的static文件夹是直接放在build根目录下的,而serve启动后,访问/app/时会去build/app/static查找这些资源——这个目录根本不存在!所以资源加载全失败,页面自然就空白了。
你手动创建app/static并移动内容能临时解决,是让资源的实际存储路径和请求路径对上了,但这属于 workaround,CRA本身就有正规配置方式,不用手动折腾目录。
正确的配置步骤,一步都不能少
1. 配置CRA的homepage字段
在package.json里设置:
"homepage": "/app"
这个字段的作用是告诉CRA:「我的应用要部署在域名的/app子路径下」,构建时会自动给所有静态资源的引用加上/app/前缀,同时process.env.PUBLIC_URL环境变量也会被设为/app,后续路由配置可以直接复用这个变量,不用硬编码。
划重点:别设置成完整的
https://example.com/app,除非你确定只在这个域名部署,用相对路径/app适配性更强。
2. 给React Router添加basename属性
打开你的路由根组件,给<BrowserRouter>(用HashRouter同理)加上basename:
import { BrowserRouter } from 'react-router-dom'; <BrowserRouter basename={process.env.PUBLIC_URL}> {/* 你的所有路由组件都放在这里 */} </BrowserRouter>
用process.env.PUBLIC_URL的好处是,它会自动读取homepage的配置值,保证路由前缀和资源路径前缀一致,避免后续修改homepage还要手动改路由的麻烦。
3. 用serve启动的正确命令
之前直接跑serve build行不通,因为serve默认把build当成根目录,访问/app/时会去build/app找index.html,但CRA构建的index.html在build根目录!正确命令应该是:
serve -s build -l 5000
这里的-s是单页应用模式,它会把所有路由请求都重定向到build/index.html,配合前面的homepage配置,静态资源路径就能正确解析,完全不用手动创建app/static文件夹。
搞懂homepage和basename的区别,为啥要同时用?
很多人容易混淆这俩的作用,我给你直白解释:
homepage(CRA配置):管静态资源的加载路径,比如JS、CSS、图片的src地址,确保它们能从/app/static正确加载,同时也会影响public目录下文件的引用路径。basename(React Router配置):管路由的路径匹配,它会给所有路由路径自动加上/app前缀,比如你写的路由/会变成/app/,/about会变成/app/about,这样用户访问这些路径时,React Router才能正确匹配到对应组件。
这俩必须同时用:只设homepage的话,路由跳转可能会跳到域名根路径;只设basename的话,静态资源会从根路径加载,直接404,缺一不可。
为什么手动创建app/static能临时解决?
当你在build下创建app/static并移动原static内容后,页面请求的/app/static/js/main.xxx.js就对应到了build/app/static/js/main.xxx.js,资源能正常加载,页面也就显示了。但这是绕开CRA正确配置的临时办法,下次重新构建后还要手动移动文件,太麻烦,还是用上面的正规配置省心。
内容的提问来源于stack exchange,提问作者tbd_

