CodeGenieApp / serverless-express

Run Express and other Node.js frameworks on AWS Serverless technologies such as Lambda, API Gateway, Lambda@Edge, and more.
https://codegenie.codes
Apache License 2.0
5.14k stars 667 forks source link

Imports not resolving properly during runtime #329

Closed smasilamani-cfins closed 3 years ago

smasilamani-cfins commented 3 years ago

Hello

We are using this package for one for our serverless typescript projects and have been facing issue with the import. During runtime none of the imports from this package are resolving and we have to do a patch to make it work, Please find below the respective code and error we get unless we run the below command after npm install. Please advise.

Command to fix : cp -r ./node_modules/@vendia/serverless-express/src/*.js ./node_modules/@vendia/serverless-express

If we run the above command after npm install, then it works fine.

Error:

TypeError: serverless_express_1.createServer is not a function
    at bootstrapServer (/mnt/c/Repos/iq-submission-service/.webpack/service/src/webpack:/iq-submission-service/src/index.ts:38:10)
    at processTicksAndRejections (node:internal/process/task_queues:93:5)
    at handler (/mnt/c/Repos/iq-submission-service/.webpack/service/src/webpack:/iq-submission-service/src/index.ts:77:18)
    at InProcessRunner.run (/mnt/c/Repos/iq-submission-service/node_modules/serverless-offline/dist/lambda/handler-runner/in-process-runner/InProcessRunner.js:199:24)
    at LambdaFunction.runHandler (/mnt/c/Repos/iq-submission-service/node_modules/serverless-offline/dist/lambda/LambdaFunction.js:325:20)
    at hapiHandler (/mnt/c/Repos/iq-submission-service/node_modules/serverless-offline/dist/events/http/HttpServer.js:521:18)
    at module.exports.internals.Manager.execute (/mnt/c/Repos/iq-submission-service/node_modules/@hapi/hapi/lib/toolkit.js:45:28)
    at Object.internals.handler (/mnt/c/Repos/iq-submission-service/node_modules/@hapi/hapi/lib/handler.js:46:20)
    at exports.execute (/mnt/c/Repos/iq-submission-service/node_modules/@hapi/hapi/lib/handler.js:31:20)
    at Request._lifecycle (/mnt/c/Repos/iq-submission-service/node_modules/@hapi/hapi/lib/request.js:312:32)
    at Request._execute (/mnt/c/Repos/iq-submission-service/node_modules/@hapi/hapi/lib/request.js:221:9)
TypeError: serverless_express_1.createServer is not a function
    at bootstrapServer (/mnt/c/Repos/iq-submission-service/.webpack/service/src/webpack:/iq-submission-service/src/index.ts:38:10)
    at processTicksAndRejections (node:internal/process/task_queues:93:5)
    at handler (/mnt/c/Repos/iq-submission-service/.webpack/service/src/webpack:/iq-submission-service/src/index.ts:77:18)
    at InProcessRunner.run (/mnt/c/Repos/iq-submission-service/node_modules/serverless-offline/dist/lambda/handler-runner/in-process-runner/InProcessRunner.js:199:24)
    at LambdaFunction.runHandler (/mnt/c/Repos/iq-submission-service/node_modules/serverless-offline/dist/lambda/LambdaFunction.js:325:20)
    at hapiHandler (/mnt/c/Repos/iq-submission-service/node_modules/serverless-offline/dist/events/http/HttpServer.js:521:18)
    at module.exports.internals.Manager.execute (/mnt/c/Repos/iq-submission-service/node_modules/@hapi/hapi/lib/toolkit.js:45:28)
    at Object.internals.handler (/mnt/c/Repos/iq-submission-service/node_modules/@hapi/hapi/lib/handler.js:46:20)
    at exports.execute (/mnt/c/Repos/iq-submission-service/node_modules/@hapi/hapi/lib/handler.js:31:20)
    at Request._lifecycle (/mnt/c/Repos/iq-submission-service/node_modules/@hapi/hapi/lib/request.js:312:32)
    at Request._execute (/mnt/c/Repos/iq-submission-service/node_modules/@hapi/hapi/lib/request.js:221:9)
offline: Failure: serverless_express_1.createServer is not a function
TypeError: serverless_express_1.createServer is not a function
    at bootstrapServer (/mnt/c/Repos/iq-submission-service/.webpack/service/src/webpack:/iq-submission-service/src/index.ts:38:10)
    at processTicksAndRejections (node:internal/process/task_queues:93:5)
    at handler (/mnt/c/Repos/iq-submission-service/.webpack/service/src/webpack:/iq-submission-service/src/index.ts:77:18)
    at InProcessRunner.run (/mnt/c/Repos/iq-submission-service/node_modules/serverless-offline/dist/lambda/handler-runner/in-process-runner/InProcessRunner.js:199:24)
    at LambdaFunction.runHandler (/mnt/c/Repos/iq-submission-service/node_modules/serverless-offline/dist/lambda/LambdaFunction.js:325:20)
    at hapiHandler (/mnt/c/Repos/iq-submission-service/node_modules/serverless-offline/dist/events/http/HttpServer.js:521:18)
    at module.exports.internals.Manager.execute (/mnt/c/Repos/iq-submission-service/node_modules/@hapi/hapi/lib/toolkit.js:45:28)
    at Object.internals.handler (/mnt/c/Repos/iq-submission-service/node_modules/@hapi/hapi/lib/handler.js:46:20)
    at exports.execute (/mnt/c/Repos/iq-submission-service/node_modules/@hapi/hapi/lib/handler.js:31:20)
    at Request._lifecycle (/mnt/c/Repos/iq-submission-service/node_modules/@hapi/hapi/lib/request.js:312:32)
    at Request._execute (/mnt/c/Repos/iq-submission-service/node_modules/@hapi/hapi/lib/request.js:221:9)

Webpack:

const path = require('path');
const slsw = require('serverless-webpack');
const TsConfigPathsPlugin = require('tsconfig-paths-webpack-plugin');
const TerserPlugin = require('terser-webpack-plugin');
const entries = {};
const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');
const HappyPack = require('happypack');

Object.keys(slsw.lib.entries).forEach((key) => (entries[key] = ['./source-map-install.js', slsw.lib.entries[key]]));

module.exports = {
    mode: slsw.lib.webpack.isLocal ? 'development' : 'production',
    entry: entries,
    devtool: 'source-map',
    optimization: {
        minimizer: [
            new TerserPlugin({
                terserOptions: {
                    mangle: true,
                    keep_classnames: true,
                    sourceMap: true
                },
                parallel: true
            })
        ]
    },
    plugins: [
        new ForkTsCheckerWebpackPlugin({ typescript: { memoryLimit: 4096 } }),
        new HappyPack({
            id: 'ts',
            threads: 10,
            loaders: [
                {
                    path: 'ts-loader',
                    query: { happyPackMode: true }
                }
            ]
        })
    ],
    resolve: {
        plugins: [
            new TsConfigPathsPlugin({
                configFile: './tsconfig.json'
            })
        ],
        extensions: ['.js', '.jsx', '.json', '.ts', '.tsx']
    },
    output: {
        libraryTarget: 'commonjs',
        path: path.join(__dirname, '.webpack'),
        filename: '[name].js'
    },
    target: 'node',
    module: {
        rules: [
            // all files with a `.ts` or `.tsx` extension will be handled by `ts-loader`
            {
                test: /\.ts|\.tsx$/,
                loader: 'ts-loader',
                exclude: [/node_modules/],
                options: {
                    // disable type checker - we will use it in fork plugin
                    transpileOnly: true
                }
                // include: __dirname
            }
        ]
    },
    externals: [
        'oracledb',
        'mongodb',
        'mysql',
        'pg',
        'pg-native',
        'pg-query-stream',
        'redis',
        'sqlite3',
        'mssql',
        'mysql2',
        '@sap/hana-client',
        'hdb-pool',
        'typeorm-aurora-data-api-driver',
        'better-sqlite3',
        'react-native-sqlite-storage',
        'sql.js',
        'grpc',
        'kafkajs',
        'mqtt',
        'nats',
        'amqplib',
        'amqp-connection-manager',
        'fastify-swagger'
    ],
    ignoreWarnings: [
        // This is optional, but it hides noisey warnings
        { module: /node_modules\/*/, message: /Critical dependency: the request of a dependency is an expression/ },
        (warning) => false
    ]
};

