无法在 Azure App 服务上部署 React JS 应用程序

Posted

技术标签:

【中文标题】无法在 Azure App 服务上部署 React JS 应用程序【英文标题】:Unable to deploy React JS application on Azure App service 【发布时间】:2020-12-08 15:05:27 【问题描述】:

我正在浏览一些链接以在 azure app 服务上部署 React Js 应用程序。但是我在部署应用程序时遇到了一些问题。

我已将 web.config 文件等所有必要的内容添加到 public 文件夹,并将构建目录添加到工作区。

Deploying web app on azure app service

Deploy Node.js to Azure App Service using Visual Studio Code

执行了所有步骤,但当我尝试在 azure 应用服务上部署时出现以下错误。在部署之前我会运行这些命令

npm run build.

2020-08-19T10:44:45.762075166Z A P P   S E R V I C E   O N   L I N U X
2020-08-19T10:44:45.762079567Z 
2020-08-19T10:44:45.762083667Z Documentation: http://aka.ms/webapp-linux
2020-08-19T10:44:45.762088167Z NodeJS quickstart: https://aka.ms/node-qs
2020-08-19T10:44:45.762092268Z NodeJS Version : v12.16.3
2020-08-19T10:44:45.762096468Z Note: Any data outside '/home' is not persisted
2020-08-19T10:44:45.762100768Z 
2020-08-19T10:44:45.789282727Z Found build manifest file at '/home/site/wwwroot/oryx-manifest.toml'. Deserializing it...
2020-08-19T10:44:45.792738514Z Build Operation ID: |OtQwveNuO0A=.83a2ec6c_
2020-08-19T10:44:47.255197638Z Writing output script to '/opt/startup/startup.sh'
2020-08-19T10:44:47.960307930Z Running #!/bin/sh
2020-08-19T10:44:47.960336532Z 
2020-08-19T10:44:47.960345833Z # Enter the source directory to make sure the script runs where the user expects
2020-08-19T10:44:47.960355334Z cd "/home/site/wwwroot"
2020-08-19T10:44:47.960363235Z 
2020-08-19T10:44:47.960370735Z export NODE_PATH=$(npm root --quiet -g):$NODE_PATH
2020-08-19T10:44:47.960378436Z if [ -z "$PORT" ]; then
2020-08-19T10:44:47.960386136Z      export PORT=8080
2020-08-19T10:44:47.960393937Z fi
2020-08-19T10:44:47.960401238Z 
2020-08-19T10:44:47.960408638Z echo Found tar.gz based node_modules.
2020-08-19T10:44:47.960416339Z extractionCommand="tar -xzf node_modules.tar.gz -C /node_modules"
2020-08-19T10:44:47.960424040Z echo "Removing existing modules directory from root..."
2020-08-19T10:44:47.960431740Z rm -fr /node_modules
2020-08-19T10:44:47.960439141Z mkdir -p /node_modules
2020-08-19T10:44:47.960446542Z echo Extracting modules...
2020-08-19T10:44:47.960453842Z $extractionCommand
2020-08-19T10:44:47.960461243Z export NODE_PATH="/node_modules":$NODE_PATH
2020-08-19T10:44:47.960468943Z export PATH=/node_modules/.bin:$PATH
2020-08-19T10:44:47.960476344Z if [ -d node_modules ]; then
2020-08-19T10:44:47.960483745Z     mv -f node_modules _del_node_modules || true
2020-08-19T10:44:47.960491245Z fi
2020-08-19T10:44:47.960498446Z 
2020-08-19T10:44:47.960505546Z if [ -d /node_modules ]; then
2020-08-19T10:44:47.960524748Z     ln -sfn /node_modules ./node_modules 
2020-08-19T10:44:47.960532849Z fi
2020-08-19T10:44:47.960540149Z 
2020-08-19T10:44:47.960547550Z echo "Done."
2020-08-19T10:44:47.960554951Z npm start
2020-08-19T10:44:48.258132115Z Found tar.gz based node_modules.
2020-08-19T10:44:48.258154316Z Removing existing modules directory from root...
2020-08-19T10:44:48.260461807Z Extracting modules...
2020-08-19T10:44:48.262765098Z tar (child): node_modules.tar.gz: Cannot open: No such file or directory
2020-08-19T10:44:48.262778299Z tar (child): Error is not recoverable: exiting now
2020-08-19T10:44:48.262970515Z tar: Child returned status 2
2020-08-19T10:44:48.262983816Z tar: Error is not recoverable: exiting now
2020-08-19T10:44:48.290740216Z Done.
2020-08-19T10:44:48.512406278Z npm info it worked if it ends with ok
2020-08-19T10:44:48.512836614Z npm info using npm@6.14.4
2020-08-19T10:44:48.512976126Z npm info using node@v12.16.3
2020-08-19T10:44:48.578204629Z npm info lifecycle adal_appp@0.1.0~prestart: adal_appp@0.1.0
2020-08-19T10:44:48.584464048Z npm info lifecycle adal_appp@0.1.0~start: adal_appp@0.1.0
2020-08-19T10:44:48.589867495Z 
2020-08-19T10:44:48.589881796Z > adal_appp@0.1.0 start /home/site/wwwroot
2020-08-19T10:44:48.589887297Z > react-scripts start
2020-08-19T10:44:48.589891697Z 
2020-08-19T10:44:48.597331914Z sh: 1: react-scripts: not found
2020-08-19T10:44:48.598224588Z npm info lifecycle adal_appp@0.1.0~start: Failed to exec start script
2020-08-19T10:44:48.599091959Z npm ERR! code ELIFECYCLE
2020-08-19T10:44:48.599182267Z npm ERR! syscall spawn
2020-08-19T10:44:48.599258573Z npm ERR! file sh
2020-08-19T10:44:48.599314678Z npm ERR! errno ENOENT
2020-08-19T10:44:48.600738196Z npm ERR! adal_appp@0.1.0 start: `react-scripts start`
2020-08-19T10:44:48.600749897Z npm ERR! spawn ENOENT
2020-08-19T10:44:48.600754497Z npm ERR! 
2020-08-19T10:44:48.600758798Z npm ERR! Failed at the adal_appp@0.1.0 start script.
2020-08-19T10:44:48.600763398Z npm ERR! This is probably not a problem with npm. There is likely additional logging output above.
2020-08-19T10:44:48.605436585Z npm timing npm Completed in 125ms
2020-08-19T10:44:48.605621800Z 
2020-08-19T10:44:48.605672405Z npm ERR! A complete log of this run can be found in:
2020-08-19T10:44:48.605750311Z npm ERR!     /root/.npm/_logs/2020-08-19T10_44_48_601Z-debug.log

