In this article, we'll explore common pitfalls and potential solutions when working with (using ts-node) in Development Pipelines. This piece is particularly valuable for developers encountering problems during the deployment process, often characterized by obscure error messages and puzzling behavior. We'll take a practical, step-by-step approach, investigating these issues, delving into their root causes, and outlining strategies for fixing them. TypeScript Azure Serverless Whether you're a seasoned developer, DevOps engineer, or a curious beginner eager to learn more about TypeScript and Azure DevOps, this comprehensive guide will serve as a valuable tool in navigating the intricacies of ts-node deployments in Azure pipelines. Problem Working on and building our backend system on different cloud solutions ( , Azure) our team has faced several issues on serverless deployment. Restart GCP Using as a runtime in-memory with the latest TypeScript 5.0.4 and nodejs18, we got errors after successfully building our app using dev.azure.com pipelines (Image 1). ts-node ts-js compiler The errors during app startup: 2023-05-25T10:52:24.326355260Z _____ 2023-05-25T10:52:24.326400861Z / _ \ __________ _________ ____ 2023-05-25T10:52:24.326406761Z / /_\ \\___ / | \_ __ \_/ __ \ 2023-05-25T10:52:24.326410361Z / | \/ /| | /| | \/\ ___/ 2023-05-25T10:52:24.326413761Z \____|__ /_____ \____/ |__| \___ > 2023-05-25T10:52:24.326417661Z \/ \/ \/ 2023-05-25T10:52:24.326420961Z A P P S E R V I C E O N L I N U X 2023-05-25T10:52:24.326424361Z 2023-05-25T10:52:24.326427461Z Documentation: http://aka.ms/webapp-linux 2023-05-25T10:52:24.326430661Z NodeJS quickstart: https://aka.ms/node-qs 2023-05-25T10:52:24.326433761Z NodeJS Version : v18.16.0 2023-05-25T10:52:24.326436961Z Note: Any data outside '/home' is not persisted 2023-05-25T10:52:24.326440161Z 2023-05-25T10:52:26.504451955Z Starting OpenBSD Secure Shell server: sshd. 2023-05-25T10:52:26.807519399Z Starting periodic command scheduler: cron. 2023-05-25T10:52:26.863716274Z Cound not find build manifest file at '/home/site/wwwroot/oryx-manifest.toml' 2023-05-25T10:52:26.866811884Z Could not find operation ID in manifest. Generating an operation id... 2023-05-25T10:52:26.868247288Z Build Operation ID: 796ee1ba-542e-43f1-9f6c-1e7a5e2e9815 2023-05-25T10:52:27.139574733Z Environment Variables for Application Insight's IPA Codeless Configuration exists.. 2023-05-25T10:52:27.156085084Z Writing output script to '/opt/startup/startup.sh' 2023-05-25T10:52:27.229878114Z Running #!/bin/sh 2023-05-25T10:52:27.229938514Z 2023-05-25T10:52:27.229945514Z # Enter the source directory to make sure the script runs where the user expects 2023-05-25T10:52:27.229950214Z cd "/home/site/wwwroot" 2023-05-25T10:52:27.229954114Z 2023-05-25T10:52:27.229957814Z export NODE_PATH=/usr/local/lib/node_modules:$NODE_PATH 2023-05-25T10:52:27.229979514Z if [ -z "$PORT" ]; then 2023-05-25T10:52:27.230057715Z export PORT=8080 2023-05-25T10:52:27.230063815Z fi 2023-05-25T10:52:27.230067915Z 2023-05-25T10:52:27.246143265Z PATH="$PATH:/home/site/wwwroot" yarn start 2023-05-25T10:52:30.491250324Z yarn run v1.17.3 2023-05-25T10:52:30.896237571Z $ ts-node src/app.ts 2023-05-25T10:52:31.521499168Z node:internal/modules/cjs/loader:1078 2023-05-25T10:52:31.577313557Z throw err; 2023-05-25T10:52:31.577384758Z ^ 2023-05-25T10:52:31.577391958Z 2023-05-25T10:52:31.577396558Z Error: Cannot find module './util' 2023-05-25T10:52:31.577400858Z Require stack: 2023-05-25T10:52:31.577404958Z - /home/site/wwwroot/node_modules/.bin/ts-node 2023-05-25T10:52:31.577484858Z at Module._resolveFilename (node:internal/modules/cjs/loader:1075:15) 2023-05-25T10:52:31.577494058Z at Module._load (node:internal/modules/cjs/loader:920:27) 2023-05-25T10:52:31.577498458Z at Module.require (node:internal/modules/cjs/loader:1141:19) 2023-05-25T10:52:31.577502658Z at require (node:internal/modules/cjs/helpers:110:18) 2023-05-25T10:52:31.577506858Z at Object.<anonymous> (/home/site/wwwroot/node_modules/.bin/ts-node:9:16) 2023-05-25T10:52:31.577511558Z at Module._compile (node:internal/modules/cjs/loader:1254:14) 2023-05-25T10:52:31.577551858Z at Module._extensions..js (node:internal/modules/cjs/loader:1308:10) 2023-05-25T10:52:31.577557158Z at Module.load (node:internal/modules/cjs/loader:1117:32) 2023-05-25T10:52:31.577561358Z at Module._load (node:internal/modules/cjs/loader:958:12) 2023-05-25T10:52:31.577565458Z at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:81:12) { 2023-05-25T10:52:31.577569658Z code: 'MODULE_NOT_FOUND', 2023-05-25T10:52:31.577573658Z requireStack: [ '/home/site/wwwroot/node_modules/.bin/ts-node' ] 2023-05-25T10:52:31.577577758Z } 2023-05-25T10:52:31.577586558Z 2023-05-25T10:52:31.577591058Z Node.js v18.16.0 2023-05-25T10:52:31.684203528Z error Command failed with exit code 1. The key points of these logs are: Error: Cannot find module './util' /home/site/wwwroot/node_modules/.bin/ts-node requireStack: [ '/home/site/wwwroot/node_modules/.bin/ts-node' ] error Command failed with exit code 1. Spending hours of googling and searching for similar problems on Stack Overflow, we cannot define the nature of the issue. Trying different pipeline setups, and switching from Linux based web app to Windows does not help. The same code works fine in the case of serverless Google Cloud, but for some reason does not work on serverless Azure. Finally, we got a solution: We switch to a basic compiler and everything worked fine. “ts-node” “tsc“ In this article, I will explain some details of switching your existing project, that uses to a native compiler. ts-node tsc Tiny ts-node project First, we need a basic project that has only one file and ts-node on it (Image 2). The folder contains our app.ts file: src import * as http from 'http'; const server = http.createServer((req, res) => { res.statusCode = 200; res.setHeader('Content-Type', 'text/plain'); res.end('Hello Hackernoon. We are using ts on Azure!\n'); }); server.listen(8080, '0.0.0.0', () => { console.log('Server running at http://0.0.0.0:8080/'); }); In we have added folder and because compiling from to will be inside the Azure pipeline process. .gitignore dist node_modules ts js The content of package.json: { "name": "ts-nodejs", "version": "1.0.0", "description": "", "scripts": { "start": "ts-node src/app.ts" }, "keywords": [], "author": "", "license": "ISC", "dependencies": { "ts-node": "^10.9.1", "typescript": "^5.0.4" }, "devDependencies": { "@types/node": "^20.2.3" } } We have installed only ts-node and typescript packages. First, we need to modify the start command and create a new command and add it here: { "name": "tsc-nodejs", "version": "1.0.0", "description": "", "scripts": { "start": "node dist/app.js", "build": "tsc" }, "keywords": [], "author": "", "license": "ISC", "dependencies": { "ts-node": "^10.9.1", "typescript": "^5.0.4" }, "devDependencies": { "@types/node": "^20.2.3" } } All project pre-compiled files will be stored in the folder, which will execute our entry point of the app (app.js). the command executes or compiler. It gets settings from file. dist nodejs Build tsc tsconfig.json Our settings will be: { "compilerOptions": { "target": "ES2019", "module": "commonjs", "esModuleInterop": true, "allowUnreachableCode": false, "allowUnusedLabels": false, "noFallthroughCasesInSwitch": true, "noImplicitAny": false, "noImplicitReturns": true, "noImplicitThis": true, "noUnusedLocals": true, "strictBindCallApply": true, "strictFunctionTypes": true, "strictNullChecks": true, "strictPropertyInitialization": true, "removeComments": true, "strict": true, "skipLibCheck": true, "forceConsistentCasingInFileNames": true, "outDir": "dist", "baseUrl": "./src", "rootDir": "src", "paths": { "@extensions/*": ["handlers/extensions/*"], "@services/*": ["services/*"], "@docs/*": ["docs/*"], "@server/*": ["server/*"], "@handlers/*": ["handlers/*"], "@app/*": ["*"], }, "experimentalDecorators": true, "emitDecoratorMetadata": true, "typeRoots": [ "./types", "./node_modules/@types" ], "allowSyntheticDefaultImports": true, "lib": ["es5", "es6", "dom"], "moduleResolution": "node", }, "include": [ "**/*" ], "exclude": [ "dist", "node_modules" ] } The most important parts of the tsconfig.json: "noEmit": false, "include": [ "**/*" ], "outDir": "dist", "baseUrl": "./src", "rootDir": "src", Be sure, that is false (by default is false), is the name of the folder, where will save precompiled files, and is , where your project is (don’t save project files outside folder, because will ignore them). noEmit outDir tsc baseUrl rootDir src src tsc In this example, I also have added in case you have it on an existing project, but this tiny project does not use its allies, so you can ignore them. If you use allies on your project, please change them inside from: paths package.json "_moduleAliases": { "@extensions": "src/handlers/extensions", "@services": "src/services", "@docs": "src/docs", "@server": "src/server", "@handlers": "src/handlers", "@app": "src" } to this: "_moduleAliases": { "@extensions": "dist/handlers/extensions", "@services": "dist/services", "@docs": "dist/docs", "@server": "dist/server", "@handlers": "dist/handlers", "@app": "dist" } Finally, you need to change basic config from: azure-pipelines.yaml # Node.js Express Web App to Linux on Azure # Build a Node.js Express app and deploy it to Azure as a Linux web app. # Add steps that analyze code, save build artifacts, deploy, and more: # https://docs.microsoft.com/azure/devops/pipelines/languages/javascript trigger: - master variables: # Azure Resource Manager connection created during pipeline creation azureSubscription: '<Your sub>' # Web app name webAppName: '<Your webAppName>' # Environment name environmentName: 'Your webAppName>' # 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: '18.x' displayName: 'Install Node.js' - script: | npm install yarn yarn 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: Your webAppName>' inputs: azureSubscription: $(azureSubscription) appType: webAppLinux appName: $(webAppName) runtimeStack: 'NODE|18-lts' package: $(Pipeline.Workspace)/drop/$(Build.BuildId).zip startUpCommand: 'yarn start' to this: # Node.js Express Web App to Linux on Azure # Build a Node.js Express app and deploy it to Azure as a Linux web app. # Add steps that analyze code, save build artifacts, deploy, and more: # https://docs.microsoft.com/azure/devops/pipelines/languages/javascript trigger: - master variables: # Azure Resource Manager connection created during pipeline creation azureSubscription: 'Your sub' # Web app name webAppName: 'Your webAppName>' # Environment name environmentName: 'Your webAppName>' # 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: '18.x' displayName: 'Install Node.js' - script: | npm install yarn yarn yarn build 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: Your webAppName>' inputs: azureSubscription: $(azureSubscription) appType: webAppLinux appName: $(webAppName) runtimeStack: 'NODE|18-lts' package: $(Pipeline.Workspace)/drop/$(Build.BuildId).zip startUpCommand: 'yarn start' Finally, and see what will happen! git push Conclusion Hope this article will save a lot of time during debugging process in case of using with . It's clear that the complexities of TypeScript deployments within Azure DevOps pipelines can present unique challenges. However, by taking a systematic approach and learning to understand the underpinnings of ts-node and Azure pipelines, we can effectively troubleshoot and resolve these obstacles. ts-node Azure Node.js Serverless Apps In this article, we dove into the most common issues developers encounter, broke down the intricacies of these problems, and provided step-by-step solutions. Remember, it's not about avoiding problems altogether – it's about developing the ability to diagnose, troubleshoot, and solve them effectively when they inevitably arise. Moving forward, take this knowledge and apply it to your DevOps processes. Not only will you increase your productivity, but you'll also be contributing to a smoother, more efficient pipeline for your entire team. There's always more to learn in this ever-evolving field, and this guide is just one step towards mastering Azure DevOps with TypeScript. Stay curious, keep learning, and happy coding!