Back

Explore Courses Blog Tutorials Interview Questions
0 votes
2 views
in AWS by (19.1k points)

Why is webpack not including the node_module libraries in the build when they are imported into the index file?

webpack is still a bit of a black art for me that I have not fully grasped, so below is an explanation of that I am trying to achieve.

I am building a test application to run as serverless code on an AWS Lambda Node server. The goal is to keep the deployment package a small as possible by having 1 or more chunks and no node_modules folder on the server.

I am writing in Typescript v3 and using webpack v4 to create a bundle for the server.

Here is my directory structure:

  • dist/
  • node_modules/
  • src/index.ts
  • package.json
  • tsconfig.json
  • tslint.json
  • webpack.config.js

here is an excerpt from my package.json

  "dependencies": {

    "moment": "^2.22.2"

  },

  "devDependencies": {

    "@types/aws-lambda": "^8.10.15",

    "@types/node": "^10.12.2",

    "awesome-typescript-loader": "^5.2.1",

    "aws-lambda": "^0.1.2",

    "source-map-loader": "^0.2.4",

    "ts-node": "^7.0.1",

    "tslint": "^5.11.0",

    "tslint-loader": "^3.5.4",

    "typescript": "^3.1.6",

    "webpack": "^4.25.1",

    "webpack-bundle-analyzer": "^3.0.3",

    "webpack-cli": "^3.1.2",

    "webpack-node-externals": "^1.7.2"

  }

my index.ts that I am trying to bundle:

import { Handler } from "aws-lambda";

import moment from "moment";

const handler: Handler = async ( event: any ) => {

    const stamp = moment().format( "x" );

    console.log( `process: ${ process.env.NAME } called at ${ stamp }` );

    console.log( event );

    return {

        body: "process completed",

        statusCode: 200

    };

};

export { handler };

my tsconfig.json:

{

    "compilerOptions": {

        "outDir": "./dist",

        "sourceMap": true,

        "noImplicitAny": true,

        "module": "commonjs",

        "target": "es5",

        "allowJs": true,

        "pretty": false,

        "removeComments": true,

        "esModuleInterop": true,

        "moduleResolution": "node",

        "types": [

            "node"

        ],

        "lib": [

            "es5",

            "es6",

            "dom"

        ]

    },

    "include": [

        "src/**/*.ts"

    ],

    "exclude": [

        "node_modules"

    ]

}

finally here is my webpack.config.js:

const path = require( "path" );

const UglifyJSPlugin = require( "uglifyjs-webpack-plugin" );

const nodeExternals = require( "webpack-node-externals" );

const ROOT = path.resolve( __dirname, "src" );

const DESTINATION = path.resolve( __dirname, "dist" );

module.exports = {

    context: ROOT,

    mode: "production",

    entry: {

        index: "./index.ts"

    },

    target: "node",

    externals: [ nodeExternals() ],

    optimization: {

        minimizer: [

            new UglifyJSPlugin( {

                uglifyOptions: {

                    compress: true,

                    mangle: false,

                    toplevel: false,

                    keep_classnames: true,

                    keep_fnames: true

                }

            } )

        ],

        splitChunks: {

            cacheGroups: {

                node_vendors: {

                    test: /[\\/]node_modules[\\/]/,

                    chunks: "all",

                    priority: 1

                }

            }

        }

    },

    output: {

        filename: "[name].js",

        libraryTarget: "commonjs2",

        path: DESTINATION

    },

    resolve: {

        extensions: [ ".ts", ".js" ],

        modules: [ ROOT, "node_modules" ]

    },

    module: {

        rules: [

            {

                enforce: "pre",

                test: /\.js$/,

                use: "source-map-loader"

            },

            {

                enforce: "pre",

                test: /\.ts$/,

                exclude: /node_modules/,

                use: "tslint-loader"

            },

            {

                test: /\.ts$/,

                exclude: [ /node_modules/ ],

                use: "awesome-typescript-loader"

            }

        ]

    },

    devtool: "cheap-module-source-map",

    devServer: {}

};

When I run webpack I get the following console output:

Version: webpack 4.25.1

Time: 4856ms

Built at: 2018-11-08 15:41:09

   Asset      Size Chunks             Chunk Names

index.js  3.83 KiB     0 [emitted] index

Entrypoint index = index.js

[0] ./index.ts 3.11 KiB {0} [built]

[1] external "moment" 42 bytes {0} [built]

When I deploy this to AWS Lambda I and call the function I get the following error:

{

    "errorMessage": "Cannot find module 'moment'",

    "errorType": "Error",

    "stackTrace": [

    "Function.Module._load (module.js:474:25)",

    "Module.require (module.js:596:17)",

    "require (internal/module.js:11:18)",

    "Object.<anonymous> (/var/task/index.js:1:3963)",

    "__webpack_require__ (/var/task/index.js:1:323)",

    "Object.<anonymous> (/var/task/index.js:1:3595)",

    "__webpack_require__ (/var/task/index.js:1:323)",

    "module.exports.__awaiter.__awaiter.P (/var/task/index.js:1:1650)",

    "Object.<anonymous> (/var/task/index.js:1:1695)"

    ]

}

1 Answer

0 votes
by (44.4k points)

Usage of nodeExternals will declare every single dependency as external. When executing node_modules has to be present.

Related questions

0 votes
1 answer

Want to get 50% Hike on your Salary?

Learn how we helped 50,000+ professionals like you !

0 votes
1 answer

Browse Categories

...