Joost Luijben
Joost Luijben

Reputation: 173

Deploy create-react-app with azure pipelines

I am trying to deploy a react app I created with create-react-app locally to azure. I am trying to do this with azure pipelines.

The code I have so far:

# Node.js React Web App to Linux on Azure
# Build a Node.js React app and deploy it to Azure as a Linux web app.
# Add steps that analyze code, save build artifacts, deploy, and more:
# https://learn.microsoft.com/azure/devops/pipelines/languages/javascript

trigger:
- master
- azure-pipelines

variables:
  # Azure Resource Manager connection created during pipeline creation
  azureSubscription: ###

  # Web app name
  webAppName: 'rafe-react'

  # Environment name
  environmentName: 'rafe-react'

  # Agent VM image name
  vmImageName: 'ubuntu-latest'
  System.debug: true
steps:
- task: NodeTool@0
  inputs:
    versionSpec: '10.1'
- task: Npm@1
  inputs:
    command: 'install'
- script: |
    npm install
    npm run build
- task: ArchiveFiles@2
  inputs:
    rootFolderOrFile: '$(Build.BinariesDirectory)'
    includeRootFolder: true
    archiveType: 'zip'
    archiveFile: '$(Build.ArtifactStagingDirectory)/$(Build.BuildId).zip'
    replaceExistingArchive: true
- task: AzureRmWebAppDeployment@4
  inputs:
    ConnectionType: 'AzureRM'
    azureSubscription: $(azureSubscription)
    appType: 'webAppLinux'
    WebAppName: 'rafe-react'
    packageForLinux: '$(Build.ArtifactStagingDirectory)/**/*.zip'
    RuntimeStack: 'NODE|10.1'
    StartupCommand: 'serve -s build'
    enableCustomDeployment: true

Now when I run this, it deploys successfully. However, when I go to my app in azure and look at the log it gives me this error:

/opt/startup/startup.sh: 11: /opt/startup/startup.sh: serve: not found.

full error log:

2019-12-05T11:48:46.270966320Z   _____                               
2019-12-05T11:48:46.271002720Z   /  _  \ __________ _________   ____  
2019-12-05T11:48:46.271008020Z  /  /_\  \___   /  |  \_  __ \_/ __ \ 
2019-12-05T11:48:46.271012420Z /    |    \/    /|  |  /|  | \/\  ___/ 
2019-12-05T11:48:46.271016320Z \____|__  /_____ \____/ |__|    \___  >
2019-12-05T11:48:46.271020420Z         \/      \/                  \/ 
2019-12-05T11:48:46.271024320Z A P P   S E R V I C E   O N   L I N U X
2019-12-05T11:48:46.271028420Z 
2019-12-05T11:48:46.271032020Z Documentation: http://aka.ms/webapp-linux
2019-12-05T11:48:46.271035820Z NodeJS quickstart: https://aka.ms/node-qs
2019-12-05T11:48:46.271039720Z NodeJS Version : v10.1.0
2019-12-05T11:48:46.271043320Z Note: Any data outside '/home' is not persisted
2019-12-05T11:48:46.271047320Z 
2019-12-05T11:48:46.387569226Z Oryx Version: 0.2.20191105.2, Commit: 67e159d71419415435cb5d10c05a0f0758ee8809, ReleaseTagName: 20191105.2
2019-12-05T11:48:46.387911428Z Cound not find build manifest file at '/home/site/wwwroot/oryx-manifest.toml'
2019-12-05T11:48:46.388236829Z Could not find operation ID in manifest. Generating an operation id...
2019-12-05T11:48:46.388474931Z Build Operation ID: 3c2e1218-c95a-418e-94c1-ce778f1b0604
2019-12-05T11:48:47.903969109Z Writing output script to '/opt/startup/startup.sh'
2019-12-05T11:48:48.190534098Z Running #!/bin/sh
2019-12-05T11:48:48.284305986Z 
2019-12-05T11:48:48.284659388Z # Enter the source directory to make sure the script runs where the user expects
2019-12-05T11:48:48.284671288Z cd "/home/site/wwwroot"
2019-12-05T11:48:48.284675988Z 
2019-12-05T11:48:48.284680088Z export NODE_PATH=$(npm root --quiet -g):$NODE_PATH
2019-12-05T11:48:48.284935189Z if [ -z "$PORT" ]; then
2019-12-05T11:48:48.284944789Z      export PORT=8080
2019-12-05T11:48:48.284949089Z fi
2019-12-05T11:48:48.285155290Z 
2019-12-05T11:48:48.285164490Z PATH="$PATH:/home/site/wwwroot" serve -s build
2019-12-05T11:48:50.410579239Z /opt/startup/startup.sh: 11: /opt/startup/startup.sh: serve: not found

