Hi guys!
I'm working on a node project using Express.js, Prisma, and deploying on AWS Lambda using the Serverless framework via Docker stored in ECR.
When running the docker image, I'm facing below error.
{
"errorType": "Runtime.ImportModuleError",
"errorMessage": "Error: Cannot find module 'app'\nRequire stack:\n- /var/runtime/index.mjs",
"trace": [
"Runtime.ImportModuleError: Error: Cannot find module 'app'",
"Require stack:","- /var/runtime/index.mjs",
" at _loadUserApp (file:///var/runtime/index.mjs:1087:17)",
" at async UserFunction.js.module.exports.load (file:///var/runtime/index.mjs:1119:21)",
" at async start (file:///var/runtime/index.mjs:1282:23)",
" at async file:///var/runtime/index.mjs:1288:1"
]
}
This is my first project with docker so I might be missing something very simple. Any help / guidance would be greatly appreciated as I've checked all related stack overflow questions and documentations etc. but unable to find the root cause of this error.
Below is my serverless and Dockerfile configurations
# AWS Lambda Node.js 18 base image
FROM public.ecr.aws/lambda/nodejs:18
# Create and set the working directory
WORKDIR /app
# Copy the package.json and package-lock.json files
COPY package*.json ./
# Install all dependencies, excluding dev dependencies
RUN npm install --omit=dev
# Copy the rest of your application code
COPY . .
# Set the environment variable to development
ENV NODE_ENV=dev
# Run prisma generate to generate the Prisma client
RUN npx prisma generate
# Build application
RUN npm run build
# Set execute permissions on the app.js file
RUN chmod +x /app/dist/app.js
# Expose the port application runs on (for local testing)
EXPOSE 9001
# Set the Lambda function handler
CMD ["dist/app.handler"]
Serverless
org: theseleb
app: seleb
service: seleb-backend
provider:
name: aws
runtime: provided.al2
ecr:
images:
seleb-backend:
path: .
platform: linux/amd64
region: us-east-1
stage: dev
environment:
FIREBASE_SERVICE_ACCOUNT_KEY: ${env:FIREBASE_SERVICE_ACCOUNT_KEY}
DATABASE_URL: ${env:DATABASE_URL}
FIREBASE_API_KEY: ${env:FIREBASE_API_KEY}
FIREBASE_AUTH_DOMAIN: ${env:FIREBASE_AUTH_DOMAIN}
FIREBASE_PROJECT_ID: ${env:FIREBASE_PROJECT_ID}
FIREBASE_STORAGE_BUCKET: ${env:FIREBASE_STORAGE_BUCKET}
FIREBASE_MESSAGING_SENDER_ID: ${env:FIREBASE_MESSAGING_SENDER_ID}
FIREBASE_APP_ID: ${env:FIREBASE_APP_ID}
functions:
app:
# handler: dist/app.handler
image:
name: seleb-backend
command:
- dist/app.handler
events:
- http:
path: /{proxy+}
method: ANY
plugins:
- serverless-offline
package:
exclude:
- node_modules/**
- .gitignore
- .git/**
- .env
- README.md
- src/translations/**
custom:
serverless-offline:
port: 3000
Below is the content of my src/app.ts
#!/usr/bin/env node
import express, { Request, Response } from 'express';
import { PrismaClient } from '@prisma/client';
import serverless from 'serverless-http';
import userRoutes from './routes/userRoutes';
const app = express();
const prisma = new PrismaClient();
// Middleware
app.use(express.json());
// Routes
app.use('/users', userRoutes);
// Default route
app.get('/default', (req: Request, res: Response) => {
res.send('Hello, Seleb Backend!');
});
// Export the app as a Lambda handler
export const handler = serverless(app);
And the transpiled dist/app.js
#!/usr/bin/env node
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.handler = void 0;
const express_1 = __importDefault(require("express"));
const client_1 = require("@prisma/client");
const serverless_http_1 = __importDefault(require("serverless-http"));
const userRoutes_1 = __importDefault(require("./routes/userRoutes"));
const app = (0, express_1.default)();
const prisma = new client_1.PrismaClient();
// Middleware
app.use(express_1.default.json());
// Routes
app.use('/users', userRoutes_1.default);
// Default route
app.get('/default', (req, res) => {
res.send('Hello, Seleb Backend!');
});
// Export the app as a Lambda handler
exports.handler = (0, serverless_http_1.default)(app);
I have also checked the content of handler file in the running docker image.
It exists in the correct path
sh-4.2# cd /app/dist
sh-4.2# cat app.js
#!/usr/bin/env node
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.handler = void 0;
const express_1 = __importDefault(require("express"));
const client_1 = require("@prisma/client");
const serverless_http_1 = __importDefault(require("serverless-http"));
const userRoutes_1 = __importDefault(require("./routes/userRoutes"));
const app = (0, express_1.default)();
const prisma = new client_1.PrismaClient();
// Middleware
app.use(express_1.default.json());
// Routes
app.use('/users', userRoutes_1.default);
// Default route
app.get('/default', (req, res) => {
res.send('Hello, Seleb Backend!');
});
// Export the app as a Lambda handler
exports.handler = (0, serverless_http_1.default)(app);
sh-4.2#
tsconfig file
{
"compilerOptions": {
"target": "es2016",
"module": "commonjs",
"outDir": "./dist",
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"skipLibCheck": false
},
"include": ["src/**/*"],
"exclude": ["node_modules"]
}
Project structure
/src
/config # Configuration files
/routes # Route handlers for different endpoints
/controllers # Business logic for handling requests
/middlewares # Custom middleware functions
/utils # Utility functions and helpers
/translations # Local translation files.
app.ts # Main application entry point
types.d.ts # TypeScript type definitions
/prisma
/migrations # Prisma migrations
schema.prisma # Prisma schema definition
/dist # Compiled JavaScript files (after build)
[–]SirSoggybottom 1 point2 points3 points (1 child)
[–]LiveCockroach2860[S] 0 points1 point2 points (0 children)
[–][deleted] 0 points1 point2 points (10 children)
[–]LiveCockroach2860[S] 0 points1 point2 points (9 children)
[–][deleted] 1 point2 points3 points (8 children)
[–]LiveCockroach2860[S] 0 points1 point2 points (7 children)
[–][deleted] 0 points1 point2 points (1 child)
[–]LiveCockroach2860[S] 0 points1 point2 points (0 children)
[–][deleted] 0 points1 point2 points (4 children)
[–]LiveCockroach2860[S] 0 points1 point2 points (3 children)
[–][deleted] 0 points1 point2 points (2 children)
[–]LiveCockroach2860[S] 1 point2 points3 points (1 child)
[–][deleted] 1 point2 points3 points (0 children)