You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何正确将create-react-app构建的ReactJS应用部署到Azure Web App?

规范部署Create React App到Azure Web App的正确方式

我来帮你梳理下更标准的部署方案,针对Create React App这类单页应用(SPA),Azure提供了两种更合适的方式,比你目前依赖serve的方法更符合最佳实践:

方案一:Azure静态网站托管(首推)

这是最适合SPA的部署方式,因为Create React App构建后产出的是纯静态文件,完全不需要Node.js服务器支撑:

  • 先在本地执行构建命令生成静态文件:npm run build
  • 登录Azure门户,创建静态网站资源(属于存储账户下的功能)
  • 将build文件夹里的所有内容上传到静态网站的$web容器(可以用Azure Storage Explorer可视化操作,或者用Azure CLI命令批量上传)
  • 关键配置:设置路由规则,因为SPA需要把所有非静态资源的请求重定向到index.html,否则刷新页面会404。在静态网站的设置里添加一条规则:
    • 源路径:/*
    • 目标路径:/index.html
    • 类型:200

这种方式成本更低、性能更优,完全贴合SPA的特性,是官方推荐的部署方式。

方案二:Azure Web App(适合需联动后端或Web App功能的场景)

如果因为业务需求必须用Azure Web App,也不需要依赖serve,可以利用Azure Web App自带的IIS静态文件服务和URL重写规则来实现:

第一步:添加Web.config配置文件

在你的React项目根目录创建web.config文件,添加URL重写规则,确保所有非静态文件的请求都转发到index.html:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
  <system.webServer>
    <rewrite>
      <rules>
        <rule name="React Routes" stopProcessing="true">
          <match url=".*" />
          <conditions logicalGrouping="MatchAll">
            <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
            <add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
            <!-- 如果你的项目有API路由,添加这一行排除API请求,避免被重写 -->
            <add input="{REQUEST_URI}" pattern="^/(api)" negate="true" />
          </conditions>
          <action type="Rewrite" url="/index.html" />
        </rule>
      </rules>
    </rewrite>
    <!-- 确保一些特殊后缀的文件能被正确识别 -->
    <staticContent>
      <mimeMap fileExtension=".json" mimeType="application/json" />
      <mimeMap fileExtension=".svg" mimeType="image/svg+xml" />
    </staticContent>
  </system.webServer>
</configuration>

第二步:优化你的deploy.sh脚本

修改部署脚本,确保在部署过程中完成依赖安装、项目构建,然后将build文件夹的内容同步到wwwroot:

#!/bin/bash
# ----------------------
# KUDU Deployment Script
# Version: 1.0.17
# ----------------------
# Helpers
# -------
exitWithMessageOnError () {
  if [ ! $? -eq 0 ]; then
    echo "An error has occurred during web site deployment."
    echo $1
    exit 1
  fi
}
# Prerequisites
# -------------
# Verify node.js installed
hash node 2>/dev/null
exitWithMessageOnError "Missing node.js executable, please install node.js, if already installed make sure it can be reached from current environment."
# Setup
# -----
SCRIPT_DIR="${BASH_SOURCE[0]%\*}"
SCRIPT_DIR="${SCRIPT_DIR%/*}"
ARTIFACTS=$SCRIPT_DIR/../artifacts
KUDU_SYNC_CMD=${KUDU_SYNC_CMD//"}

if [[ ! -n "$DEPLOYMENT_SOURCE" ]]; then
  DEPLOYMENT_SOURCE=$SCRIPT_DIR
fi

if [[ ! -n "$NEXT_MANIFEST_PATH" ]]; then
  NEXT_MANIFEST_PATH=$ARTIFACTS/manifest
  if [[ ! -n "$PREVIOUS_MANIFEST_PATH" ]]; then
    PREVIOUS_MANIFEST_PATH=$NEXT_MANIFEST_PATH
  fi
fi

if [[ ! -n "$DEPLOYMENT_TARGET" ]]; then
  DEPLOYMENT_TARGET=$ARTIFACTS/wwwroot
else
  KUDU_SERVICE=true
fi

if [[ ! -n "$KUDU_SYNC_CMD" ]]; then
  # Install kudu sync
  echo Installing Kudu Sync
  npm install kudusync -g --silent
  exitWithMessageOnError "npm failed"

  if [[ ! -n "$KUDU_SERVICE" ]]; then
    # In case we are running locally this is the correct location of kuduSync
    KUDU_SYNC_CMD=kuduSync
  else
    # In case we are running on kudu service this is the correct location of kuduSync
    KUDU_SYNC_CMD=$APPDATA/npm/node_modules/kuduSync/bin/kuduSync
  fi
fi

# Node Helpers
# ------------
selectNodeVersion () {
  if [[ -n "$KUDU_SELECT_NODE_VERSION_CMD" ]]; then
    SELECT_NODE_VERSION="$KUDU_SELECT_NODE_VERSION_CMD \"$DEPLOYMENT_SOURCE\" \"$DEPLOYMENT_TARGET\" \"$DEPLOYMENT_TEMP\""
    eval $SELECT_NODE_VERSION
    exitWithMessageOnError "select node version failed"

    if [[ -e "$DEPLOYMENT_TEMP/__nodeVersion.tmp" ]]; then
      NODE_EXE=`cat "$DEPLOYMENT_TEMP/__nodeVersion.tmp"`
      exitWithMessageOnError "getting node version failed"
    fi

    if [[ -e "$DEPLOYMENT_TEMP/__npmVersion.tmp" ]]; then
      NPM_JS_PATH=`cat "$DEPLOYMENT_TEMP/__npmVersion.tmp"`
      exitWithMessageOnError "getting npm version failed"
    fi

    if [[ ! -n "$NODE_EXE" ]]; then
      NODE_EXE=node
    fi

    NPM_CMD=\"$NODE_EXE\" \"$NPM_JS_PATH\"
  else
    NPM_CMD=npm
    NODE_EXE=node
  fi
}

##################################################################################################################################
# Deployment
# ----------
echo Handling node.js deployment.

# 2. Select node version (保留自动选择版本的逻辑,避免本地与Azure版本不一致)
selectNodeVersion

# 3. Install npm packages (需要安装所有依赖,包括dev依赖,因为要执行build)
if [ -e "$DEPLOYMENT_SOURCE/package.json" ]; then
  cd "$DEPLOYMENT_SOURCE"
  echo "Running $NPM_CMD install"
  eval $NPM_CMD install
  exitWithMessageOnError "npm install failed"
  
  # 执行build命令生成静态文件
  echo "Running $NPM_CMD run build"
  eval $NPM_CMD run build
  exitWithMessageOnError "build failed"
  cd - > /dev/null
fi

# 1. KuduSync: 将build文件夹内容同步到wwwroot
if [[ "$IN_PLACE_DEPLOYMENT" -ne "1" ]]; then
  "$KUDU_SYNC_CMD" -v 50 -f "$DEPLOYMENT_SOURCE/build" -t "$DEPLOYMENT_TARGET" -n "$NEXT_MANIFEST_PATH" -p "$PREVIOUS_MANIFEST_PATH" -i ".git;.hg;.deployment;deploy.sh"
  exitWithMessageOnError "Kudu Sync failed"
fi

##################################################################################################################################
echo "Finished successfully."

第三步:配置Azure Web App

  • 不需要设置启动命令,Azure Web App会自动通过IIS托管wwwroot里的静态文件,web.config的重写规则会处理SPA的路由问题
  • 在Azure门户的Web App配置>常规设置里,设置Node.js版本和本地项目使用的版本一致,避免构建时出现兼容性问题

为什么你的原有方法不够规范?

  • 额外引入serve依赖,增加了部署复杂度和不必要的服务器资源消耗
  • 用Node.js服务器托管静态文件,不如Azure Web App自带的IIS静态文件服务高效
  • 不符合SPA的部署最佳实践:纯静态文件应该直接由专门的静态文件服务托管,不需要额外的Node.js中间层

内容的提问来源于stack exchange,提问作者AQuirky

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.06 10:12:49