I have tried to replace the startupCommand with npm run build and use the InlineScript parameter (see the Azure documentation and also this site) for serve -s build, but got a permission denied error.

Does anyone know how to successfully deploy a react app to azure with azure pipelines?

Upvotes: 1

Views: 3803

Answers (3)

32423hjh32423
32423hjh32423

Reputation: 3088

I had the same problem. My Azure Pipeline was fine and the build and deploy worked fine and published the build folder to the /home/site/wwwroot folder.

When you create your App Service just install the PHP stack and you don't have to worry about serving anything because index.html is picked up by which ever webserver is running on there already for the PHP stack.

Slightly hacky but it works

Upvotes: 2

Joost Luijben
Joost Luijben

Reputation: 173

I got it working. So what I had to do was serving the static files from the build folder. To let the react-router work on azure you have to create a file called ecosystem.config.js. At this file to your public folder. If pm2 environment detects this file it executes it. See here for reference. This file executes the serve command. It looks as follows:

module.exports = {
  apps: [
    {
      script: "npx serve -s"
    }
  ]
};

The azure-pipelines.yml looks as follows


trigger:
- none

variables:

  # Azure Resource Manager connection created during pipeline creation
  azureSubscription: ###

  # Web app name
  webAppNameStaging: 'rafeFrontendWebApp-staging'
  webAppNameProduction: 'rafeFrontendWebApp-production'

  # Environment name
  environmentNameStaging: 'staging'
  environmentNameProduction: 'production'

  # Agent VM image name
  vmImageName: 'ubuntu-latest'
  System.Debug: true
stages:
- stage: Build
  displayName: Build stage
  pool:
    vmImage: $(vmImageName)
  jobs:  
  - job: Build_Staging
    displayName: Build Staging
    steps:
      - script: |
         npm install react-scripts
         npm run build
      - task: CopyFiles@2
        displayName: 'Copy Files to: $(Build.ArtifactStagingDirectory)'
        inputs:
          SourceFolder: '$(System.DefaultWorkingDirectory)/build'
          TargetFolder: '$(Build.ArtifactStagingDirectory)'
      - task: PublishPipelineArtifact@1
        inputs:
          targetPath: $(System.DefaultWorkingDirectory)/build
          artifact: 'drop'
          publishLocation: 'pipeline'
- stage: Deploy_Staging
  displayName: Deploy staging
  dependsOn: Build
  condition: succeeded()
  jobs:
  - deployment: Deploy
    displayName: Deploy staging
    environment: $(environmentNameStaging)
    strategy:
      runOnce:
        deploy:
            steps:            
              - task: AzureRmWebAppDeployment@4
                inputs:
                  ConnectionType: 'AzureRM'
                  azureSubscription: $(azureSubscription)
                  appType: 'webAppLinux'
                  WebAppName: $(webAppNameStaging)
                  packageForLinux: $(Pipeline.Workspace)/drop
                  RuntimeStack: 'NODE|lts'

Since the Build.ArtifactStagingDirectory is cleared on a deploy you have to use the PublishPipelineArtifact task to still be able to access the files in a deployment

Upvotes: 1

ssedwards
ssedwards

Reputation: 129

As an alternative you can use the following command directly in the main yml file.

StartupCommand: 'pm2 serve /home/site/wwwroot --no-daemon --spa'

Upvotes: 2

Related Questions