但问题是相同的应用程序在本地使用以下命令完美运行 npm install , npm start.

只是为了验证npm run build 之后生成的构建是否有效,是否尝试使用以下命令从构建目录运行应用程序

npm install -g serve

然后

serve -s build

然后应用程序在浏览器中打开。

【问题讨论】:

【参考方案1】:

从日志看来,这不是Node.js 应用程序,而是react 应用程序。因此,react-scripts start 是 Azure 应用服务一无所知。

当您在 localhost 上运行 react 应用程序时,它由 development server 提供支持,这确实是一个 Node.js 服务器,但是一旦您使用 npm run build 构建它以用于生产,它只不过是一个 index.html由一堆.js 文件和样式表驱动的文件。它本身没有网络功能。

另一方面,serve 是一个单独的故事。根据他们在npmjs.com 的描述:假设您想提供静态站点、单页应用程序或只是一个静态文件(无论是在您的设备上还是在本地网络上),这个包都是您的正确选择.

但这不是类似 Azure 的方法。

但是,在生产中,如果您使用的是 Azure,我建议使用 Azure Blob Storage v2,它具有静态站点托管功能。在 Blob 存储中启用静态站点托管,并将 build 文件夹部署在名为 $web 的容器中。当然,如果您将vscodeAzure plugin 一起使用,所有这些都是自动完成的。假设您已通过 vscode 登录 Azure,请右键单击 build 文件夹并选择 deploy to static site,按照步骤操作即可使用您的 react 应用程序。

但是,如果您在react 应用程序旁边确实有一个Node.js express 后端,那么您可以将build 文件夹放入与node_modules 文件夹相同级别的Node.js 项目中并使用静态路由让前端和后端作为一个包工作。明确定义一个路由来告诉express 在被要求时使用index.html 文件进行响应。然后你可以将整个包部署到Azure App Service

const express = require('express');
const path = require('path');
const port = process.env.PORT || 3006;

const app = express();

app.use(express.json())
app.use(bodyParser.urlencoded(extended: true));
app.use(bodyParser.json(extended: true));

app.use(express.static(__dirname + '/build'));
app.get('/', (req, res) =>  
  res.sendFile(path.join(__dirname + '/build/index.html'))
);

// Then prefix your API endpoints with /api
app.get('/api/user/:id', (req, res) => 
  // Code to get user by id
);

app.post('/api/user', (req, res) => 
  // Code to save user
);

app.listen(port, () => 
  console.log(`App bootstrapped on port $port...`);
);

/ 被击中时,index.html 被服务。 API 调用按照/api/* 的定义提供。我发现这种机制很多时候都很有用。

祝你好运。

【讨论】:

后端是spring boot。是的,它是一个反应应用程序。在此之前已经进行了多次部署,但从未遇到过这个问题。【参考方案2】:

在谷歌搜索found solution 之后。我们需要在 Linux 机器的应用服务配置中的启动命令中添加以下命令。

pm2 serve /home/site/wwwroot --no-daemon

步骤:

- Go to App Service

- Navigate to Configuration

- Click on General Settings

- add the above command in Start up command, click on save 

- then restart the server

【讨论】:

以上是关于无法在 Azure App 服务上部署 React JS 应用程序的主要内容,如果未能解决你的问题,请参考以下文章

无法将 React 应用(构建)文件夹部署到应用服务 Azure

azure App 服务部署为代码还是容器?

尝试使用 Github Actions 工作流将 React App 部署到 Azure,但在 TypeScript 中出现错误

在 Azure 应用服务上部署 Spring Boot jar

如何使用 Azure App 服务部署任务通过 VSTS 将多个 jar 文件上传到 Azure

在 Azure 上部署 Asp.NET Core Web App