├── .eslintignore ├── test ├── .eslintrc ├── data │ ├── webpack.conf.js │ └── stats.json ├── getExternalsFromStats.test.js ├── copyModules.test.js └── getConfig.test.js ├── .editorconfig ├── .eslintrc ├── .gitignore ├── lib ├── getExternalsFromStats.js ├── getConfig.js └── copyModules.js ├── package.json ├── README.md └── index.js /.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /test/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "mocha": true 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | end_of_line = lf 5 | insert_final_newline = true 6 | 7 | [*.{js,jsx}] 8 | charset = utf-8 9 | indent_style = space 10 | indent_size = 2 11 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "airbnb/base", 3 | "env": { 4 | "node": true 5 | }, 6 | "globals": {}, 7 | "rules": { 8 | "comma-dangle": 0, 9 | "padded-blocks": 0 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /test/data/webpack.conf.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | target: 'node', 3 | externals: [ 4 | 'aws-sdk' 5 | ], 6 | resolve: { 7 | extensions: ['', '.js', '.jsx'] 8 | }, 9 | module: { 10 | loaders: [ 11 | { 12 | test: /\.json$/, 13 | loader: 'json', 14 | } 15 | ] 16 | } 17 | }; 18 | -------------------------------------------------------------------------------- /test/getExternalsFromStats.test.js: -------------------------------------------------------------------------------- 1 | const getExternalsFromStats = require('../lib/getExternalsFromStats'); 2 | const assert = require('chai').assert; 3 | 4 | function getStatsMock() { 5 | return { 6 | toJson() { 7 | return { modules: require('./data/stats.json').slice(0) }; 8 | } 9 | }; 10 | } 11 | 12 | describe('getExternalsFromStats', () => { 13 | 14 | it('filters out aws-sdk and native node modules', () => { 15 | const stats = getStatsMock(); 16 | const result = getExternalsFromStats(stats); 17 | 18 | assert.isArray(result, 'The result should be an array'); 19 | assert.lengthOf(result, 1); 20 | assert.strictEqual(result[0], 'serverless-helpers-js'); 21 | 22 | }); 23 | 24 | }); 25 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log 5 | 6 | # Runtime data 7 | pids 8 | *.pid 9 | *.seed 10 | dist 11 | 12 | # Directory for instrumented libs generated by jscoverage/JSCover 13 | lib-cov 14 | 15 | # Coverage directory used by tools like istanbul 16 | coverage 17 | 18 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 19 | .grunt 20 | 21 | # node-waf configuration 22 | .lock-wscript 23 | 24 | # Compiled binary addons (http://nodejs.org/api/addons.html) 25 | build/Release 26 | 27 | # Dependency directory 28 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git 29 | node_modules 30 | 31 | #IDE Stuff 32 | **/.idea 33 | 34 | #OS STUFF 35 | .DS_Store 36 | .tmp 37 | 38 | #SERVERLESS STUFF 39 | admin.env 40 | .env -------------------------------------------------------------------------------- /lib/getExternalsFromStats.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | const natives = process.binding('natives'); 3 | 4 | module.exports = function getExternalsFromStats(stats) { 5 | const options = { 6 | hash: false, 7 | version: false, 8 | timings: false, 9 | assets: false, 10 | chunks: false, 11 | modules: true, 12 | reasons: false, 13 | children: false, 14 | source: false, 15 | errors: false, 16 | errorDetails: false, 17 | warnings: false, 18 | publicPath: false, 19 | exclude: [/^(?!external )/] 20 | }; 21 | 22 | const externalModules = stats.toJson(options).modules; 23 | return externalModules 24 | .map(module => /external "(.+)"/.exec(module.identifier)[1]) 25 | // exclude aws-sdk since it is provided by lambda 26 | // also exclude native node.js modules 27 | .filter(id => id !== 'aws-sdk' && !natives[id]); 28 | }; 29 | -------------------------------------------------------------------------------- /lib/getConfig.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | const path = require('path'); 3 | const clone = require('clone'); 4 | 5 | function getCustomConfig(obj) { 6 | if (obj.custom) { 7 | const webpack = obj.custom.webpack; 8 | if (typeof webpack === 'object') { 9 | return webpack; 10 | } else if (webpack === false) { 11 | return { configPath: '' }; 12 | } 13 | } 14 | return { }; 15 | } 16 | 17 | module.exports = function getConfig(projectPath, project, func) { 18 | const defaults = { 19 | handlerExt: 'js', 20 | configPath: '' 21 | }; 22 | 23 | const config = Object.assign(defaults, getCustomConfig(project), getCustomConfig(func)); 24 | 25 | if (config.configPath) { 26 | try { 27 | const configPath = path.join(projectPath, config.configPath); 28 | config.webpackConfig = clone(require(configPath)); 29 | } catch (e) { 30 | console.log(e); 31 | } 32 | } 33 | 34 | return config; 35 | }; 36 | -------------------------------------------------------------------------------- /test/copyModules.test.js: -------------------------------------------------------------------------------- 1 | const copyModules = require('../lib/copyModules'); 2 | const assert = require('chai').assert; 3 | const path = require('path'); 4 | const Promise = require('bluebird'); 5 | const fs = Promise.promisifyAll(require('fs-extra')); 6 | 7 | function exists(filePath) { 8 | try { 9 | fs.accessSync(filePath, fs.F_OK); 10 | return true; 11 | } catch (e) { 12 | return false; 13 | } 14 | } 15 | 16 | describe('copyModules', () => { 17 | const projectPath = path.join(__dirname, '..'); 18 | const dest = path.join(projectPath, '.tmp'); 19 | 20 | before(() => fs.mkdirsAsync(dest)); 21 | after(() => fs.removeAsync(dest)); 22 | 23 | it('copys the correct modules', () => { 24 | const includePaths = ['mocha']; 25 | 26 | return copyModules(projectPath, includePaths, dest) 27 | .then(() => { 28 | assert.isTrue(exists(path.join(dest, 'mocha/index.js'))); 29 | assert.isTrue(exists(path.join(dest, 'mocha/lib/browser/debug.js'))); 30 | assert.isTrue(exists(path.join(dest, 'mocha/node_modules/glob/glob.js'))); 31 | }); 32 | }); 33 | 34 | }); 35 | -------------------------------------------------------------------------------- /lib/copyModules.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | const path = require('path'); 3 | const childProcess = require('child_process'); 4 | const Promise = require('bluebird'); 5 | 6 | const exec = Promise.promisify(childProcess.execFile); 7 | 8 | module.exports = function copyModules(projectPath, moduleNames, dest) { 9 | // No dependencies, just return, so that npm install would not fail. 10 | if (moduleNames.length === 0) { 11 | return Promise.resolve(); 12 | } 13 | 14 | const pkg = require(path.join(projectPath, 'package.json')); 15 | const modulesAndVersions = moduleNames.map(moduleName => { 16 | const moduleVersion = pkg.dependencies[moduleName]; 17 | 18 | // If no module version was found, throw an error 19 | if (!moduleVersion) { 20 | throw new Error(`Error: Could not find module ${moduleName} in package.json!`); 21 | } 22 | 23 | return `${moduleName}@${moduleVersion}`; 24 | }); 25 | const opts = { cwd: path.join(dest), env: process.env }; 26 | const args = ['install', '--production'].concat(modulesAndVersions); 27 | 28 | // Run 'npm install' on each module to get a full set of dependencies, 29 | // not just the directly copied ones. 30 | return exec('npm', args, opts); 31 | }; 32 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "serverless-webpack-plugin", 3 | "version": "0.4.5", 4 | "engines": { 5 | "node": ">=4.0" 6 | }, 7 | "description": "Serverless Webpack Plugin - Significantly reduces Lambda file size and improves performance", 8 | "author": "asprouse", 9 | "license": "MIT", 10 | "repository": { 11 | "type": "git", 12 | "url": "https://github.com/asprouse/serverless-webpack-plugin" 13 | }, 14 | "keywords": [ 15 | "serverless webpack plugin", 16 | "serverless webpack", 17 | "serverless framework plugin", 18 | "serverless applications", 19 | "serverless plugins", 20 | "lambda webpack", 21 | "api gateway", 22 | "lambda", 23 | "aws", 24 | "aws lambda", 25 | "amazon", 26 | "amazon web services", 27 | "serverless.com" 28 | ], 29 | "main": "index.js", 30 | "bin": {}, 31 | "scripts": { 32 | "test": "NODE_PATH=. mocha \"test/**/*.test.js\"" 33 | }, 34 | "peerDependencies": { 35 | "webpack": "^1.12.14" 36 | }, 37 | "devDependencies": { 38 | "chai": "^3.4.1", 39 | "mocha": "^2.3.4", 40 | "eslint": "^1.10.3", 41 | "eslint-config-airbnb": "^5.0.0" 42 | }, 43 | "dependencies": { 44 | "bluebird": "^3.1.1", 45 | "clone": "^1.0.2", 46 | "fs-extra": "^0.26.7" 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /test/getConfig.test.js: -------------------------------------------------------------------------------- 1 | const assert = require('chai').assert; 2 | const getConfig = require('../lib/getConfig'); 3 | const path = require('path'); 4 | 5 | const projectPath = path.resolve('./test/data'); 6 | 7 | describe.only('getConfig', () => { 8 | 9 | it('assigns defaults', () => { 10 | const project = {}; 11 | const func = {}; 12 | const result = getConfig(projectPath, project, func); 13 | 14 | assert.deepEqual(result, { handlerExt: 'js', configPath: '' }); 15 | }); 16 | 17 | it('respects custom project config', () => { 18 | const project = { 19 | custom: { 20 | webpack: { 21 | configPath: './webpack.conf.js' 22 | } 23 | } 24 | }; 25 | const func = {}; 26 | const result = getConfig(projectPath, project, func); 27 | 28 | assert.deepEqual(result, { 29 | handlerExt: 'js', 30 | configPath: './webpack.conf.js', 31 | webpackConfig: { 32 | target: 'node', 33 | externals: [ 34 | 'aws-sdk' 35 | ], 36 | resolve: { 37 | extensions: ['', '.js', '.jsx'] 38 | }, 39 | module: { 40 | loaders: [ 41 | { 42 | test: /\.json$/, 43 | loader: 'json', 44 | } 45 | ] 46 | } 47 | } 48 | }); 49 | }); 50 | 51 | it('respects custom func config', () => { 52 | const project = {}; 53 | const func = { 54 | custom: { 55 | webpack: { 56 | configPath: './webpack.conf.js' 57 | } 58 | } 59 | }; 60 | const result = getConfig(projectPath, project, func); 61 | 62 | assert.deepEqual(result, { 63 | handlerExt: 'js', 64 | configPath: './webpack.conf.js', 65 | webpackConfig: { 66 | target: 'node', 67 | externals: [ 68 | 'aws-sdk' 69 | ], 70 | resolve: { 71 | extensions: ['', '.js', '.jsx'] 72 | }, 73 | module: { 74 | loaders: [ 75 | { 76 | test: /\.json$/, 77 | loader: 'json', 78 | } 79 | ] 80 | } 81 | } 82 | }); 83 | }); 84 | 85 | it('creates a unique webpack config', () => { 86 | const project = { 87 | custom: { 88 | webpack: { 89 | configPath: './webpack.conf.js' 90 | } 91 | } 92 | }; 93 | const func = {}; 94 | const result = getConfig(projectPath, project, func); 95 | const webpackConfig = require('./data/webpack.conf.js'); 96 | 97 | assert.notStrictEqual(result.webpackConfig, webpackConfig); 98 | assert.deepEqual(result, { 99 | handlerExt: 'js', 100 | configPath: './webpack.conf.js', 101 | webpackConfig: { 102 | target: 'node', 103 | externals: [ 104 | 'aws-sdk' 105 | ], 106 | resolve: { 107 | extensions: ['', '.js', '.jsx'] 108 | }, 109 | module: { 110 | loaders: [ 111 | { 112 | test: /\.json$/, 113 | loader: 'json', 114 | } 115 | ] 116 | } 117 | } 118 | }); 119 | }); 120 | 121 | }); 122 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Serverless Webpack Plugin 2 | ============================= 3 | 4 | Forked from [serverless-optimizer-plugin](https://github.com/serverless/serverless-optimizer-plugin) this plugin uses 5 | webpack to optimize your Serverless Node.js Functions on deployment. 6 | 7 | Reducing the file size of your AWS Lambda Functions allows AWS to provision them more quickly, speeding up the response 8 | time of your Lambdas. Smaller Lambda sizes also helps you develop faster because you can upload them faster. 9 | This Severless Plugin is absolutely recommended for every project including Lambdas with Node.js. 10 | 11 | **Note:** Requires Serverless *v0.5.0*. 12 | 13 | ### Setup 14 | 15 | * Install the plugin and webpack in the root of your Serverless Project: 16 | ``` 17 | npm install serverless-webpack-plugin webpack --save-dev 18 | ``` 19 | 20 | * Add the plugin to the `plugins` array in your Serverless Project's `s-project.json`, like this: 21 | 22 | ``` 23 | plugins: [ 24 | "serverless-webpack-plugin" 25 | ] 26 | ``` 27 | 28 | * In the `custom` property of either your `s-project.json` or `s-function.json` add an webpack property. The configPath is relative to the project root. 29 | 30 | ```javascript 31 | { 32 | ... 33 | "custom": { 34 | "webpack": { 35 | "configPath": "path/relative/to/project-path" 36 | } 37 | } 38 | ... 39 | } 40 | 41 | ``` 42 | 43 | 44 | ## Webpack config 45 | This plugin allows you to completely customize how your code is optimized by specifying your own webpack config. Heres a sample `webpack.config.js`: 46 | 47 | ```javascript 48 | var webpack = require('webpack'); 49 | 50 | module.exports = { 51 | // entry: provided by serverless 52 | // output: provided by serverless 53 | target: 'node', 54 | externals: [ 55 | 'aws-sdk' 56 | ], 57 | resolve: { 58 | extensions: ['', '.js', '.jsx'] 59 | }, 60 | devtool: 'source-map', 61 | plugins: [ 62 | new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/), 63 | new webpack.optimize.DedupePlugin(), 64 | new webpack.optimize.OccurenceOrderPlugin(), 65 | new webpack.optimize.UglifyJsPlugin({ 66 | compress: { 67 | unused: true, 68 | dead_code: true, 69 | warnings: false, 70 | drop_debugger: true 71 | } 72 | }) 73 | ], 74 | module: { 75 | loaders: [ 76 | { 77 | test: /\.jsx?$/, 78 | loader: 'babel', 79 | exclude: /node_modules/, 80 | query: { 81 | presets: ['es2015', 'stage-0'] 82 | } 83 | } 84 | ] 85 | } 86 | }; 87 | ``` 88 | **Note:** Some node modules don't play nicely with `webpack.optimize.UglifyJsPlugin` in this case, you can omit it from 89 | your config, or add the offending modules to `externals`. For more on externals see below. 90 | 91 | ### Externals 92 | Externals specified in your webpack config will be properly packaged into the deployment. 93 | This is useful when working with modules that have binary dependencies, are incompatible with `webpack.optimize.UglifyJsPlugin` 94 | or if you simply want to improve build performance. Check out [webpack-node-externals](https://github.com/liady/webpack-node-externals) 95 | for an easy way to externalize all node modules. 96 | 97 | ### Source Maps 98 | Yes using `devtool: 'source-map'` works, include `require('source-map-support').install();` you'll have pretty stacktraces. 99 | 100 | ### Loading additional modules before the lambda function module 101 | If you need to load modules before your lambda function module is loaded, 102 | you can specify those modules with entry option in your webpack config. 103 | For example if you need to load the babel-polyfill, you can do that 104 | by adding `entry: ['babel-polyfill']` to your webpack config. 105 | This will first load the babel-polyfill module and then your lambda function module. 106 | 107 | ### Improving deploy performance 108 | 109 | The plugin builds directly from the source files, using "magic handlers" to include the parent directory (as mentioned in 110 | the [0.5.0 release notes](https://github.com/serverless/serverless/releases/tag/v0.5.0)) is unnecessary. 111 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | const path = require('path'); 3 | const webpack = require('webpack'); 4 | const Promise = require('bluebird'); 5 | const fs = Promise.promisifyAll(require('fs-extra')); 6 | 7 | const getConfig = require('./lib/getConfig'); 8 | const getExternalsFromStats = require('./lib/getExternalsFromStats'); 9 | const copyModules = require('./lib/copyModules'); 10 | 11 | 12 | function runWebpack(config) { 13 | return new Promise((resolve, reject) => { 14 | webpack(config).run((err, stats) => { 15 | if (err) { 16 | return reject(err); 17 | } 18 | resolve(stats); 19 | }); 20 | }); 21 | } 22 | 23 | module.exports = function getPlugin(S) { 24 | const SCli = require(S.getServerlessPath('utils/cli')); 25 | 26 | function logStats(stats) { 27 | SCli.log(stats.toString({ 28 | colors: true, 29 | hash: false, 30 | version: false, 31 | chunks: false, 32 | children: false 33 | })); 34 | } 35 | 36 | class ServerlessWebpack extends S.classes.Plugin { 37 | 38 | static getName() { 39 | return `com.serverless.${ServerlessWebpack.name}`; 40 | } 41 | 42 | registerHooks() { 43 | S.addHook(this.optimize.bind(this), { 44 | action: 'codeDeployLambda', 45 | event: 'pre' 46 | }); 47 | 48 | return Promise.resolve(); 49 | } 50 | 51 | optimize(evt) { 52 | // Validate: Check Serverless version 53 | if (parseInt(S._version.split('.')[1], 10) < 5) { 54 | SCli.log('WARNING: This version of the Serverless Optimizer Plugin ' + 55 | 'will not work with a version of Serverless that is less than v0.5'); 56 | } 57 | 58 | // Get function 59 | const project = S.getProject(); 60 | const func = project.getFunction(evt.options.name); 61 | 62 | if (func.runtime === 'nodejs' || func.runtime === 'nodejs4.3') { 63 | const projectPath = S.config.projectPath; 64 | const config = getConfig( 65 | projectPath, 66 | project.toObjectPopulated(evt.options), 67 | func.toObjectPopulated(evt.options) 68 | ); 69 | 70 | if (config.webpackConfig) { 71 | const pathDist = evt.options.pathDist; 72 | const optimizedPath = path.join(pathDist, 'optimized'); 73 | const optimizedModulesPath = path.join(optimizedPath, 'node_modules'); 74 | 75 | const webpackConfig = Object.assign({}, config.webpackConfig); 76 | const handlerName = func.getHandler().split('.')[0]; 77 | const handlerFileName = `${handlerName}.${config.handlerExt}`; 78 | const handlerEntryPath = `./${handlerFileName}`; 79 | 80 | // override entry and output 81 | webpackConfig.context = path.dirname(func.getFilePath()); 82 | if (Array.isArray(webpackConfig.entry)) { 83 | webpackConfig.entry.push(handlerEntryPath); 84 | } else { 85 | webpackConfig.entry = handlerEntryPath; 86 | } 87 | webpackConfig.output = { 88 | libraryTarget: 'commonjs', 89 | path: optimizedPath, 90 | filename: handlerFileName 91 | }; 92 | 93 | // copy generated handler so we can build directly from the source directory 94 | const generatedHandler = path.join(webpackConfig.context, handlerFileName); 95 | 96 | return fs.copyAsync(path.join(pathDist, handlerFileName), generatedHandler) 97 | .then(() => fs.mkdirsAsync(optimizedModulesPath)) 98 | .then(() => runWebpack(webpackConfig)) 99 | .then((stats) => { 100 | logStats(stats); 101 | const externals = getExternalsFromStats(stats); 102 | return copyModules(projectPath, externals, optimizedModulesPath); 103 | }) 104 | .then(() => { 105 | evt.options.pathDist = optimizedPath; // eslint-disable-line 106 | return evt; 107 | }) 108 | // delete generated handler we copied above 109 | .finally(() => fs.removeAsync(generatedHandler)); 110 | } 111 | } 112 | 113 | return Promise.resolve(evt); 114 | } 115 | } 116 | 117 | return ServerlessWebpack; 118 | }; 119 | -------------------------------------------------------------------------------- /test/data/stats.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": 30, 4 | "identifier": "external \"util\"", 5 | "name": "external \"util\"", 6 | "index": 206, 7 | "index2": 203, 8 | "size": 42, 9 | "cacheable": false, 10 | "built": false, 11 | "optional": false, 12 | "prefetched": false, 13 | "chunks": [ 14 | 0 15 | ], 16 | "assets": [], 17 | "issuer": "/Users/als/dev/api/node_modules/babel-loader/index.js?{\"presets\":[\"es2015\",\"stage-0\"],\"cacheDirectory\":true}!/Users/als/dev/api/lib/util/data-translators.js", 18 | "failed": false, 19 | "errors": 0, 20 | "warnings": 0 21 | }, 22 | { 23 | "id": 51, 24 | "identifier": "external \"buffer\"", 25 | "name": "external \"buffer\"", 26 | "index": 236, 27 | "index2": 230, 28 | "size": 42, 29 | "cacheable": false, 30 | "built": false, 31 | "optional": false, 32 | "prefetched": false, 33 | "chunks": [ 34 | 0 35 | ], 36 | "assets": [], 37 | "issuer": "/Users/als/dev/api/node_modules/jsonwebtoken/node_modules/jws/lib/data-stream.js", 38 | "failed": false, 39 | "errors": 0, 40 | "warnings": 0 41 | }, 42 | { 43 | "id": 52, 44 | "identifier": "external \"crypto\"", 45 | "name": "external \"crypto\"", 46 | "index": 205, 47 | "index2": 202, 48 | "size": 42, 49 | "cacheable": false, 50 | "built": false, 51 | "optional": false, 52 | "prefetched": false, 53 | "chunks": [ 54 | 0 55 | ], 56 | "assets": [], 57 | "issuer": "/Users/als/dev/node_modules/node-uuid/uuid.js", 58 | "failed": false, 59 | "errors": 0, 60 | "warnings": 0 61 | }, 62 | { 63 | "id": 69, 64 | "identifier": "external \"stream\"", 65 | "name": "external \"stream\"", 66 | "index": 237, 67 | "index2": 231, 68 | "size": 42, 69 | "cacheable": false, 70 | "built": false, 71 | "optional": false, 72 | "prefetched": false, 73 | "chunks": [ 74 | 0 75 | ], 76 | "assets": [], 77 | "issuer": "/Users/als/dev/api/node_modules/jsonwebtoken/node_modules/jws/lib/sign-stream.js", 78 | "failed": false, 79 | "errors": 0, 80 | "warnings": 0 81 | }, 82 | { 83 | "id": 117, 84 | "identifier": "external \"aws-sdk\"", 85 | "name": "external \"aws-sdk\"", 86 | "index": 289, 87 | "index2": 286, 88 | "size": 42, 89 | "cacheable": false, 90 | "built": false, 91 | "optional": false, 92 | "prefetched": false, 93 | "chunks": [ 94 | 0 95 | ], 96 | "assets": [], 97 | "issuer": "/Users/als/dev/api/node_modules/babel-loader/index.js?{\"presets\":[\"es2015\",\"stage-0\"],\"cacheDirectory\":true}!/Users/als/dev/api/lib/data/s3.js", 98 | "failed": false, 99 | "errors": 0, 100 | "warnings": 0 101 | }, 102 | { 103 | "id": 118, 104 | "identifier": "external \"path\"", 105 | "name": "external \"path\"", 106 | "index": 12, 107 | "index2": 9, 108 | "size": 42, 109 | "cacheable": false, 110 | "built": false, 111 | "optional": false, 112 | "prefetched": false, 113 | "chunks": [ 114 | 0 115 | ], 116 | "assets": [], 117 | "issuer": "/Users/als/dev/api/node_modules/source-map-support/source-map-support.js", 118 | "failed": false, 119 | "errors": 0, 120 | "warnings": 0 121 | }, 122 | { 123 | "id": 339, 124 | "identifier": "external \"dns\"", 125 | "name": "external \"dns\"", 126 | "index": 219, 127 | "index2": 214, 128 | "size": 42, 129 | "cacheable": false, 130 | "built": false, 131 | "optional": false, 132 | "prefetched": false, 133 | "chunks": [ 134 | 0 135 | ], 136 | "assets": [], 137 | "issuer": "/Users/als/dev/api/node_modules/babel-loader/index.js?{\"presets\":[\"es2015\",\"stage-0\"],\"cacheDirectory\":true}!/Users/als/dev/api/node_modules/joi/node_modules/isemail/lib/index.js", 138 | "failed": false, 139 | "errors": 0, 140 | "warnings": 0 141 | }, 142 | { 143 | "id": 340, 144 | "identifier": "external \"fs\"", 145 | "name": "external \"fs\"", 146 | "index": 13, 147 | "index2": 10, 148 | "size": 42, 149 | "cacheable": false, 150 | "built": false, 151 | "optional": false, 152 | "prefetched": false, 153 | "chunks": [ 154 | 0 155 | ], 156 | "assets": [], 157 | "issuer": "/Users/als/dev/api/node_modules/source-map-support/source-map-support.js", 158 | "failed": false, 159 | "errors": 0, 160 | "warnings": 0 161 | }, 162 | { 163 | "id": 341, 164 | "identifier": "external \"net\"", 165 | "name": "external \"net\"", 166 | "index": 217, 167 | "index2": 213, 168 | "size": 42, 169 | "cacheable": false, 170 | "built": false, 171 | "optional": false, 172 | "prefetched": false, 173 | "chunks": [ 174 | 0 175 | ], 176 | "assets": [], 177 | "issuer": "/Users/als/dev/api/node_modules/babel-loader/index.js?{\"presets\":[\"es2015\",\"stage-0\"],\"cacheDirectory\":true}!/Users/als/dev/api/node_modules/joi/lib/string.js", 178 | "failed": false, 179 | "errors": 0, 180 | "warnings": 0 181 | }, 182 | { 183 | "id": 342, 184 | "identifier": "external \"serverless-helpers-js\"", 185 | "name": "external \"serverless-helpers-js\"", 186 | "index": 342, 187 | "index2": 341, 188 | "size": 42, 189 | "cacheable": false, 190 | "built": false, 191 | "optional": false, 192 | "prefetched": false, 193 | "chunks": [ 194 | 0 195 | ], 196 | "assets": [], 197 | "issuer": "/Users/als/dev/api/node_modules/babel-loader/index.js?{\"presets\":[\"es2015\",\"stage-0\"],\"cacheDirectory\":true}!/Users/als/dev/api/user-register/index.js", 198 | "failed": false, 199 | "errors": 0, 200 | "warnings": 0 201 | } 202 | ] 203 | --------------------------------------------------------------------------------