diff --git a/README.md b/README.md index f8a0cdca1..3a9576cec 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,30 @@ custom: Note that, if the `output` configuration is not set, it will automatically be generated to write bundles in the `.webpack` directory. + +By default, the plugin will try to bundle all dependencies. However, you don't +want to include all modules in some cases such as selectively import, excluding +builtin package (aws-sdk) and handling webpack-incompatible modules. In this case, +you add all the modules, you want to exclude from bundled files, into `externals` field +of your `webpack.config.json` and add those, you want to include in final distribution, +into `serverless.yml`: + +```json +// webpack.config.json +{ + externals: ["module1", "module2"] // modules to be excluded from bundled file +} +``` + +```yaml +# serverless.yml +custom: + webpackIncludeModules: + - module1 # modules to be included in distribution +``` + +You can find an example setup in the [`examples`](./examples) folder. + ## Usage ### Automatic bundling diff --git a/examples/include-external-npm-packages/event.json b/examples/include-external-npm-packages/event.json new file mode 100644 index 000000000..2ac50a459 --- /dev/null +++ b/examples/include-external-npm-packages/event.json @@ -0,0 +1,5 @@ +{ + "key3": "value3", + "key2": "value2", + "key1": "value1" +} diff --git a/examples/include-external-npm-packages/handler.js b/examples/include-external-npm-packages/handler.js new file mode 100644 index 000000000..5048e5220 --- /dev/null +++ b/examples/include-external-npm-packages/handler.js @@ -0,0 +1,8 @@ +'use strict'; + +var AWS = require('aws-sdk'); +var fbgraph = require('fbgraph'); + +module.exports.hello = function (event, context, cb) { + cb(null, { message: 'hello fb & aws', event }); +} diff --git a/examples/include-external-npm-packages/package.json b/examples/include-external-npm-packages/package.json new file mode 100644 index 000000000..b13ee3038 --- /dev/null +++ b/examples/include-external-npm-packages/package.json @@ -0,0 +1,19 @@ +{ + "name": "serverless-include-external-npm-package", + "version": "1.0.0", + "description": "Serverless webpack example", + "main": "handler.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "Tony Yuen ", + "license": "MIT", + "devDependencies": { + "serverless-webpack": "^1.0.0-beta.2", + "webpack": "^1.13.1" + }, + "dependencies": { + "aws-sdk": "^2.5.3", + "fbgraph": "^1.3.0" + } +} diff --git a/examples/include-external-npm-packages/serverless.env.yml b/examples/include-external-npm-packages/serverless.env.yml new file mode 100644 index 000000000..38baba6a5 --- /dev/null +++ b/examples/include-external-npm-packages/serverless.env.yml @@ -0,0 +1,15 @@ +# This is the Serverless Environment File +# +# It contains listing of your stages and their regions +# It also manages serverless variables at 3 levels: +# - common variables: variables that apply to all stages/regions +# - stage variables: variables that apply to a specific stage +# - region variables: variables that apply to a specific region + +vars: +stages: + dev: + vars: + regions: + us-east-1: + vars: diff --git a/examples/include-external-npm-packages/serverless.yml b/examples/include-external-npm-packages/serverless.yml new file mode 100644 index 000000000..d27dd6a49 --- /dev/null +++ b/examples/include-external-npm-packages/serverless.yml @@ -0,0 +1,21 @@ +service: serverless-webpack-multiple-entries-example + +# Add the serverless-webpack plugin +plugins: + - serverless-webpack + +provider: + name: aws + runtime: nodejs4.3 + +custom: + webpackIncludeModules: # modules to be included in distribution + - fbgraph + +functions: + first: + handler: handler.hello + events: + - http: + method: GET + path: first diff --git a/examples/include-external-npm-packages/webpack.config.js b/examples/include-external-npm-packages/webpack.config.js new file mode 100644 index 000000000..846684e5e --- /dev/null +++ b/examples/include-external-npm-packages/webpack.config.js @@ -0,0 +1,7 @@ +var path = require('path'); + +module.exports = { + entry: './handler.js', + target: 'node', + externals: ["fbgraph", "aws-sdk"] // modules to be excluded from bundled file +}; diff --git a/index.js b/index.js index eb68a225c..73160b67a 100644 --- a/index.js +++ b/index.js @@ -7,6 +7,7 @@ const compile = require('./lib/compile'); const cleanup = require('./lib/cleanup'); const run = require('./lib/run'); const serve = require('./lib/serve'); +const packExternalModules = require('./lib/packExternalModules') class ServerlessWebpack { constructor(serverless, options) { @@ -19,7 +20,8 @@ class ServerlessWebpack { compile, cleanup, run, - serve + serve, + packExternalModules ); this.commands = { @@ -28,6 +30,7 @@ class ServerlessWebpack { lifecycleEvents: [ 'validate', 'compile', + 'packExternalModules', ], options: { out: { @@ -89,7 +92,8 @@ class ServerlessWebpack { this.hooks = { 'before:deploy:createDeploymentArtifacts': () => BbPromise.bind(this) .then(this.validate) - .then(this.compile), + .then(this.compile) + .then(this.packExternalModules), 'after:deploy:createDeploymentArtifacts': () => BbPromise.bind(this) .then(this.cleanup), @@ -100,6 +104,9 @@ class ServerlessWebpack { 'webpack:compile': () => BbPromise.bind(this) .then(this.compile), + 'webpack:packExternalModules': () => BbPromise.bind(this) + .then(this.packExternalModules), + 'webpack:invoke:invoke': () => BbPromise.bind(this) .then(this.validate) .then(this.compile) diff --git a/lib/packExternalModules.js b/lib/packExternalModules.js new file mode 100644 index 000000000..0e8e9c006 --- /dev/null +++ b/lib/packExternalModules.js @@ -0,0 +1,42 @@ +'use strict'; + +const BbPromise = require('bluebird'); +const fs = require('fs'); +const path = require('path'); +const npm = require('npm-programmatic'); + +module.exports = { + packExternalModules() { + + const includes = ( + this.serverless.service.custom && + this.serverless.service.custom.webpackIncludeModules + ); + + return BbPromise.resolve().then(() => { + if (!includes || includes.length === 0) { + return; + } + + this.serverless.cli.log('Packing external modules: ' + includes.join(",")); + + const tmpPackageJson = path.join(this.serverless.config.servicePath, 'package.json'); + + // create a temp package.json in dist directory so that we can install the dependencies later. + fs.writeFileSync(tmpPackageJson, "{}"); + + return new BbPromise((resolve, reject) => { + npm.install(includes, { + cwd: this.serverless.config.servicePath, + save: false + }).then(() => { + fs.unlink(tmpPackageJson); + resolve() + }).catch(e => { + fs.unlink(tmpPackageJson); + reject(e); + }) + }) + }) + }, +}; diff --git a/package.json b/package.json index dae65b09f..2995ecb44 100644 --- a/package.json +++ b/package.json @@ -31,6 +31,7 @@ "body-parser": "^1.15.2", "express": "^4.14.0", "fs-extra": "^0.26.7", + "npm-programmatic": "0.0.5", "webpack": "^1.13.1" }, "devDependencies": {