Search code examples
expressaws-lambdacreate-react-appserverlessvercel

expressjs and create react app deployment with zeit now


I was able to deploy a Create-React-App and express back-end with now.sh but the problem is that it only gets the home route(I can route to /about from home but on page reload/refresh, i get a 404 error). I have tried several config. Please i need help.

  "public": false,
  "version": 2,

  "builds": [
    {
      "src": "server/index.js",
      "use": "@now/node",
      "config": {
        "maxLambdaSize": "20mb"
      }
    },
    {
      "src": "package.json",
      "use": "@now/static-build",
      "config": {
        "distDir": "build"
      }
    }
  ],
  "routes": [
    {
      "src": "/api/(.*)",
      "dest": "/server/index.js"
    },
    {
      "src": "/(.*)",
      "dest": "/build/$1"
    }
  ]
}


Solution

  • This sounds like a problem described here - https://create-react-app.dev/docs/deployment/

    If you use routers that use the HTML5 pushState history API under the hood (for example, React Router with browserHistory), many static file servers will fail. For example, if you used React Router with a route for /todos/42, the development server will respond to localhost:3000/todos/42 properly, but an Express serving a production build as above will not. This is because when there is a fresh page load for a /todos/42, the server looks for the file build/todos/42 and does not find it. The server needs to be configured to respond to a request to /todos/42 by serving index.html. For example, we can amend our Express example above to serve index.html for any unknown paths:

    app.use(express.static(path.join(__dirname, 'build')));
    
    -app.get('/', function (req, res) {
    +app.get('/*', function (req, res) {
       res.sendFile(path.join(__dirname, 'build', 'index.html'));
     });
    

    When users install your app to the homescreen of their device the default configuration will make a shortcut to /index.html. This may not work for client-side routers which expect the app to be served from /. Edit the web app manifest at public/manifest.json and change start_url to match the required URL scheme, for example:

    "start_url": ".",
    

    This helped when I had 404 with Zeit - https://itnext.io/fix-404-error-on-single-page-app-with-zeit-now-b35b8c9eb8fb -

    In order to solve the 404 error message, we have to make sure that when a user goes to any URL which is not the root URL (e.g. www.myapp.com/something or www.myapp.com/dashboard/example) and they have never loaded our web app before, they are redirected to the root URL. Once they have loaded the root URL then they can be redirected back to the page they were trying to access and everyone is happy!

    Step 1 - in your project's public folder make another package.json file -

    {
      "name": "myapp-spa",
      "version": "1.0.0",
      "scripts": {
        "start": "serve --single --cache=60000"
      },
      "dependencies": {
        "serve": "latest"
      }
    }
    

    Step 2 - Configure the 404 page

    Now that our files are being served, if a person goes to a non-root URL, the server will look for a 404.html file to send them instead. This is our chance to redirect them and take them to the index.html page. Put the 404.html file in the same public folder as the index file.

    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <meta http-equiv="X-UA-Compatible" content="ie=edge">
      <title>404 Not Found | My App</title>
    </head>
    <body>
      <script>
        (function redirect() {
          if (document && document.location) {
            document.location.replace(`/?redirect=${encodeURIComponent(document.location.pathname)}`);
          }
        }());
      </script>
    </body>
    </html> 
    

    Step 3. - Prepare for deployments

    Now that, we have our redirect code, all we have to do is add a deploy command to our original myapp/package.json (this is not the file we created earlier):

    {
      "scripts": {
        ...    
        "deploy": "yarn run build && now ./build --name=myapp-spa",
        "start": "react-scripts start",
        "build": "react-scripts build",
        ...
      }
    }
    

    Sweet, now all we need to do is call yarn run deploy and our app should stop getting the 404 error pages.

    Step 4: Clean up

    In order to get back to the page we originally requested e.g. myapp.com/something we need to redirect the page to the ?redirect parameter we set earlier in the tutorial. To do this, we need to install the query-string library to parse the parameter. Then you can include the following code into your app in a place that loads after your routing code loads.

    const queryString = require('query-string');
    
    ...
    
    const params = queryString.parse(document.location.search);
    const redirect = params.redirect; // this would be "abcdefg" if the query was "?redirect=abcdefg"
    if (document.location.pathname === '/' && redirect) {
      document.location.assign(`${document.location.origin}/${redirect}`);
    }
    

    It’s important that you do not redirect the user with the above code until after the routing code is cached in the browser. Once you’ve finished, your app should be working just as it should be.

    Basically pasted the whole thing, but make sure to check the article. Apparently there's another possible solution, might be worth trying:

    {
      ...
      "builds": [
        { "src": "build/**", "use": "@now/static" }
      ],
      "routes": [
        {
          "src": "/(.*)\\.(.*)",
          "dest": "/build/$1.$2"
        },
        {
          "src": "/",
          "dest": "/build/index.html"
        },
        {
          "src": "/(.*)",
          "status": 301, "headers": { "Location": "/" }
        }
      ]