serverless-heaven / serverless-webpack

Serverless plugin to bundle your lambdas with Webpack
MIT License
1.72k stars 417 forks source link

webpack isn't bundling entire directory #497

Open jatinvmehta opened 5 years ago

jatinvmehta commented 5 years ago

I am creating serverless lambda API and using webpack so can use ES6 feature. My webpack.config.js is

const slsw = require('serverless-webpack');
const path = require('path');
const nodeExternals = require('webpack-node-externals');

module.exports = {
  entry: slsw.lib.entries,
  target: 'node',
  // Generate sourcemaps for proper error messages
  devtool: 'source-map',
  // Since 'aws-sdk' is not compatible with webpack,
  // we exclude all node dependencies
  externals: [nodeExternals()],
  mode: slsw.lib.webpack.isLocal ? 'development' : 'production',
  optimization: {
    // We no not want to minimize our code.
    minimize: false,
  },
  performance: {
    // Turn off size warnings for entry points
    hints: false,
  },
  // Run babel on all .js files and skip those in node_modules
  module: {
    rules: [
      {
        test: /\.js$/,
        loader: 'babel-loader',
        include: __dirname,
        exclude: /node_modules/,
      },
    ],
  },  
  output: {
    libraryTarget: 'commonjs2',
    path: path.join(__dirname, 'dist'),
    filename: '[name].js',
    sourceMapFilename: '[file].map',
  }
};

My serverless.yml file already contains following

plugins:
  - serverless-webpack
  - serverless-offline

# serverless optimization
package:
  individually: true

# serverless-webpack configuration
# Enable auto-packing of external modules
custom:
  webpack:
    webpackConfig: ./webpack.config.js 
    includeModules: true
    packager: npm

My .babelrc contains
{
  "plugins": ["source-map-support"],
  "presets": [
    [
      "@babel/preset-env",
      {
        "targets": {
          "node": "8.10"
        }
      }
    ],

  ]
}

My handler file try to use db connection (MongoDB) defined i db.js

import mongoose from 'mongoose';

mongoose.Promise = global.Promise;
let isConnected;

export default connectToDatabase = () => {
  if (isConnected) {
    console.log('=> using existing database connection');
    return Promise.resolve();
  }

  console.log('=> using new database connection');
  return mongoose.connect(process.env.DB)
    .then(db => { 
      isConnected = db.connections[0].readyState;
    });
}

and handler file refer it as

import { connectToDatabase } from './db';
import Campaign from '../models/campaign';

module.exports.CreateCampaign = (event, context, callback) => {
  context.callbackWaitsForEmptyEventLoop = false;

  connectToDatabase()
    .then(() => {
      Campaign.create(JSON.parse(event.body))
        .then(note => callback(null, {
          statusCode: 200,
          body: JSON.stringify(note)
        }))
        .catch(err => callback(null, {
          statusCode: err.statusCode || 500,
          headers: { 'Content-Type': 'text/plain' },
          body: 'Could not create the note.'
        }));
    });
};

I get warning and error as

WARNING in ./src/Campaign.js 5:12-29
"export 'connectToDatabase' was not found in './db'

When i execute npm start

npm start
> orim-api@1.0.0 start /Users/elopez/Projects/orion-serverless/orim-api
> sls offline start --skipCacheInvalidation

Serverless: Bundling with Webpack...
Time: 511ms
Built at: 2019-05-03 09:46:01
              Asset      Size        Chunks             Chunk Names
    src/Campaign.js    10 KiB  src/Campaign  [emitted]  src/Campaign
src/Campaign.js.map  9.68 KiB  src/Campaign  [emitted]  src/Campaign
Entrypoint src/Campaign = src/Campaign.js src/Campaign.js.map
[./models/campaign.js] 321 bytes {src/Campaign} [built]
[./node_modules/webpack/buildin/harmony-module.js] (webpack)/buildin/harmony-module.js 625 bytes {src/Campaign} [built]
[./src/Campaign.js] 1.19 KiB {src/Campaign} [built]
[./src/db.js] 442 bytes {src/Campaign} [built]
[mongoose] external "mongoose" 42 bytes {src/Campaign} [built]
[source-map-support/register] external "source-map-support/register" 42 bytes {src/Campaign} [built]

WARNING in ./src/Campaign.js 5:12-29
"export 'connectToDatabase' was not found in './db'

WARNING in ./src/Campaign.js 13:2-19
"export 'connectToDatabase' was not found in './db'