Code: (only the interested part)

import { Handler } from 'aws-lambda';
import Express from 'express';
import { Server } from 'http';

import { INestApplication } from '@nestjs/common';
import { ExpressAdapter } from '@nestjs/platform-express';
import { DSServerConstants } from '@shared/models/server.constants';
import { createServer, proxy } from '@vendia/serverless-express';

import { bootstrap } from './main';

let cachedServer: Server;

const binaryMimeTypes: string[] = [
    'application/javascript',
    'application/octet-stream',
    'application/xml',
    'font/eot',
    'font/opentype',
    'font/otf',
    'image/jpeg',
    'image/png',
    'image/svg+xml',
    'text/comma-separated-values',
    'text/css',
    'text/html',
    'text/javascript',
    'text/plain',
    'text/text',
    'text/xml'
];

const bootstrapServer: () => Promise<Server> = async () => {
    try {
        const expressApp: any = Express();
        const expAdapter: ExpressAdapter = new ExpressAdapter(expressApp);
        const app: INestApplication = await bootstrap(expAdapter);
        return createServer(app.getHttpAdapter().getInstance(), null, binaryMimeTypes);
    } catch (error) {
        console.error(error);
        throw error;
    }
};
brettstack commented 3 years ago

Hey, thanks for the report. I wonder if this is something with Typescript configuration? I can do simple:

