3

I have been trying to deploy a Server-side rendered react app I built with NextJS on Azure. I set up the Azure pipeline and release successfully but after running it the app doesn't seem to load up when I went to the azure website URL. The build file content is different from a client rendered app. Please share a resource or explanation about deploying SSR React apps (on Azure).

I used this resource to set up the pipeline and I encountered no error but the URL is still not loading the app.

James D
  • 125
  • 4
  • 14
  • You could have a look at this video: https://www.youtube.com/watch?v=Ny5vJRfQito&feature=youtu.be – Doris Lv Feb 01 '21 at 02:05
  • @James Does Doris's answer helps? If so, you could [Accept it as an Answer](https://meta.stackexchange.com/questions/5234/how-does-accepting-an-answer-work/5235#5235), it could help other community members who get the same issues, thanks. – Edward Han-MSFT Feb 02 '21 at 06:22
  • @EdwardHan-MSFT Yes, I'm all good now. The answer worked – James D Feb 03 '21 at 14:42
  • 1
    @EdwardHan-MSFT This works but the app is very slow in production. takes like 6-10 mins to load and an average of 6 secs to move from one page to another. Please share a possible fix. – James D Feb 05 '21 at 09:44

2 Answers2

8

As mentioned by @James in the comment in Doris's answer, using a custom server.js in a Next.js app would make it slower in production because the routes aren't pre-built. Using next build followed by next start would solve this issue. But for you to be able to do that, you should not have a server.js.

And as per Microsoft documentation for deploying Node JS / Next JS application on Azure Linux web app, the recommended way is to use PM2 rather than using npm start (or) node server.js.

So you don't need server.js or web.config. All you need to do is to have a file called ecosystem.config.js with the below content

module.exports = {
  apps: [
    {
      name: "my-nextJs-site",
      script: "./node_modules/next/dist/bin/next",
      args: "start -p " + (process.env.PORT || 3000),
      watch: false,
      autorestart: true,
    },
  ],
};

and have the startup command for your Azure app to be this

pm2 --no-daemon start /home/site/wwwroot/ecosystem.config.js

and no change in your package.json scripts

"scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",

Azure Windows App Service

pm2 is not available in Azure Windows Service - it uses IIS Server. Check out the following answer and its linked questions.

Other useful resources:

Gangula
  • 5,193
  • 4
  • 30
  • 59
  • its possible that your path is not correct. Check out the folder strucutre of your project in [Azure Kudu Environment](https://github.com/projectkudu/kudu/wiki/Accessing-the-kudu-service). Additional info - [Kudu service overview](https://learn.microsoft.com/en-us/azure/app-service/resources-kudu) – Gangula Sep 07 '22 at 07:08
2

You need two file: server.js and web.config, and modify package.json like below. I've answered a question about deploy nextjs app step by step, you could have a look at this.

package.json modify.

"scripts": {
    "dev": "node server.js",
    "build": "next build",
    "start": "node server.js"

server.js (create this file with the code below:)

const { createServer } = require('http')
const next = require('next')

const port = parseInt(process.env.PORT, 10) || 3000
const dev = process.env.NODE_ENV !== 'production'
const app = next({ dev })
const handle = app.getRequestHandler()

app.prepare().then(() => {
  createServer((req, res) => {
    const parsedUrl = new URL(req.url, 'http://w.w')
    const { pathname, query } = parsedUrl

    if (pathname === '/a') {
      app.render(req, res, '/a', query)
    } else if (pathname === '/b') {
      app.render(req, res, '/b', query)
    } else {
      handle(req, res, parsedUrl)
    }
  }).listen(port, (err) => {
    if (err) throw err
    console.log(`> Ready on http://localhost:${port}`)
  })
})

web.config (create this file with the code below:)

<?xml version="1.0" encoding="utf-8"?>
<!--
     This configuration file is required if iisnode is used to run node processes behind
     IIS or IIS Express.  For more information, visit:
     https://github.com/tjanczuk/iisnode/blob/master/src/samples/configuration/web.config
-->

<configuration>
  <system.webServer>
    <!-- Visit http://blogs.msdn.com/b/windowsazure/archive/2013/11/14/introduction-to-websockets-on-windows-azure-web-sites.aspx for more information on WebSocket support -->
    <webSocket enabled="false" />
    <handlers>
      <!-- Indicates that the server.js file is a node.js site to be handled by the iisnode module -->
      <add name="iisnode" path="server.js" verb="*" modules="iisnode"/>
    </handlers>
    <rewrite>
      <rules>
        <!-- Do not interfere with requests for node-inspector debugging -->
        <rule name="NodeInspector" patternSyntax="ECMAScript" stopProcessing="true">
          <match url="^server.js\/debug[\/]?" />
        </rule>

        <!-- First we consider whether the incoming URL matches a physical file in the /public folder -->
        <rule name="StaticContent">
          <action type="Rewrite" url="public{REQUEST_URI}"/>
        </rule>

        <!-- All other URLs are mapped to the node.js site entry point -->
        <rule name="DynamicContent">
          <conditions>
            <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="True"/>
          </conditions>
          <action type="Rewrite" url="server.js"/>
        </rule>
      </rules>
    </rewrite>

    <!-- 'bin' directory has no special meaning in node.js and apps can be placed in it -->
    <security>
      <requestFiltering>
        <hiddenSegments>
          <remove segment="bin"/>
        </hiddenSegments>
      </requestFiltering>
    </security>

    <!-- Make sure error responses are left untouched -->
    <httpErrors existingResponse="PassThrough" />

    <!--
      You can control how Node is hosted within IIS using the following options:
        * watchedFiles: semi-colon separated list of files that will be watched for changes to restart the server
        * node_env: will be propagated to node as NODE_ENV environment variable
        * debuggingEnabled - controls whether the built-in debugger is enabled
      See https://github.com/tjanczuk/iisnode/blob/master/src/samples/configuration/web.config for a full list of options
    -->
    <!--<iisnode watchedFiles="web.config;*.js"/>-->
  </system.webServer>
</configuration> 
Doris Lv
  • 3,083
  • 1
  • 5
  • 14
  • 1
    This works but the app is very slow in production. takes like 6-10 mins to load and an average of 6 secs to move from one page to another. Please share a possible fix. – James D Feb 05 '21 at 09:41