WARNING in ./src/Campaign.js 29:2-19
"export 'connectToDatabase' was not found in './db'
Serverless: Watching for changes...
Serverless: Starting Offline: dev/us-east-1.

Serverless: Routes for createCampaign:
Serverless: POST /Campaign

Serverless: Routes for getAllCampaign:
Serverless: GET /Campaign

Serverless: Routes for helloCampaign:
Serverless: GET /Hello

Serverless: Offline listening on http://localhost:3000

My package.json is

{
  "name": "test-api",
  "version": "1.0.0",
  "description": "",
  "main": "handler.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "sls offline start --skipCacheInvalidation",
    "build": "sls webpack --out dist"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "@babel/cli": "^7.4.4",
    "@babel/core": "^7.4.4",
    "@babel/plugin-transform-runtime": "^7.4.4",
    "@babel/preset-env": "^7.4.4",
    "babel-loader": "^8.0.5",
    "babel-plugin-source-map-support": "^2.0.1",
    "babel-preset-stage-3": "^6.24.1",
    "nodemon": "^1.19.0",
    "serverless-offline": "^4.9.4",
    "serverless-webpack": "^5.3.0",
    "webpack": "^4.30.0",
    "webpack-node-externals": "^1.7.2"
  },
  "dependencies": {
    "dotenv": "^7.0.0",
    "mongoose": "^5.5.5",
    "source-map-support": "^0.5.12"
  }
}
hassankhan commented 5 years ago

I think the problem is related to incorrect exports, your db.js file should not export default, it should just be export connectToDatabase

lopezdp commented 5 years ago

I am having a similar problem. Please see below:

What went wrong?

Babe Migration from 7.x to 8.x Node Migration from 8.x to 10.x

What was the config you used?

Changed targets in .babelrc from 8.10 to 10.14.1 Changed runtime in serverless.yml from 8.10 to runtime: nodejs10.14.1

What stacktrace or error message from your provider did you see?

ERROR in ./getCaseRecord.js
Module build failed (from ./node_modules/babel-loader/lib/index.js):
Error: Plugin/Preset files are not allowed to export objects, only functions. In /Users/MyDocs/DevOps/QuickAutoTags/services/v2.crm-case-record-api/node_modules/babel-preset-stage-3/lib/index.js
    at createDescriptor (/Users/MyDocs/DevOps/QuickAutoTags/services/v2.crm-case-record-api/node_modules/@babel/core/lib/config/config-descriptors.js:178:11)
    at items.map (/Users/MyDocs/DevOps/QuickAutoTags/services/v2.crm-case-record-api/node_modules/@babel/core/lib/config/config-descriptors.js:109:50)
    at Array.map (<anonymous>)
    at createDescriptors (/Users/MyDocs/DevOps/QuickAutoTags/services/v2.crm-case-record-api/node_modules/@babel/core/lib/config/config-descriptors.js:109:29)
    at createPresetDescriptors (/Users/MyDocs/DevOps/QuickAutoTags/services/v2.crm-case-record-api/node_modules/@babel/core/lib/config/config-descriptors.js:101:10)
    at presets (/Users/MyDocs/DevOps/QuickAutoTags/services/v2.crm-case-record-api/node_modules/@babel/core/lib/config/config-descriptors.js:47:19)
    at mergeChainOpts (/Users/MyDocs/DevOps/QuickAutoTags/services/v2.crm-case-record-api/node_modules/@babel/core/lib/config/config-chain.js:320:26)
    at /Users/MyDocs/DevOps/QuickAutoTags/services/v2.crm-case-record-api/node_modules/@babel/core/lib/config/config-chain.js:283:7
    at buildRootChain (/Users/MyDocs/DevOps/QuickAutoTags/services/v2.crm-case-record-api/node_modules/@babel/core/lib/config/config-chain.js:120:22)
    at loadPrivatePartialConfig (/Users/MyDocs/DevOps/QuickAutoTags/services/v2.crm-case-record-api/node_modules/@babel/core/lib/config/partial.js:85:55)
    at Object.loadPartialConfig (/Users/MyDocs/DevOps/QuickAutoTags/services/v2.crm-case-record-api/node_modules/@babel/core/lib/config/partial.js:110:18)
    at Object.<anonymous> (/Users/MyDocs/DevOps/QuickAutoTags/services/v2.crm-case-record-api/node_modules/babel-loader/lib/index.js:144:26)
    at Generator.next (<anonymous>)
    at asyncGeneratorStep (/Users/MyDocs/DevOps/QuickAutoTags/services/v2.crm-case-record-api/node_modules/babel-loader/lib/index.js:3:103)
    at _next (/Users/MyDocs/DevOps/QuickAutoTags/services/v2.crm-case-record-api/node_modules/babel-loader/lib/index.js:5:194)
    at /Users/MyDocs/DevOps/QuickAutoTags/services/v2.crm-case-record-api/node_modules/babel-loader/lib/index.js:5:364
    at new Promise (<anonymous>)
    at Object.<anonymous> (/Users/MyDocs/DevOps/QuickAutoTags/services/v2.crm-case-record-api/node_modules/babel-loader/lib/index.js:5:97)
    at Object._loader (/Users/MyDocs/DevOps/QuickAutoTags/services/v2.crm-case-record-api/node_modules/babel-loader/lib/index.js:224:18)
    at Object.loader (/Users/MyDocs/DevOps/QuickAutoTags/services/v2.crm-case-record-api/node_modules/babel-loader/lib/index.js:60:18)
    at Object.<anonymous> (/Users/MyDocs/DevOps/QuickAutoTags/services/v2.crm-case-record-api/node_modules/babel-loader/lib/index.js:55:12)