import { createServer, proxy } from '@vendia/serverless-express';

console.log(createServer, proxy)

with my babel config and I get:

[Function: createServer] [Function: proxy]

The way the package is structured, it has an index.js at the top-level https://github.com/vendia/serverless-express/blob/master/index.js that simply re-exports the index.js in src/index.js which is where those functions are defined.

If you run ls node_modules/@vendia/serverless-express what do you get (is the index.js there)?

brettstack commented 3 years ago

I just tried with basic TypeScript by running:

npx tsc lambda.ts
node lambda.js

And I got the same [Function: createServer] [Function: proxy] output.

If you don't want to spend time figuring out what's going on (why the top-level index.js isn't exporting src/index.js) you can simply import like import { createServer, proxy } from '@vendia/serverless-express/src', however, this isn't guaranteed to continue to work forever (though it's unlikely we'll change/break it)

smasilamani-cfins commented 3 years ago

Thank you for getting back on this quickly, here is my tsconfig.json and we do not use babel at all.

{
    "compilerOptions": {
        "module": "commonjs",
        "declaration": true,
        "removeComments": true,
        "emitDecoratorMetadata": true,
        "experimentalDecorators": true,
        "esModuleInterop": true,
        "target": "ES2017",
        "sourceMap": true,
        "outDir": "./dist",
        "baseUrl": ".",
        "incremental": true,
        "noUnusedLocals": true,
        "noUnusedParameters": true,
        "noImplicitReturns": true,
        "noImplicitThis": true,
        "lib": ["ES2019"],
        "skipLibCheck": true,
        "alwaysStrict": true,
        "forceConsistentCasingInFileNames": true,
        "isolatedModules": true,
        "moduleResolution": "node",
        "noFallthroughCasesInSwitch": true,
        "resolveJsonModule": true,
        "strict": false,
        "paths": {
            "@app/*": ["src/app/*"],
            "@clearance/*": ["src/clearance/*"],
            "@submission/*": ["src/submission/*"],
            "@shared/*": ["src/shared/*"],
            "@external_services/*": ["src/external_services/*"]
        }
    },
    "exclude": ["node_modules", ".serverless", ".webpack", "_warmup", ".vscode", "dist"]
}

ls command :

$ ls -ltr node_modules/@vendia/serverless-express
total 28
-rwxrwxrwx 1 root root  5161 Oct 26  1985 README.md    
-rwxrwxrwx 1 root root  3609 Oct 26  1985 package.json 
-rwxrwxrwx 1 root root    59 Oct 26  1985 middleware.js
-rwxrwxrwx 1 root root 11357 Oct 26  1985 LICENSE      
-rwxrwxrwx 1 root root    54 Oct 26  1985 index.js     
-rwxrwxrwx 1 root root  2508 Oct 26  1985 CHANGELOG.md 
drwxrwxrwx 1 root root  4096 Jan  4 17:59 src

Without running my copy command all I can see is undefined (last line in the output) Code:

import { Handler } from 'aws-lambda';
import Express from 'express';
import { Server } from 'http';

import { INestApplication } from '@nestjs/common';
import { ExpressAdapter } from '@nestjs/platform-express';
import { DSServerConstants } from '@shared/models/server.constants';
import { createServer, proxy } from '@vendia/serverless-express';

import { bootstrap } from './main';

console.log(createServer, proxy);

Output:

offline: Offline [http for lambda] listening on http://localhost:3002
offline: Function names exposed for local invocation by aws-sdk:
           * index: ds-iq-submission-service-local-index

   ┌─────────────────────────────────────────────────────────────────────────┐
   │                                                                         │
   │   ANY | http://localhost:3003/local                                     │
   │   POST | http://localhost:3003/2015-03-31/functions/index/invocations   │
   │   ANY | http://localhost:3003/local/{proxy*}                            │
   │   POST | http://localhost:3003/2015-03-31/functions/index/invocations   │
   │                                                                         │
   └─────────────────────────────────────────────────────────────────────────┘

Watchpack Error (initial scan): Error: EACCES: permission denied, lstat '/mnt/c/hiberfil.sys'
Watchpack Error (initial scan): Error: EACCES: permission denied, lstat '/mnt/c/pagefile.sys'
Watchpack Error (initial scan): Error: EACCES: permission denied, lstat '/mnt/c/swapfile.sys'
offline: [HTTP] server ready: http://localhost:3003 �
offline:
offline: Enter "rp" to replay the last request
asset src/index.js 22.9 MiB [emitted] (name: src/index) 1 related asset
cached modules 20 MiB [cached] 3590 modules
runtime modules 1.03 KiB 5 modules
./node_modules/agentkeepalive/index.js 169 bytes [code generated]
webpack compiled successfully in 3486 ms
Serverless: Watching for changes...
No issues found.

offline: ANY /local/api-json (λ: index)
undefined undefined

Since my copy command works fine, we should be good for now and when I get time, I can look into it in detail.

Thanks again.