反应脚本应用程序是否可以导出路由以便 NGINX 轻松使用

Is it possible for a react-script app to export the routes for easy consumption by NGINX

上下文

我正在将基于 ReactJS 的应用程序部署到 NGINX 以在客户端呈现。 NGINX 正在按如下方式提供静态文件:

  location / {
    try_files $uri $uri/ =404;
  }

这在为 index.html 服务的主路由 / 上运行良好,然后客户端路由器启动并呈现页面。

版本

"dependencies": {
    "react": "^16.3.2",
    "react-dom": "^16.3.2",
    "react-helmet": "^5.2.0",
    "react-router-dom": "^4.2.2",
    "react-scripts": "1.1.4",
    "styled-components": "^3.2.6"
  },

问题

如果我们在 React 中有像 /abc 这样的路由。这需要在客户端呈现。问题是如果有人将路线添加为书签,或共享它,或将其发布到搜索引擎等......然后如果浏览器在 NGINX 中请求 /abc 然后它找不到 /abc 位置块或文件如此导致 404

我目前提出的解决方案

我可以为每个已知路由添加一个到 NGINX 的路由,如下所示:

location /abc {
        try_files $uri $uri/ index.html;
      }

或者,我可以修改默认位置块 try_files 指令,如下所示:

location / {
    try_files $uri $uri/ index.html;
  }

第一种方法似乎更好,因为我明确定义了可接受的路线。因此,对 /xyz 的请求 - 这不是有效路由,将导致 404 - 这正是我想要的。但是,它要求我定义每条可能成为维护问题的路线,除非我可以有效地自动化它。

我建议 CI 构建的一部分执行如下操作:

cat src/components/Routes/Routes.js \
| grep -i route | grep "path" \
| tr '"' "'" \
| grep  -o -E "path=['\"]{1}(.*)['\"]{1}" \
| cut -d "=" -f 2 \
| tr -d "'"

然后使用此输出生成基于路由的 NGINX 位置块。

while read -r route; do
    echo "    try_files $uri /index.html;" >> ${ROUTES}
    echo "}" >> ${ROUTES}
done <<< "${ROUTES}"

例如输入如:

class Routes extends Component {
  render() {
    return [
      <Header {...this.props} key='header' />,
      <Switch key='content'>
        <Route exact path="/" component={HomeMVP} />
        <Route exact path='/about' component={About} />
        <Route exact path='/privacy' component={Privacy} />
        <Route component={NotFound} />
      </Switch>
    ];
  }
}

变为:

/
/about
/privacy

然后我可以生成 return index.html 的 NGINX 路由,以允许客户端路由器启动并呈现正确的页面。

问题

有谁知道使用 NGINX 或 React JS/reach 脚本的某些功能以比使用我上面建议的脚本更简单的方式导出路由的更好方法。

我在构建时 运行 在 dockerfile 中结束了以下脚本 (nginx:1.14-alpine):

#!/bin/sh
set -euo pipefail
IFS=$'\n\t'

ROUTES_FILE=/etc/nginx/dynamic-routes.conf

# Extract all of the routes (except "/")
ROUTES=$(grep -i route /etc/nginx/routes.js \
| grep "path" \
| tr '"' "'" \
| grep  -o -E "path='(.*)'" \
| grep  -v "'/'" \
| cut -d "=" -f 2 \
| tr -d "'")

# Now the routes contain the URI's, e.g. "/about" and "/privacy" loop through and generate NGINX routes.
echo "Routes are: ${ROUTES}"

for route in ${ROUTES}
do
    echo "Generating location for route: ${route}"
    echo "location ~ ${route}[/]?$ {" >> ${ROUTES_FILE}
    echo "    try_files $uri /index.html;" >> ${ROUTES_FILE}
    echo "}" >> ${ROUTES_FILE}
done

echo "Dynamic routes are: "
cat ${ROUTES_FILE}