Here is what is in my .babelrc file:

{
    "plugins": [],
    "presets": [
        ["env", {"node": "10.14.1"}],
        "stage-3"
    ]
}

Here are my dependencies in my package.json:

"devDependencies": {
    "aws-sdk": "^2.350.0",
    "babel-core": "^6.26.3",
    "babel-eslint": "^10.0.1",
    "babel-loader": "^8.0.6",
    "babel-plugin-source-map-support": "^2.0.1",
    "babel-plugin-transform-runtime": "^6.23.0",
    "babel-preset-env": "^1.7.0",
    "babel-preset-stage-3": "^6.24.1",
    "eslint": "^5.15.0",
    "eslint-config-standard": "^12.0.0",
    "eslint-plugin-import": "^2.14.0",
    "eslint-plugin-node": "^9.1.0",
    "eslint-plugin-promise": "^4.0.1",
    "eslint-plugin-react": "^7.12.4",
    "eslint-plugin-standard": "^4.0.0",
    "jest": "^24.8.0",
    "serverless-offline": "^5.0.0",
    "serverless-webpack": "^5.1.0",
    "webpack": "^4.16.2",
    "webpack-node-externals": "^1.6.0"
  },

What do you think? I really want to stay current and use the most recent version of babel if at all possible. Does anyone know if serverless-webpack supports babel.v8 yet??

If so, how can I get them to work together considering the above info?

Thanks!

hmtri1011 commented 5 years ago

I'm also facing this issue.

This is my folder structure and the webpack build result: image

This is my webpack.config.js:

const slsw = require('serverless-webpack')
const nodeExternals = require('webpack-node-externals')

module.exports = {
  entry: slsw.lib.entries,
  target: 'node',
  node: {
    __dirname: true
  },
  // Generate sourcemaps for proper error messages
  devtool: 'source-map',
  // Since 'aws-sdk' is not compatible with webpack,
  // we exclude all node dependencies
  externals: [nodeExternals()],
  mode: slsw.lib.webpack.isLocal ? 'development' : 'production',
  optimization: {
    // We no not want to minimize our code.
    minimize: false
  },
  performance: {
    // Turn off size warnings for entry points
    hints: false
  },
  // Run babel on all .js files and skip those in node_modules
  module: {
    rules: [
      {
        test: /\.js$/,
        loader: 'babel-loader',
        include: __dirname,
        exclude: /node_modules/
      }
    ]
  }
}

As we can see, my email_template.ejs file was not built so that after I deployed and run the lambda function, it would return

"errorMessage": "ENOENT: no such file or directory, open '/var/task/src/email_template.ejs'"

However, it works perfectly on my local.

HyperBrain commented 5 years ago

Hi @hmtri1011 , I think you need to install and configure an ejs loader for webpack (ejs extensions). Can you check?

hmtri1011 commented 5 years ago

Hi @HyperBrain, I found the reason, the issue is my email_template.js was not built and deployed on output.zip file by webpack. So I use copy-webpack-plugin and add this line to my webpack.config.js

 (...),
  plugins: [
    new CopyWebpackPlugin([{ from: './src/email_template.ejs', to: './src' }])
  ]

Now my email_template.js is existed on the output.zip file and it works perfectly.