typescript - Deploy an Express API written with TypeScript to Azure App Service
问题描述
I created a simple Express JS API with TypeScript and I want to utilize Azure Pipelines for both the CI and CD.
# package.json
{
"name": "sandbox-express",
"version": "0.1.0",
"description": "",
"scripts": {
"build": "tsc -p .",
"build:live": "nodemon --watch 'src/**/*.ts' --exec 'ts-node' src/index.ts",
"start": "npm run build:live",
"test": "mocha"
},
"dependencies": {
"dotenv": "^8.2.0",
"express": "^4.17.1"
},
"devDependencies": {
"@types/express": "^4.17.6",
"@types/mocha": "^7.0.2",
"@types/node": "^14.0.1",
"mocha": "^7.1.2",
"nodemon": "^2.0.4",
"ts-node": "^8.10.1",
"typescript": "^3.9.2"
}
}
# src/app.ts
import express, { Application, Request, Response } from "express";
const app: Application = express();
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.get("/", (req: Request, res: Response) => {
return res.status(200).json({ message: "Hello!" });
});
export { app };
# src/config.ts
import dotenv from "dotenv";
dotenv.config();
# index.ts
import { app } from "./app";
import "./config";
const PORT: string | undefined = process.env.PORT;
if (!PORT) {
console.error("PORT is not set!!!");
process.exit(1);
}
app.listen(Number(PORT), (): void => {
console.log(`Listening on port ${PORT}`);
});
My code is hosted in Azure DevOps and I also added an azure-pipelines.yml
file to trigger a CI build when I push to develop
branch. This is what's inside my YAML file.
# azure-pipelines.yml
trigger:
batch: true
branches:
include:
- develop
variables:
# Node.js version
NODE_VERSION: "12.16.3"
# Agent VM image name
VM_IMAGE_NAME: "ubuntu-16.04"
stages:
- stage: Build
displayName: "Build stage"
jobs:
- job: Build
displayName: "Build"
pool:
vmImage: $(VM_IMAGE_NAME)
steps:
- task: NodeTool@0
displayName: "Install Node.js"
inputs:
versionSpec: $(NODE_VERSION)
- script: |
npm install
npm run build
displayName: "npm install and build"
- task: CopyFiles@2
displayName: "Copy package.json file"
inputs:
sourceFolder: "$(System.DefaultWorkingDirectory)"
contents: "package.json"
targetFolder: "$(Build.ArtifactStagingDirectory)"
cleanTargetFolder: true
- task: CopyFiles@2
displayName: "Copy built files"
inputs:
sourceFolder: "dist"
contents: "**"
targetFolder: "$(Build.ArtifactStagingDirectory)"
- task: PublishBuildArtifacts@1
displayName: "Publish artifact"
inputs:
pathtoPublish: $(Build.ArtifactStagingDirectory)
artifactName: "drop"
The CI build is successful and I get the copied files insize the build artifacts; 4 files -- package.json
, app.js
, config.js
and index.js
; inside the drop
folder.
For the CD part, I did it through Azure Pipelines - Releases UI builder in Azure DevOps.
Task: Deploy Azure App Service
The CD also succeeds in deploying but when I access the web application via the browser, I get a 503 response error.
:( Application Error
If you are the application administrator, you can access the diagnostic resources.
In Azure Portal, I go to my App Service resource and check the "Diagnose and solve problems" section and I get an error like so:
(!) Application logs from instance: RD0003FF65FA79 contain an error or a warning
[1] 2020-05-21T06:43:45 Cannot find module 'express'
And also the following error log:
2020-05-21T06:43:31.232273271Z / _ \ __________ _________ ____
2020-05-21T06:43:31.232279871Z / /_\ \___ / | \_ __ \_/ __ \
2020-05-21T06:43:31.232284571Z / | \/ /| | /| | \/\ ___/
2020-05-21T06:43:31.232289071Z \____|__ /_____ \____/ |__| \___ >
2020-05-21T06:43:31.232294071Z \/ \/ \/
2020-05-21T06:43:31.232298571Z A P P S E R V I C E O N L I N U X
2020-05-21T06:43:31.232302771Z
2020-05-21T06:43:31.232306871Z Documentation: http://aka.ms/webapp-linux
2020-05-21T06:43:31.232310871Z NodeJS quickstart: https://aka.ms/node-qs
2020-05-21T06:43:31.232314871Z NodeJS Version : v12.13.0
2020-05-21T06:43:31.232318872Z Note: Any data outside '/home' is not persisted
2020-05-21T06:43:31.232323072Z
2020-05-21T06:43:31.831224489Z Oryx Version: 0.2.20191105.2, Commit: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx, ReleaseTagName: 20191105.2
2020-05-21T06:43:31.836152521Z Cound not find build manifest file at '/home/site/wwwroot/oryx-manifest.toml'
2020-05-21T06:43:31.837351129Z Could not find operation ID in manifest. Generating an operation id...
2020-05-21T06:43:31.837760531Z Build Operation ID: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
2020-05-21T06:43:33.641043173Z Writing output script to '/opt/startup/startup.sh'
2020-05-21T06:43:34.254679097Z Running #!/bin/sh
2020-05-21T06:43:34.255203901Z
2020-05-21T06:43:34.255216701Z # Enter the source directory to make sure the script runs where the user expects
2020-05-21T06:43:34.255222301Z cd "/home/site/wwwroot"
2020-05-21T06:43:34.255226602Z
2020-05-21T06:43:34.255230802Z export NODE_PATH=$(npm root --quiet -g):$NODE_PATH
2020-05-21T06:43:34.256123609Z if [ -z "$PORT" ]; then
2020-05-21T06:43:34.256135909Z export PORT=8080
2020-05-21T06:43:34.256141209Z fi
2020-05-21T06:43:34.256145309Z
2020-05-21T06:43:34.256901516Z PATH="$PATH:/home/site/wwwroot" node index.js
2020-05-21T06:43:36.534911269Z internal/modules/cjs/loader.js:797
2020-05-21T06:43:36.534950269Z throw err;
2020-05-21T06:43:36.534956469Z ^
2020-05-21T06:43:36.534960769Z
2020-05-21T06:43:36.534964969Z Error: Cannot find module 'express'
2020-05-21T06:43:36.534969069Z Require stack:
2020-05-21T06:43:36.534973169Z - /home/site/wwwroot/app.js
2020-05-21T06:43:36.534977369Z - /home/site/wwwroot/index.js
2020-05-21T06:43:36.534981569Z at Function.Module._resolveFilename (internal/modules/cjs/loader.js:794:15)
2020-05-21T06:43:36.534986269Z at Function.Module._load (internal/modules/cjs/loader.js:687:27)
2020-05-21T06:43:36.534997169Z at Module.require (internal/modules/cjs/loader.js:849:19)
2020-05-21T06:43:36.535001569Z at require (internal/modules/cjs/helpers.js:74:18)
2020-05-21T06:43:36.535005669Z at Object. (/home/site/wwwroot/app.js:7:33)
2020-05-21T06:43:36.535010169Z at Module._compile (internal/modules/cjs/loader.js:956:30)
2020-05-21T06:43:36.535014269Z at Object.Module._extensions..js (internal/modules/cjs/loader.js:973:10)
2020-05-21T06:43:36.535018569Z at Module.load (internal/modules/cjs/loader.js:812:32)
2020-05-21T06:43:36.535022569Z at Function.Module._load (internal/modules/cjs/loader.js:724:14)
2020-05-21T06:43:36.535026770Z at Module.require (internal/modules/cjs/loader.js:849:19) {
2020-05-21T06:43:36.535031070Z code: 'MODULE_NOT_FOUND',
2020-05-21T06:43:36.535035170Z requireStack: [ '/home/site/wwwroot/app.js', '/home/site/wwwroot/index.js' ]
2020-05-21T06:43:36.535039370Z }
So I guess my question is how do I install Express and all the required packages in the Release CD section of my pipeline?