Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I setup routing for react in GAE? Directly routing to react-router-dom routes via URL fails in GAE on basic create-react-app?

ANSWER for now

This was tough for me to get exactly right. Very little in the way of guidance via Google. I hope this helps others.

As Dan Cornilescu pointed out, the handlers accept the first match. So we go from more specific to less specific. I've solved this by following the folder structure created by npm run build: 1. Handle sub-directories for js, css, and media. 2. Handle json and ico requests for manifest.json and fav.ico. 3. Route all other traffic to index.html.

handlers:
  - url: /static/js/(.*)
    static_files: build/static/js/\1
    upload: build/static/js/(.*)
  - url: /static/css/(.*)
    static_files: build/static/css/\1
    upload: build/static/css/(.*)
  - url: /static/media/(.*)
    static_files: build/static/media/\1
    upload: build/static/media/(.*)
  - url: /(.*\.(json|ico))$
    static_files: build/\1
    upload: build/.*\.(json|ico)$
  - url: /
    static_files: build/index.html
    upload: build/index.html
  - url: /.*
    static_files: build/index.html
    upload: build/index.html

More efficient answers welcome.

Original Question:

Setting GAE app.yaml for react-router routes produces "Unexpected token <" errors.

In the development enviroment, all routes work when called directly. localhost:5000 and localhost:5000/test produce expected results.

In GAE standard app.yaml functions for the root directory when the URL www.test-app.com is called directly. www.test-app.com/test produces a 404 error.

app.yaml #1

runtime: nodejs8
instance_class: F1
automatic_scaling:
  max_instances: 1

handlers:
  - url: /
    static_files: build/index.html
    upload: build/index.html

Configuring app.yaml to accept wildcard routes fails for all paths. www.test-app.com/ and www.test-app.com/test produce an error "Unexpected token <". It appears that it is serving .js files as index.html.

app.yaml #2

runtime: nodejs8
instance_class: F1
automatic_scaling:
  max_instances: 1

handlers:
  - url: /.*
    static_files: build/index.html
    upload: build/index.html

Steps to reproduce this issue:

Node: 10.15.0 npm: 6.4.1

gcloud init via Google Cloud SDK

npm init react-app test-app

npm install react-router-dom

Add router to index.js:

index.js

import {BrowserRouter as Router, Route} from 'react-router-dom';
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';


ReactDOM.render(
  <Router>
    <App />
  </Router>,
  document.getElementById('root'));
serviceWorker.unregister();

Add routing to app.js:

app.js

import {Route} from 'react-router-dom'
import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';

class App extends Component {
  render() {
    return (
      <div>
        <Route exact path="/"
          render={() =>  <div className="App">
            <header className="App-header">
              <img src={logo} className="App-logo" alt="logo" />
              <p>
                Edit <code>src/App.js</code> and save to reload.
              </p>
              <a
                className="App-link"
                href="https://reactjs.org"
                target="_blank"
                rel="noopener noreferrer"
              >
                Learn React
              </a>
            </header>
          </div>} />
        <Route exact path="/test"
          render={() =>  <div className="App">
            Hello, World!
          </div>} />
      </div>
    );
  }
}

export default App;

No changes to package.json:

package.json

{
  "name": "test-app",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "react": "^16.7.0",
    "react-dom": "^16.7.0",
    "react-router-dom": "^4.3.1",
    "react-scripts": "2.1.3"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  },
  "eslintConfig": {
    "extends": "react-app"
  },
  "browserslist": [
    ">0.2%",
    "not dead",
    "not ie <= 11",
    "not op_mini all"
  ]
}

npm run build

gcloud app deploy

How do we convince app engine to allow a react SPA to process routes directly?

like image 909
Nathan Shepherd Avatar asked Jan 18 '19 04:01

Nathan Shepherd


People also ask

Do I need to install both react router and react router dom?

@snAtchnAren It's not mandatory. You should never need the "react-router" package if you've already installed "react-router-dom".

Is it possible to configure routes programmatically in react?

Since v4 of React Router, there are three approaches that you can take to programmatic routing within components. Use the withRouter higher-order component. Use the context .


1 Answers

I took the answers from Nathan Shephard and Dan Cornilescu and condensed them into the app.yaml below. It seems to be working for my React SPA on GAE Standard. No application server (ex: serve.js, ExpressJS, etc) is necessary.

env: standard
runtime: nodejs10
service: default

handlers:
  - url: /static
    static_dir: build/static

  - url: /(.*\.(json|ico|js))$
    static_files: build/\1
    upload: build/.*\.(json|ico|js)$

  - url: .*
    static_files: build/index.html
    upload: build/index.html
like image 197
John Michelau Avatar answered Oct 21 '22 21:10

John Michelau