Next.js部署至Azure Web App后出现渲染及模块缺失问题
问题描述
通过GitHub Actions将Next.js PWA部署到Azure Web App,CI/CD流水线运行成功,但访问已部署应用时遇到渲染错误。App Service日志流显示以下错误:
2024-10-13T16:07:14.538332001Z at Module._resolveFilename (node:internal/modules/cjs/loader:1145:15) 2024-10-13T16:07:14.538351203Z at Module._load (node:internal/modules/cjs/loader:986:27) 2024-10-13T16:07:14.538357203Z at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:174:12) 2024-10-13T16:07:14.538363004Z at node:internal/main/run_main_module:28:49 { 2024-10-13T16:07:14.538368704Z code: 'MODULE_NOT_FOUND', 2024-10-13T16:07:14.538374204Z requireStack: [] 2024-10-13T16:07:14.538379905Z }
相关配置文件如下:
next.config.js
const withPWA = require('next-pwa')({ dest: 'public', disable: process.env.NODE_ENV === 'development' // add your own icons to src/app/manifest.ts // to re-generate manifest.json, you can visit https://tomitm.github.io/appmanifest/ }); /** @type {import('next').NextConfig} */ module.exports = withPWA({ output: "standalone", swcMinify: true, reactStrictMode: true, eslint: { dirs: ['src'] } });
GitHub Actions工作流配置
name: Deploy Next.js to Azure Web App on: workflow_dispatch: env: NODE_VERSION: 20 NEXT_APP_DIR: src/FinPhlo.Web concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true jobs: build: runs-on: ubuntu-latest defaults: run: working-directory: ${{ env.NEXT_APP_DIR }} steps: - name: Checkout uses: actions/checkout@v4 - name: Detect package manager id: detect-package-manager run: | if [ -f "yarn.lock" ]; then echo "manager=yarn" >> $GITHUB_OUTPUT echo "command=install" >> $GITHUB_OUTPUT echo "runner=yarn" >> $GITHUB_OUTPUT elif [ -f "package.json" ]; then echo "manager=npm" >> $GITHUB_OUTPUT echo "command=ci" >> $GITHUB_OUTPUT echo "runner=npx --no-install" >> $GITHUB_OUTPUT else echo "Unable to determine package manager" exit 1 fi - name: Setup Node uses: actions/setup-node@v4 with: node-version: ${{ env.NODE_VERSION }} cache: ${{ steps.detect-package-manager.outputs.manager }} cache-dependency-path: ${{ env.NEXT_APP_DIR }}/package-lock.json - name: Restore cache uses: actions/cache@v4 with: path: | ${{ env.NEXT_APP_DIR }}/.next/cache key: ${{ runner.os }}-nextjs-${{ hashFiles('${{ env.NEXT_APP_DIR }}/package-lock.json') }}-${{ hashFiles('${{ env.NEXT_APP_DIR }}/**.[jt]s', '${{ env.NEXT_APP_DIR }}/**.[jt]sx') }} restore-keys: | ${{ runner.os }}-nextjs-${{ hashFiles('${{ env.NEXT_APP_DIR }}/package-lock.json') }}- - name: Install dependencies run: ${{ steps.detect-package-manager.outputs.manager }} ${{ steps.detect-package-manager.outputs.command }} - name: Build with Next.js run: ${{ steps.detect-package-manager.outputs.runner }} next build --no-lint - name: Zip artifact for deployment run: zip ../../web.zip ./* .next -qr - name: Upload artifact uses: actions/upload-artifact@v3 with: name: web-app path: web.zip retention-days: 30 deploy-testing: environment: name: Testing url: ${{ steps.deployment.outputs.webapp-url }} runs-on: ubuntu-latest needs: build permissions: id-token: write steps: - name: Download artifact uses: actions/download-artifact@v3 with: name: web-app - name: Azure login uses: azure/login@v2 with: client-id: ${{ secrets.AZURE_CLIENT_ID }} tenant-id: ${{ secrets.AZURE_TENANT_ID }} subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }} - name: Deploy to Testing id: deployment uses: azure/webapps-deploy@v3 with: app-name: finphlo-testing-frontend-app package: web.zip
Terraform配置
module "frontend_linux_web_app" { source = "../../modules/web-app/linux-web-app" basename = "${local.basename}-frontend" resource_group_name = var.resource_group_name location = var.location service_plan_id = data.azurerm_service_plan.linux_uk_south_asp.id site_config = { always_on = true minimum_tls_version = "1.2" ftps_state = "Disabled" http2_enabled = true app_command_line = "node .next/standalone/server.js" application_stack = { node = { node_version = "20-lts" } } } https_only = true identity_type = "SystemAssigned" tags = var.tags }
package.json
{ "name": "fin-phlo", "version": "0.1.0", "private": true, "author": "phlo", "scripts": { "dev": "next dev", "build": "next build", "turbo": "npx turbo@2.0.9", "build:turbo": "npm run turbo run build", "postbuild": "next-sitemap --config next-sitemap.config.js", "start": "next start", "type-check": "tsc --noEmit", "check:turbo": "npm run turbo lint type-check", "format": "prettier --write src", "up-interactive": "npx npm-check-updates -i", "up-latest": "npx npm-check-updates -u --interactive --latest", "release": "cross-env HUSKY=0 standard-version", "push-release": "git push --follow-tags origin main", "prepare": "husky", "sanity-check": "npm run checkTs && npm run lint && npm run prettier:check", "checkTs": "tsc && tsc-strict", "eslint": "eslint --ext js,ts,tsx", "lint": "npm run eslint -- src", "lint:fix": "npm run eslint -- --fix src", "prettier:check": "prettier --check .", "prettify": "prettier --write --ignore-unknown ." }, "dependencies": { "@chakra-ui/icons": "^2.2.3", "@chakra-ui/next-js": "^2.2.0", "@chakra-ui/react": "^2.8.2", "@emotion/react": "^11.13.3", "@emotion/styled": "^11.13.0", "@hookform/resolvers": "^3.9.0", "@types/yup": "^0.32.0", "framer-motion": "^11.5.4", "next": "^14.2.9", "next-auth": "^4.24.8", "next-pwa": "^5.6.0", "react": "^18.3.1", "react-dom": "^18.3.1", "react-hook-form": "^7.53.0", "react-icons": "^5.3.0", "yup": "^1.4.0" }, "devDependencies": { "@commitlint/cli": "^19.4.1", "@commitlint/config-conventional": "19.4.1", "@commitlint/cz-commitlint": "19.4.0", "@types/react": "^18.3.5", "@typescript-eslint/eslint-plugin": "^8.7.0", "commitizen": "^4.3.0", "cross-env": "^7.0.3", "eslint": "^8.57.0", "eslint-config-next": "^14.2.9", "eslint-config-prettier": "^9.1.0", "eslint-config-sznm": "^2.0.3", "husky": "^9.1.5", "lint-staged": "^15.2.10", "next-sitemap": "^4.2.3", "prettier": "^3.3.3", "standard-version": "^9.5.0", "ts-node": "^10.9.2", "typescript": "^5.6.2", "typescript-strict-plugin": "^2.4.4" }, "engines": { "node": ">=20.14.x", "npm": ">=9" }, "packageManager": "npm@9.1.2" }
解决方案
这个MODULE_NOT_FOUND错误是因为Next.js standalone模式下的部署包不完整,加上启动命令路径错误导致的,具体修复步骤如下:
1. 修正部署包的压缩范围
Next.js output: "standalone" 构建后,会生成.next/standalone目录,这个目录包含了运行所需的所有依赖和服务器文件,当前压缩命令的范围和路径结构不符合要求。
修改GitHub Actions中的Zip artifact for deployment步骤:
- name: Zip artifact for deployment run: | # 复制standalone目录及必要资源到统一结构 cp -r .next/standalone ../../ cp -r .next/static ../../standalone/.next/ cp -r public ../../standalone/ cp package.json ../../standalone/ # 进入standalone目录压缩,确保启动路径正确 cd ../../standalone zip -r ../web.zip ./* -q
2. 修正Azure启动命令
当前Terraform中的启动命令路径错误,部署后standalone是应用根目录,正确的启动路径应为node server.js。
修改Terraform的app_command_line:
app_command_line = "node server.js"
3. 优化依赖安装(可选)
为减少部署包体积并确保生产依赖完整,可在安装依赖后添加清理dev依赖的步骤:
在GitHub Actions的Install dependencies步骤后添加:
- name: Prune dev dependencies run: npm prune --production
4. 验证PWA资源路径
next-pwa生成的Service Worker和manifest文件依赖public目录,第一步的压缩命令已包含该目录,确保部署后这些资源可正常访问。
完成以上修改后,重新运行CI/CD流水线,部署后应用即可正常启动。
内容的提问来源于stack exchange,提问作者nop
相关产品推荐
相关产品推荐

