I have a repository which represents the code for an Express Web App which serves a React frontend when started. I tried automating the process of building and deploying using Azure pipelines. The build step succeeds, however the deployment one fails. The repo is set up like this:
my_app/
├── client/
│ ├── src/
│ ├── package.json
│ └── index.js
├── package.json
├── server.js
└── azure-pipelines.yml
And here are the configuration files:
client/package.json
{
"name": "client",
"version": "0.1.0",
"private": true,
"dependencies": {
"#testing-library/jest-dom": "^4.2.4",
"#testing-library/react": "^9.5.0",
"#testing-library/user-event": "^7.2.1",
"react": "^16.13.1",
"react-dom": "^16.13.1",
"react-scripts": "3.4.1"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"eslintConfig": {
"extends": "react-app"
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"proxy": "http://localhost:5001/"
}.
package.json:
{
"name": "my-app",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "cd client/ && npm install && npm run build && cd ../",
"start": "npm install && node server",
"build": "cd client/ && npm install && npm run build && cd ../",
"dev": "node server"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"body-parser": "^1.19.0",
"dotenv": "^8.2.0",
"express": "^4.17.1"
}
}
azure-pipelines.yml:
trigger:
- master
variables:
# Azure Resource Manager connection created during pipeline creation
azureSubscription: 'my_sub_id'
# Web app name
webAppName: 'my_app_name'
# Environment name
environmentName: 'my_env_name'
# Agent VM image name
vmImageName: 'ubuntu-latest'
stages:
- stage: Build
displayName: Build stage
jobs:
- job: Build
displayName: Build
pool:
vmImage: $(vmImageName)
steps:
- task: NodeTool#0
inputs:
versionSpec: '10.x'
displayName: 'Install Node.js'
- script: |
npm install
npm run build --if-present
npm run test --if-present
displayName: 'npm install, build and test'
- task: ArchiveFiles#2
displayName: 'Archive files'
inputs:
rootFolderOrFile: '$(System.DefaultWorkingDirectory)'
includeRootFolder: false
archiveType: zip
archiveFile: $(Build.ArtifactStagingDirectory)/$(Build.BuildId).zip
replaceExistingArchive: true
- upload: $(Build.ArtifactStagingDirectory)/$(Build.BuildId).zip
artifact: drop
- stage: Deploy
displayName: Deploy stage
dependsOn: Build
condition: succeeded()
jobs:
- deployment: Deploy
displayName: Deploy
environment: $(environmentName)
pool:
vmImage: $(vmImageName)
strategy:
runOnce:
deploy:
steps:
- task: AzureWebApp#1
displayName: 'Azure Web App Deploy: referee-management-tool'
inputs:
azureSubscription: $(azureSubscription)
appType: webAppLinux
appName: $(webAppName)
runtimeStack: 'NODE|10.10'
package: $(Pipeline.Workspace)/drop/$(Build.BuildId).zip
startUpCommand: 'npm run start'
The error which I get in Azure Pipelines Deploy:
2020-05-25T15:56:53.2620824Z Error: Cannot find module '../scripts/build'
2020-05-25T15:56:53.2621190Z Require stack:
2020-05-25T15:56:53.2626302Z - /tmp/8d800c3a4e8367c/client/node_modules/.bin/react-scripts
2020-05-25T15:56:53.2627240Z at Function.Module._resolveFilename (internal/modules/cjs/loader.js:982:15)
2020-05-25T15:56:53.2627901Z at Function.resolve (internal/modules/cjs/helpers.js:83:19)
2020-05-25T15:56:53.2628870Z at Object.<anonymous> (/tmp/8d800c3a4e8367c/client/node_modules/.bin/react-scripts:31:23)
2020-05-25T15:56:53.2629532Z at Module._compile (internal/modules/cjs/loader.js:1158:30)
2020-05-25T15:56:53.2630113Z at Object.Module._extensions..js (internal/modules/cjs/loader.js:1178:10)
2020-05-25T15:56:53.2630662Z at Module.load (internal/modules/cjs/loader.js:1002:32)
2020-05-25T15:56:53.2631232Z at Function.Module._load (internal/modules/cjs/loader.js:901:14)
2020-05-25T15:56:53.2631841Z at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:74:12)
2020-05-25T15:56:53.2632406Z at internal/main/run_main_module.js:18:47 {
2020-05-25T15:56:53.2633045Z code: 'MODULE_NOT_FOUND',
2020-05-25T15:56:53.2633823Z requireStack: [ '/tmp/8d800c3a4e8367c/client/node_modules/.bin/react-scripts' ]
2020-05-25T15:56:53.2634320Z }
I have already tried SSH-ing into the machine to test the "node server" command by hand, but for some reason the SSH connection was dropped and I could not re-connect. If you need more information here
is the repo
I solved this problem finally: In the azure-pipelines.yml file, in the Stages->Build->Script section, I added cd client/ && npm install && cd ../ because npm was not installing the packages needed by the client and was performing npm install only in the parent folder, parsing the package.json there. After adding this, everything was fine.
You need to build the react app locally and use the build folder in your express webapp project.
The project structure should look like this:
my_app/
├── client/
│ ├── build/
│ ├── reat_built_files
│
├── package.json
├── server.js
└── azure-pipelines.yml
Reference:
https://devblogs.microsoft.com/premier-developer/deploying-react-apps-to-azure-with-azure-devops/
Related
I have a pipeline in GitHub Actions and it is suggesting that it cannot find Jest despite it working locally.
If I run npm run unit-tests locally it works fine, but in the CI I get the following error:
> jest --group=unit --coverage --verbose
/tmp/unit-tests-2f311f40.sh: 1: jest: not found
name: staging-pipeline
on:
push:
tags:
- 'v*-staging'
env:
CI: true
NODE_ENV: production
jobs:
unit-test:
name: unit-test
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout#master
- name: Unit Tests
run: |
npm install
npm run unit-tests
{
"name": "app",
"version": "1.0.0",
"description": "app",
"main": "",
"scripts": {
"ts-node": "ts-node",
"test": "jest",
"unit-tests": "jest --group=unit --coverage --verbose",
"prisma-generate": "npx prisma generate && npm install #prisma/client"
},
"dependencies": {
"#prisma/client": "^4.3.1",
"axios": "^0.27.2",
"axios-retry": "^3.3.1",
"dotenv": "^16.0.2",
"mongodb": "^4.9.1",
"qs": "^6.11.0",
"winston": "^3.8.1",
"zod": "^3.18.0"
},
"devDependencies": {
"#types/aws-lambda": "^8.10.102",
"#types/jest": "^29.0.0",
"#types/node": "^18.7.15",
"#types/qs": "^6.9.7",
"#typescript-eslint/eslint-plugin": "^5.36.1",
"#typescript-eslint/parser": "^5.36.1",
"esbuild": "^0.15.7",
"eslint": "^8.23.0",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-prettier": "^4.2.1",
"jest": "^28.1.3",
"jest-mock-extended": "^2.0.7",
"jest-runner-groups": "^2.2.0",
"json-schema-to-ts": "^2.5.5",
"prettier": "2.7.1",
"prisma": "^4.3.1",
"ts-jest": "^28.0.8",
"ts-node": "^10.9.1",
"tsconfig-paths": "^4.1.0",
"typescript": "^4.8.2"
},
"author": "",
"license": "MIT"
}
The reason is you installed jest globally on your local machine so Jest command is available in your local machine but not the case in Github action environment(container), so you have to way to fix it :
1.install jest globally in in Github action environment.
jobs:
unit-test:
name: unit-test
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout#master
- name: Unit Tests
run: |
npm install
npm install -g jest
npm run unit-tests
2.or in your package.json file change the npm run unit-test to
./node_modules/.bin/jest --group=unit --coverage --verbos to read
I recommend the second way.
You can see in my CI i have the following variable
NODE_ENV: production
This was causing npm to only install the dependencies and not the devDependencies. equivalant of doing npm install --prod once i removed this env variable, it was able to install jest and use it as normal.
I need to setup build pipeline in AWS amplify for create react app.I couldn't find code snippet to add unit test that uses Jest with React testing library and typescript. Can you please share the amplify.yml that have jest unit test. I have tried below
version: 1
frontend:
phases:
preBuild:
commands: ['npm ci']
build:
commands: 'npm run test' && 'npm run build'
artifacts:
baseDirectory: build
files:
- '**/*'
cache:
paths:
- 'node_modules/**/*'
To add Jest you should first make sure it's installed and listed in your package.json file.
In the root of your project:
npm install jest --save-dev
You should also add this to package.json:
"scripts": {
"test": "jest"
},
Then run Jest locally by running
npm run test
If that works you just need to ensure that jest is available in your build environment.
Package.json:
{
"name": "Your-app-name",
"author": "",
"license": "",
"homepage": "",
"version": "1.0.0",
"description": "xxx",
"scripts": {
"test": "jest"
},
"devDependencies": {
"jest": "^26.6.3",
"uuid": "^8.3.2"
}
}
Hope it helps you some!
The fronted is made with create-react-app and the backend is Node.js with Firebase.
This is my folder structure:
my-app
├── docker-compose.yml
├── client
│ ├── Dockerfile
│ ├── package.json
├── server
│ ├── Dockerfile
│ ├── package.json
docker-compose.yml
version: "3.8"
services:
client:
container_name: client
build: ./client
ports:
- "3000:3000"
tty: true
server:
container_name: server
build: ./server
ports:
- "5000:5000"
client/package.json
{
"name": "react-ui",
"version": "0.1.0",
"private": true,
"dependencies": {
"axios": "^0.19.2",
"node-sass": "^4.14.1",
"normalize.css": "^8.0.1",
"react": "^16.13.1",
"react-dom": "^16.13.1",
"react-redux": "^7.2.1",
"react-scripts": "^3.4.1",
"redux": "^4.0.5"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"eslintConfig": {
"extends": "react-app"
},
"browserslist": [
">0.2%",
"not dead",
"not ie <= 11",
"not op_mini all"
],
"proxy": "http://server:5000",
"secure": false
}
client/Dockerfile
FROM node:lts
WORKDIR /client
COPY package*.json /client/
RUN npm install
COPY . /client/
RUN npm run build
EXPOSE 3000
CMD [ "npm", "start" ]
server/package.json
{
"name": "snake-react-node",
"version": "3.0.0",
"engines": {
"node": "10.x"
},
"scripts": {
"start": "node ./build/index.js",
"build": "tsc",
"dev": "nodemon ./src/index.ts"
},
"dependencies": {
"#types/express": "^4.17.7",
"cors": "^2.8.5",
"dotenv": "^8.2.0",
"express": "^4.17.1",
"firebase-admin": "^9.0.0",
"moment": "^2.27.0",
"rimraf": "^3.0.2",
"ts-node-dev": "^1.0.0-pre.56",
"typescript": "^3.9.7"
},
"license": "MIT",
"devDependencies": {
"nodemon": "^2.0.4",
"npm-run-all": "^4.1.5"
}
}
server/Dockerfile
FROM node:lts
WORKDIR /server
COPY package*.json /server/
RUN npm install
COPY . /server/
RUN npm run build
EXPOSE 5000
CMD [ "npm", "start" ]
When I run docker-compose up on the root directory, two images and two containers get created, one for each Dockerfile. The app runs flawlessly and a production build is created but I would like to be able to use Docker for development too, with live reloads
Since your server container publishes ports: out, you can change the proxy settings in your package.json file to point at this. In your non-Docker host development environment, set
"proxy": "http://localhost:5000"
and then you can npm run dev to have a totally ordinary local live-reloading development server, targeting your backend service that's running in Docker.
There's not really any technical benefits to trying to simulate a local development environment inside a Docker container, especially for a browser-based application. A typical Webpack-based build toolchain doesn't have complex native dependencies that would require special setup, and since the application itself runs in the browser, it can't take advantage of Docker networking and the container itself doesn't provide any of the application's runtime environment. So the only real difference between running the dev server on the host vs. in a container is which version of Node the Webpack build is using, and hopefully this isn't a substantial difference to your application.
You can use bind volume mounts for dev live reload. Make another dev compose file like docker-compose-dev.yml and add the volumes: section.
Whenever code is changed on the host machine using your favorite IDE, the container will pick it up and do the hot reload.
Note: I haven't tested this setup. Just suggesting something you could do.
#docker-compose-dev.yml
version: "3.8"
services:
client:
container_name: client
build: ./client
volumes:
- ./frontend-src:/client/src
ports:
- "3000:3000"
tty: true
server:
container_name: server
build: ./server
ports:
- "5000:5000"
I have developed a simple app using React and Node.js 8 for Google App Engine. It works fine in the Flexible Environment, but if I try to deploy it on the Standard Environment, I am getting "GET / HTTP/1.1" 500 errors. I can't find any more information on what is going wrong beyond that.
How can I configure it so that it will work in the standard environment?
app.standard.yaml
runtime: nodejs8
handlers:
- url: /
script: src/index.js
- url: /src
script: index.js
package.json
{
"name": "eventpub",
"version": "0.1.0",
"private": true,
"engines": {
"node": "8.x.x"
},
"dependencies": {
"node-pre-gyp": "^0.11.0",
"npm": "^5.6.0",
"react": "^16.4.2",
"react-collapsible": "^2.3.1",
"react-dom": "^16.4.2",
"react-json-viewer": "^1.7.1",
"react-scripts": "1.1.5"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test --env=jsdom",
"eject": "react-scripts eject"
}
}
project folder structure
node_modules
public
- public/index.html
- public/manifest.json
src
- src/App.css
- src/App.js
- src/App.test.js
- src/index.css
- src/index.js
- src/registerServiceWorker.js
.gcloudignore
.gitignore
app.flexible.yaml
app.standard.yaml
package.json
package-lock.json
README.md
I solved the issue by building the react app first (npm run build), deploying the already built version to google cloud, and adding handlers for the built app in app.yaml.
handlers:
- url: /
static_files: build/index.html
upload: build/index.html
- url: /
static_dir: build
To me it seems that the issue you are experiencing is due to App Engine Standard for Nodejs still being in beta as mentioned over at https://cloud.google.com/appengine/docs/standard/nodejs/runtime#dependencies
I want to deploy my app build in vue which use CLI 3.0.
My package.json:
"scripts": {
"serve": "vue-cli-service serve",
"postinstall": "npm run build",
"build": "vue-cli-service build",
"lint": "vue-cli-service lint",
"test:unit": "vue-cli-service test:unit",
"test:e2e": "vue-cli-service test:e2e"
}
I added "#vue/cli": "^3.0.0-rc.3" to devDependencies, but is don't see any changes.
Azure deploy result:
> npm run vue-cli-service build
npm ERR! missing script: vue-cli-service
Do you have any ideas?
I havent used azure yet, but try only with
npm run build
instead of
npm run vue-cli-service build
I assume you have a build pipeline that struggles with the message you have given.
I think what you are missing is a simple
npm install
After the install you are able to run
npm run build
Without the npm install before, threre is no vue-cli-service npm can find to build the application. I build my own vue-cli 3.0 app this way an deploy to azure like this from an Azure DevOps build pipeline.
or an other possibility is that you are missing another dependency. Add "#vue/cli-service": "^3.0.1" to your devDependencies. And as Daniel Gonzalez pointed out in the comments, there is no need for a postinstall script.
I have succeed building Vue with Vue CLI 3 in Azure.
Sharing my build file here
Azure pipeline YAML script
resources:
- repo: self
trigger: ['staging']
pool:
vmImage: 'Ubuntu 16.04'
steps:
- task: NodeTool#0
displayName: 'Use Node 10.x'
inputs:
versionSpec: 10.x
- script: |
npm install
npm run build-staging
displayName: 'npm install and build'
env:
NODE_ENV: staging
- task: ArchiveFiles#2
displayName: Archive
inputs:
rootFolderOrFile: '$(build.sourcesDirectory)/dist'
includeRootFolder: false
archiveFile: '$(Build.ArtifactStagingDirectory)/$(Build.SourceVersion)_$(Build.BuildId).zip'
- task: PublishBuildArtifacts#1
displayName: 'Publish Artifact: build'
inputs:
ArtifactName: build
package.json
...
"scripts": {
"serve": "vue-cli-service serve --port 9001",
"build": "vue-cli-service build",
"build-staging": "NODE_ENV=production vue-cli-service build --mode staging",
"build-production": "NODE_ENV=production vue-cli-service build --mode production",
"lint": "vue-cli-service lint"
},
...
Only way I have found to host Vue-CLI build files in Azure is this:
Create a StorageV2 in Azure. Make this a static website (under settings). Make index.html the index document name.
Run: npm run build
Install Azure Storage explorer
Open the new storage you created in step 1 in Azure Storage Explorer, go to Blob Containers, $web
Copy the build files from the ./dist folder to the $web folder.
Open a web browser, enter the endpoint URL.