From 555c81b8b40197af3fd95f6ed0db5aaac8456987 Mon Sep 17 00:00:00 2001 From: Stuart Harris Date: Tue, 26 Jul 2016 13:09:21 +0100 Subject: [PATCH 01/12] for alpha2 (WIP - needs cleaning up and tests) --- index.js | 157 +++++++++++++++++++++------------------------------ package.json | 6 +- 2 files changed, 67 insertions(+), 96 deletions(-) diff --git a/index.js b/index.js index aef6db0..034ad1c 100644 --- a/index.js +++ b/index.js @@ -1,13 +1,16 @@ 'use strict'; + +const fs = require('fs'); const path = require('path'); -const webpack = require('webpack'); const Promise = require('bluebird'); -const fs = Promise.promisifyAll(require('fs-extra')); - -const getConfig = require('./lib/getConfig'); -const getExternalsFromStats = require('./lib/getExternalsFromStats'); -const copyModules = require('./lib/copyModules'); +const webpack = require('webpack'); +const Zip = require('node-zip'); +const compact = require('lodash/fp/compact'); +const concat = require('lodash/fp/concat'); +const forEach = require('lodash/fp/forEach'); +const map = require('lodash/fp/map'); +const uniq = require('lodash/fp/uniq'); function runWebpack(config) { return new Promise((resolve, reject) => { @@ -20,99 +23,65 @@ function runWebpack(config) { }); } -module.exports = function getPlugin(S) { - const SCli = require(S.getServerlessPath('utils/cli')); +function format(stats) { + return stats.toString({ + colors: true, + hash: false, + version: false, + chunks: false, + children: false + }); +} + +const artifact = 'handler.js'; - function logStats(stats) { - SCli.log(stats.toString({ - colors: true, - hash: false, - version: false, - chunks: false, - children: false - })); +module.exports = class ServerlessWebpack { + constructor(serverless) { + this.serverless = serverless; + this.hooks = { + 'before:deploy:createDeploymentPackage': this.optimize.bind(this) + }; } - class ServerlessWebpack extends S.classes.Plugin { - - static getName() { - return `com.serverless.${ServerlessWebpack.name}`; + optimize() { + if (this.serverless.getVersion() !== '1.0.0-alpha.2') { + throw new this.serverless.classes.Error( + 'WARNING: This version of serverless-webpack-plugin needs Serverless 1.0.0-alpha.2' + ); } - - registerHooks() { - S.addHook(this.optimize.bind(this), { - action: 'codeDeployLambda', - event: 'pre' + const servicePath = this.serverless.config.servicePath; + const serverlessTmpDirPath = path.join(servicePath, '.serverless'); + + const handlerNames = uniq(map(f => f.handler.split('.')[0], this.serverless.service.functions)); + const entrypoints = map(h => `./${h}.js`, handlerNames); + + const webpackConfig = require(path.resolve(servicePath, './webpack.config.js')); + webpackConfig.context = servicePath; + webpackConfig.entry = compact(concat(webpackConfig.entry, entrypoints)); + webpackConfig.output = { + libraryTarget: 'commonjs', + path: serverlessTmpDirPath, + filename: artifact + }; + + return runWebpack(webpackConfig) + .then(stats => this.serverless.cli.log(format(stats))) + .then(() => { + const zip = new Zip(); + forEach(f => + zip.file(f, fs.readFileSync(path.resolve(serverlessTmpDirPath, f)) + ), [artifact, `${artifact}.map`]); + const data = zip.generate({ + type: 'nodebuffer', + compression: 'DEFLATE', + platform: process.platform, }); + const zipFileName = + `${this.serverless.service.service}-${(new Date).getTime().toString()}.zip`; + const artifactFilePath = path.resolve(serverlessTmpDirPath, zipFileName); - return Promise.resolve(); - } - - optimize(evt) { - // Validate: Check Serverless version - if (parseInt(S._version.split('.')[1], 10) < 5) { - SCli.log('WARNING: This version of the Serverless Optimizer Plugin ' + - 'will not work with a version of Serverless that is less than v0.5'); - } - - // Get function - const project = S.getProject(); - const func = project.getFunction(evt.options.name); - - if (func.runtime === 'nodejs' || func.runtime === 'nodejs4.3') { - const projectPath = S.config.projectPath; - const config = getConfig( - projectPath, - project.toObjectPopulated(evt.options), - func.toObjectPopulated(evt.options) - ); - - if (config.webpackConfig) { - const pathDist = evt.options.pathDist; - const optimizedPath = path.join(pathDist, 'optimized'); - const optimizedModulesPath = path.join(optimizedPath, 'node_modules'); - - const webpackConfig = Object.assign({}, config.webpackConfig); - const handlerName = func.getHandler().split('.')[0]; - const handlerFileName = `${handlerName}.${config.handlerExt}`; - const handlerEntryPath = `./${handlerFileName}`; - - // override entry and output - webpackConfig.context = path.dirname(func.getFilePath()); - if (Array.isArray(webpackConfig.entry)) { - webpackConfig.entry.push(handlerEntryPath); - } else { - webpackConfig.entry = handlerEntryPath; - } - webpackConfig.output = { - libraryTarget: 'commonjs', - path: optimizedPath, - filename: handlerFileName - }; - - // copy generated handler so we can build directly from the source directory - const generatedHandler = path.join(webpackConfig.context, handlerFileName); - - return fs.copyAsync(path.join(pathDist, handlerFileName), generatedHandler) - .then(() => fs.mkdirsAsync(optimizedModulesPath)) - .then(() => runWebpack(webpackConfig)) - .then((stats) => { - logStats(stats); - const externals = getExternalsFromStats(stats); - return copyModules(projectPath, externals, optimizedModulesPath); - }) - .then(() => { - evt.options.pathDist = optimizedPath; // eslint-disable-line - return evt; - }) - // delete generated handler we copied above - .finally(() => fs.removeAsync(generatedHandler)); - } - } - - return Promise.resolve(evt); - } + this.serverless.utils.writeFileSync(artifactFilePath, data); + this.serverless.service.package.artifact = artifactFilePath; + }); } - - return ServerlessWebpack; }; diff --git a/package.json b/package.json index 93864a4..fe8f962 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,7 @@ "test": "NODE_PATH=. mocha \"test/**/*.test.js\"" }, "peerDependencies": { - "webpack": "^1.12.14" + "webpack": "^1.13.1" }, "devDependencies": { "chai": "^3.4.1", @@ -43,6 +43,8 @@ "dependencies": { "bluebird": "^3.1.1", "clone": "^1.0.2", - "fs-extra": "^0.26.7" + "fs-extra": "^0.26.7", + "lodash": "^4.14.0", + "node-zip": "^1.1.1" } } From 7c4a093a976f48b013cab9dc9235cca9829852e6 Mon Sep 17 00:00:00 2001 From: Stuart Harris Date: Thu, 4 Aug 2016 09:42:58 +0100 Subject: [PATCH 02/12] 1.0-beta.1 --- index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/index.js b/index.js index 034ad1c..34ead3c 100644 --- a/index.js +++ b/index.js @@ -44,9 +44,9 @@ module.exports = class ServerlessWebpack { } optimize() { - if (this.serverless.getVersion() !== '1.0.0-alpha.2') { + if (this.serverless.getVersion() !== '1.0.0-beta.1') { throw new this.serverless.classes.Error( - 'WARNING: This version of serverless-webpack-plugin needs Serverless 1.0.0-alpha.2' + 'WARNING: This version of serverless-webpack-plugin needs Serverless 1.0.0-beta.1' ); } const servicePath = this.serverless.config.servicePath; From fca5e29123484ddc1343d29ce03d37022d23f203 Mon Sep 17 00:00:00 2001 From: Stuart Harris Date: Sat, 6 Aug 2016 13:20:16 +0100 Subject: [PATCH 03/12] es6, lint and build --- .babelrc | 3 + .eslintignore | 1 + .gitignore | 3 +- 1.0/index.js | 128 +++++++++++++++++++++++ 1.0/src/.eslintrc.yaml | 9 ++ 1.0/src/index.js | 89 ++++++++++++++++ README.md | 38 ++++--- index.js | 160 +++++++++++++++++------------ lib/copyModules.js | 3 +- lib/getConfig.js | 5 +- lib/getExternalsFromStats.js | 1 - package.json | 18 +++- test/getConfig.test.js | 2 +- test/getExternalsFromStats.test.js | 4 +- 14 files changed, 373 insertions(+), 91 deletions(-) create mode 100644 .babelrc create mode 100644 1.0/index.js create mode 100644 1.0/src/.eslintrc.yaml create mode 100644 1.0/src/index.js diff --git a/.babelrc b/.babelrc new file mode 100644 index 0000000..eaf3238 --- /dev/null +++ b/.babelrc @@ -0,0 +1,3 @@ +{ + "presets": ["es2015", "stage-0"] +} diff --git a/.eslintignore b/.eslintignore index 3c3629e..d1094cb 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1 +1,2 @@ node_modules +1.0/index.js diff --git a/.gitignore b/.gitignore index f897b5a..56d370a 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ logs *.log npm-debug.log +.eslintcache # Runtime data pids @@ -37,4 +38,4 @@ node_modules #SERVERLESS STUFF admin.env -.env \ No newline at end of file +.env diff --git a/1.0/index.js b/1.0/index.js new file mode 100644 index 0000000..f4f9d49 --- /dev/null +++ b/1.0/index.js @@ -0,0 +1,128 @@ +'use strict'; + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +var runWebpack = function () { + var _ref = _asyncToGenerator(regeneratorRuntime.mark(function _callee(config) { + return regeneratorRuntime.wrap(function _callee$(_context) { + while (1) { + switch (_context.prev = _context.next) { + case 0: + return _context.abrupt('return', new Promise(function (resolve, reject) { + (0, _webpack2.default)(config).run(function (err, stats) { + if (err) { + return reject(err); + } + resolve(stats); + }); + })); + + case 1: + case 'end': + return _context.stop(); + } + } + }, _callee, this); + })); + + return function runWebpack(_x) { + return _ref.apply(this, arguments); + }; +}(); + +var _fs = require('fs'); + +var _fs2 = _interopRequireDefault(_fs); + +var _path = require('path'); + +var _path2 = _interopRequireDefault(_path); + +var _webpack = require('webpack'); + +var _webpack2 = _interopRequireDefault(_webpack); + +var _nodeZip = require('node-zip'); + +var _nodeZip2 = _interopRequireDefault(_nodeZip); + +var _fp = require('lodash/fp'); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { return step("next", value); }, function (err) { return step("throw", err); }); } } return step("next"); }); }; } + +function format(stats) { + return stats.toString({ + colors: true, + hash: false, + version: false, + chunks: false, + children: false + }); +} + +var artifact = 'handler.js'; + +module.exports = function () { + function ServerlessWebpack(serverless) { + _classCallCheck(this, ServerlessWebpack); + + this.serverless = serverless; + this.hooks = { + 'before:deploy:createDeploymentPackage': this.optimize.bind(this) + }; + } + + _createClass(ServerlessWebpack, [{ + key: 'optimize', + value: function optimize() { + var _this = this; + + if (!this.serverless.getVersion().startsWith('1.0')) { + throw new this.serverless.classes.Error('WARNING: This version of serverless-webpack-plugin needs Serverless 1.0'); + } + var servicePath = this.serverless.config.servicePath; + var serverlessTmpDirPath = _path2.default.join(servicePath, '.serverless'); + + var handlerNames = (0, _fp.uniq)((0, _fp.map)(function (f) { + return f.handler.split('.')[0]; + }, this.serverless.service.functions)); + var entrypoints = (0, _fp.map)(function (h) { + return './' + h + '.js'; + }, handlerNames); + + var webpackConfig = require(_path2.default.resolve(servicePath, './webpack.config.js')); + webpackConfig.context = servicePath; + webpackConfig.entry = (0, _fp.compact)((0, _fp.concat)(webpackConfig.entry, entrypoints)); + webpackConfig.output = { + libraryTarget: 'commonjs', + path: serverlessTmpDirPath, + filename: artifact + }; + + return runWebpack(webpackConfig).then(function (stats) { + return _this.serverless.cli.log(format(stats)); + }).then(function () { + var zip = new _nodeZip2.default(); + (0, _fp.forEach)(function (f) { + return zip.file(f, _fs2.default.readFileSync(_path2.default.resolve(serverlessTmpDirPath, f))); + }, [artifact, artifact + '.map']); + var data = zip.generate({ + type: 'nodebuffer', + compression: 'DEFLATE', + platform: process.platform + }); + var zipFileName = _this.serverless.service.service + '-' + new Date().getTime().toString() + '.zip'; + var artifactFilePath = _path2.default.resolve(serverlessTmpDirPath, zipFileName); + + _this.serverless.utils.writeFileSync(artifactFilePath, data); + _this.serverless.service.package.artifact = artifactFilePath; + }); + } + }]); + + return ServerlessWebpack; +}(); \ No newline at end of file diff --git a/1.0/src/.eslintrc.yaml b/1.0/src/.eslintrc.yaml new file mode 100644 index 0000000..6d1bb74 --- /dev/null +++ b/1.0/src/.eslintrc.yaml @@ -0,0 +1,9 @@ +--- +parser: babel-eslint +extends: airbnb +env: + es6: true +rules: + strict: 0 + object-shorthand: 0 + react/require-extension: 0 diff --git a/1.0/src/index.js b/1.0/src/index.js new file mode 100644 index 0000000..7e235fc --- /dev/null +++ b/1.0/src/index.js @@ -0,0 +1,89 @@ +import fs from 'fs'; +import path from 'path'; +import webpack from 'webpack'; +import Zip from 'node-zip'; + +import { + compact, + concat, + forEach, + map, + uniq, +} from 'lodash/fp'; + +async function runWebpack(config) { + return new Promise((resolve, reject) => { + webpack(config).run((err, stats) => { + if (err) { + return reject(err); + } + return resolve(stats); + }); + }); +} + +function format(stats) { + return stats.toString({ + colors: true, + hash: false, + version: false, + chunks: false, + children: false, + }); +} + +const artifact = 'handler.js'; + +const getConfig = servicePath => + require(path.resolve(servicePath, './webpack.config.js')); // eslint-disable-line global-require + +module.exports = class ServerlessWebpack { + constructor(serverless) { + this.serverless = serverless; + this.hooks = { + 'before:deploy:createDeploymentPackage': this.optimize.bind(this), + }; + } + + optimize() { + if (!this.serverless.getVersion().startsWith('1.0')) { + throw new this.serverless.classes.Error( + 'WARNING: This version of serverless-webpack-plugin needs Serverless 1.0' + ); + } + const servicePath = this.serverless.config.servicePath; + const serverlessTmpDirPath = path.join(servicePath, '.serverless'); + + const handlerNames = uniq(map(f => f.handler.split('.')[0], this.serverless.service.functions)); + const entrypoints = map(h => `./${h}.js`, handlerNames); + + const webpackConfig = getConfig(servicePath); + webpackConfig.context = servicePath; + webpackConfig.entry = compact(concat(webpackConfig.entry, entrypoints)); + webpackConfig.output = { + libraryTarget: 'commonjs', + path: serverlessTmpDirPath, + filename: artifact, + }; + + return runWebpack(webpackConfig) + .then(stats => this.serverless.cli.log(format(stats))) + .then(() => { + const zip = new Zip(); + forEach(f => + zip.file(f, fs.readFileSync(path.resolve(serverlessTmpDirPath, f)) + ), [artifact, `${artifact}.map`]); + const data = zip.generate({ + type: 'nodebuffer', + compression: 'DEFLATE', + platform: process.platform, + }); + const zipFileName = + `${this.serverless.service.service}-${(new Date).getTime().toString()}.zip`; + const artifactFilePath = path.resolve(serverlessTmpDirPath, zipFileName); + + this.serverless.utils.writeFileSync(artifactFilePath, data); + this.serverless.service.package.artifact = artifactFilePath; + }); + } +}; diff --git a/README.md b/README.md index 1ab5943..1840e51 100644 --- a/README.md +++ b/README.md @@ -1,25 +1,37 @@ Serverless Webpack Plugin ============================= -Forked from [serverless-optimizer-plugin](https://github.com/serverless/serverless-optimizer-plugin) this plugin uses +Forked from [serverless-optimizer-plugin](https://github.com/serverless/serverless-optimizer-plugin) this plugin uses webpack to optimize your Serverless Node.js Functions on deployment. -Reducing the file size of your AWS Lambda Functions allows AWS to provision them more quickly, speeding up the response +Reducing the file size of your AWS Lambda Functions allows AWS to provision them more quickly, speeding up the response time of your Lambdas. Smaller Lambda sizes also helps you develop faster because you can upload them faster. This Severless Plugin is absolutely recommended for every project including Lambdas with Node.js. -**Note:** Requires Serverless *v0.5.0*. +**Note:** Requires Serverless *v0.5.0* or Serverless *v1.0* ### Setup * Install the plugin and webpack in the root of your Serverless Project: -``` + +```sh npm install serverless-webpack-plugin webpack --save-dev ``` -* Add the plugin to the `plugins` array in your Serverless Project's `s-project.json`, like this: +#### Using with Serverless 1.0... +* Add the plugin to the `plugins` array in `serverless.yml`: + +```yaml +plugins: + - serverless-webpack-plugin/1.0 ``` + +#### Using with Serverless 0.5... + +* Add the plugin to the `plugins` array in your Serverless Project's `s-project.json`, like this: + +```json plugins: [ "serverless-webpack-plugin" ] @@ -85,13 +97,13 @@ module.exports = { } }; ``` -**Note:** Some node modules don't play nicely with `webpack.optimize.UglifyJsPlugin` in this case, you can omit it from +**Note:** Some node modules don't play nicely with `webpack.optimize.UglifyJsPlugin` in this case, you can omit it from your config, or add the offending modules to `externals`. For more on externals see below. ### Externals -Externals specified in your webpack config will be properly packaged into the deployment. -This is useful when working with modules that have binary dependencies, are incompatible with `webpack.optimize.UglifyJsPlugin` -or if you simply want to improve build performance. Check out [webpack-node-externals](https://github.com/liady/webpack-node-externals) +Externals specified in your webpack config will be properly packaged into the deployment. +This is useful when working with modules that have binary dependencies, are incompatible with `webpack.optimize.UglifyJsPlugin` +or if you simply want to improve build performance. Check out [webpack-node-externals](https://github.com/liady/webpack-node-externals) for an easy way to externalize all node modules. ### Source Maps @@ -103,8 +115,8 @@ you can specify those modules with entry option in your webpack config. For example if you need to load the babel-polyfill, you can do that by adding `entry: ['babel-polyfill']` to your webpack config. This will first load the babel-polyfill module and then your lambda function module. - + ### Improving deploy performance - -The plugin builds directly from the source files, using "magic handlers" to include the parent directory (as mentioned in -the [0.5.0 release notes](https://github.com/serverless/serverless/releases/tag/v0.5.0)) is unnecessary. + +The plugin builds directly from the source files, using "magic handlers" to include the parent directory (as mentioned in +the [0.5.0 release notes](https://github.com/serverless/serverless/releases/tag/v0.5.0)) is unnecessary. diff --git a/index.js b/index.js index 34ead3c..99f2656 100644 --- a/index.js +++ b/index.js @@ -1,16 +1,12 @@ -'use strict'; - -const fs = require('fs'); const path = require('path'); -const Promise = require('bluebird'); const webpack = require('webpack'); -const Zip = require('node-zip'); +const Promise = require('bluebird'); +const fs = Promise.promisifyAll(require('fs-extra')); + +const getConfig = require('./lib/getConfig'); +const getExternalsFromStats = require('./lib/getExternalsFromStats'); +const copyModules = require('./lib/copyModules'); -const compact = require('lodash/fp/compact'); -const concat = require('lodash/fp/concat'); -const forEach = require('lodash/fp/forEach'); -const map = require('lodash/fp/map'); -const uniq = require('lodash/fp/uniq'); function runWebpack(config) { return new Promise((resolve, reject) => { @@ -18,70 +14,104 @@ function runWebpack(config) { if (err) { return reject(err); } - resolve(stats); + return resolve(stats); }); }); } -function format(stats) { - return stats.toString({ - colors: true, - hash: false, - version: false, - chunks: false, - children: false - }); -} - -const artifact = 'handler.js'; +module.exports = function getPlugin(S) { + const SCli = require(S.getServerlessPath('utils/cli')); // eslint-disable-line global-require -module.exports = class ServerlessWebpack { - constructor(serverless) { - this.serverless = serverless; - this.hooks = { - 'before:deploy:createDeploymentPackage': this.optimize.bind(this) - }; + function logStats(stats) { + SCli.log(stats.toString({ + colors: true, + hash: false, + version: false, + chunks: false, + children: false + })); } - optimize() { - if (this.serverless.getVersion() !== '1.0.0-beta.1') { - throw new this.serverless.classes.Error( - 'WARNING: This version of serverless-webpack-plugin needs Serverless 1.0.0-beta.1' - ); + class ServerlessWebpack extends S.classes.Plugin { + + static getName() { + return `com.serverless.${ServerlessWebpack.name}`; } - const servicePath = this.serverless.config.servicePath; - const serverlessTmpDirPath = path.join(servicePath, '.serverless'); - - const handlerNames = uniq(map(f => f.handler.split('.')[0], this.serverless.service.functions)); - const entrypoints = map(h => `./${h}.js`, handlerNames); - - const webpackConfig = require(path.resolve(servicePath, './webpack.config.js')); - webpackConfig.context = servicePath; - webpackConfig.entry = compact(concat(webpackConfig.entry, entrypoints)); - webpackConfig.output = { - libraryTarget: 'commonjs', - path: serverlessTmpDirPath, - filename: artifact - }; - - return runWebpack(webpackConfig) - .then(stats => this.serverless.cli.log(format(stats))) - .then(() => { - const zip = new Zip(); - forEach(f => - zip.file(f, fs.readFileSync(path.resolve(serverlessTmpDirPath, f)) - ), [artifact, `${artifact}.map`]); - const data = zip.generate({ - type: 'nodebuffer', - compression: 'DEFLATE', - platform: process.platform, + + registerHooks() { + S.addHook(this.optimize.bind(this), { + action: 'codeDeployLambda', + event: 'pre' }); - const zipFileName = - `${this.serverless.service.service}-${(new Date).getTime().toString()}.zip`; - const artifactFilePath = path.resolve(serverlessTmpDirPath, zipFileName); - this.serverless.utils.writeFileSync(artifactFilePath, data); - this.serverless.service.package.artifact = artifactFilePath; - }); + return Promise.resolve(); + } + + optimize(evt) { + // Validate: Check Serverless version + if (parseInt(S._version.split('.')[1], 10) < 5) { // eslint-disable-line no-underscore-dangle + SCli.log('WARNING: This version of the Serverless Optimizer Plugin ' + + 'will not work with a version of Serverless that is less than v0.5'); + } + + // Get function + const project = S.getProject(); + const func = project.getFunction(evt.options.name); + + if (func.runtime === 'nodejs' || func.runtime === 'nodejs4.3') { + const projectPath = S.config.projectPath; + const config = getConfig( + projectPath, + project.toObjectPopulated(evt.options), + func.toObjectPopulated(evt.options) + ); + + if (config.webpackConfig) { + const pathDist = evt.options.pathDist; + const optimizedPath = path.join(pathDist, 'optimized'); + const optimizedModulesPath = path.join(optimizedPath, 'node_modules'); + + const webpackConfig = Object.assign({}, config.webpackConfig); + const handlerName = func.getHandler().split('.')[0]; + const handlerFileName = `${handlerName}.${config.handlerExt}`; + const handlerEntryPath = `./${handlerFileName}`; + + // override entry and output + webpackConfig.context = path.dirname(func.getFilePath()); + if (Array.isArray(webpackConfig.entry)) { + webpackConfig.entry.push(handlerEntryPath); + } else { + webpackConfig.entry = handlerEntryPath; + } + webpackConfig.output = { + libraryTarget: 'commonjs', + path: optimizedPath, + filename: handlerFileName + }; + + // copy generated handler so we can build directly from the source directory + const generatedHandler = path.join(webpackConfig.context, handlerFileName); + + return fs.copyAsync(path.join(pathDist, handlerFileName), generatedHandler) + .then(() => fs.mkdirsAsync(optimizedModulesPath)) + .then(() => runWebpack(webpackConfig)) + .then((stats) => { + logStats(stats); + const externals = getExternalsFromStats(stats); + return copyModules(projectPath, externals, optimizedModulesPath); + }) + .then(() => { + evt.options.pathDist = optimizedPath; // eslint-disable-line + return evt; + }) + // delete generated handler we copied above + .finally(() => fs.removeAsync(generatedHandler)); + } + } + + return Promise.resolve(evt); + } } + + return ServerlessWebpack; }; diff --git a/lib/copyModules.js b/lib/copyModules.js index 10030c4..5445956 100644 --- a/lib/copyModules.js +++ b/lib/copyModules.js @@ -1,4 +1,3 @@ -'use strict'; const path = require('path'); const childProcess = require('child_process'); const Promise = require('bluebird'); @@ -11,7 +10,7 @@ module.exports = function copyModules(projectPath, moduleNames, dest) { return Promise.resolve(); } - const pkg = require(path.join(projectPath, 'package.json')); + const pkg = require(path.join(projectPath, 'package.json')); // eslint-disable-line global-require const modulesAndVersions = moduleNames.map(moduleName => { const moduleVersion = pkg.dependencies[moduleName]; diff --git a/lib/getConfig.js b/lib/getConfig.js index 0a1396e..46fb8e3 100644 --- a/lib/getConfig.js +++ b/lib/getConfig.js @@ -1,4 +1,3 @@ -'use strict'; const path = require('path'); const clone = require('clone'); @@ -25,9 +24,9 @@ module.exports = function getConfig(projectPath, project, func) { if (config.configPath) { try { const configPath = path.join(projectPath, config.configPath); - config.webpackConfig = clone(require(configPath)); + config.webpackConfig = clone(require(configPath)); // eslint-disable-line global-require } catch (e) { - console.log(e); + console.log(e); // eslint-disable-line no-console } } diff --git a/lib/getExternalsFromStats.js b/lib/getExternalsFromStats.js index 97bb89e..6ce9e53 100644 --- a/lib/getExternalsFromStats.js +++ b/lib/getExternalsFromStats.js @@ -1,4 +1,3 @@ -'use strict'; const natives = process.binding('natives'); module.exports = function getExternalsFromStats(stats) { diff --git a/package.json b/package.json index fe8f962..f55cefc 100644 --- a/package.json +++ b/package.json @@ -29,22 +29,32 @@ "main": "index.js", "bin": {}, "scripts": { + "build": "babel -d 1.0 1.0/src/", + "lint": "eslint --quiet --cache .", + "prepublish": "npm run build", "test": "NODE_PATH=. mocha \"test/**/*.test.js\"" }, "peerDependencies": { "webpack": "^1.13.1" }, "devDependencies": { + "babel-cli": "^6.11.4", + "babel-eslint": "^6.1.2", + "babel-preset-es2015": "^6.13.2", + "babel-preset-stage-0": "^6.5.0", "chai": "^3.4.1", - "mocha": "^2.3.4", - "eslint": "^1.10.3", - "eslint-config-airbnb": "^5.0.0" + "eslint": "^2.13.1", + "eslint-config-airbnb": "^9.0.1", + "eslint-plugin-import": "^1.12.0", + "eslint-plugin-jsx-a11y": "^2.0.1", + "eslint-plugin-react": "^5.2.2", + "mocha": "^2.3.4" }, "dependencies": { "bluebird": "^3.1.1", "clone": "^1.0.2", "fs-extra": "^0.26.7", - "lodash": "^4.14.0", + "lodash": "^4.14.1", "node-zip": "^1.1.1" } } diff --git a/test/getConfig.test.js b/test/getConfig.test.js index 3d8cb09..a20088d 100644 --- a/test/getConfig.test.js +++ b/test/getConfig.test.js @@ -92,7 +92,7 @@ describe.only('getConfig', () => { }; const func = {}; const result = getConfig(projectPath, project, func); - const webpackConfig = require('./data/webpack.conf.js'); + const webpackConfig = require('./data/webpack.conf.js'); // eslint-disable-line global-require assert.notStrictEqual(result.webpackConfig, webpackConfig); assert.deepEqual(result, { diff --git a/test/getExternalsFromStats.test.js b/test/getExternalsFromStats.test.js index 058f9f3..b680824 100644 --- a/test/getExternalsFromStats.test.js +++ b/test/getExternalsFromStats.test.js @@ -4,7 +4,9 @@ const assert = require('chai').assert; function getStatsMock() { return { toJson() { - return { modules: require('./data/stats.json').slice(0) }; + return { + modules: require('./data/stats.json').slice(0) // eslint-disable-line global-require + }; } }; } From 82d0aed831a25f74e2e2ce19e89d5e04823452ea Mon Sep 17 00:00:00 2001 From: Stuart Harris Date: Sat, 6 Aug 2016 13:22:41 +0100 Subject: [PATCH 04/12] pre-commit lint and test --- package.json | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index f55cefc..8b9a66f 100644 --- a/package.json +++ b/package.json @@ -37,6 +37,10 @@ "peerDependencies": { "webpack": "^1.13.1" }, + "pre-commit": [ + "lint", + "test" + ], "devDependencies": { "babel-cli": "^6.11.4", "babel-eslint": "^6.1.2", @@ -48,7 +52,8 @@ "eslint-plugin-import": "^1.12.0", "eslint-plugin-jsx-a11y": "^2.0.1", "eslint-plugin-react": "^5.2.2", - "mocha": "^2.3.4" + "mocha": "^2.3.4", + "pre-commit": "^1.1.3" }, "dependencies": { "bluebird": "^3.1.1", From adca0b5376bb40b3b101192d17b75d6864449096 Mon Sep 17 00:00:00 2001 From: Stuart Harris Date: Sat, 6 Aug 2016 13:34:01 +0100 Subject: [PATCH 05/12] babel transform runtime (polyfill) --- .babelrc | 3 ++- package.json | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.babelrc b/.babelrc index eaf3238..d5876c1 100644 --- a/.babelrc +++ b/.babelrc @@ -1,3 +1,4 @@ { - "presets": ["es2015", "stage-0"] + "presets": ["es2015", "stage-0"], + "plugins": ["transform-runtime"] } diff --git a/package.json b/package.json index 8b9a66f..2df7913 100644 --- a/package.json +++ b/package.json @@ -44,6 +44,7 @@ "devDependencies": { "babel-cli": "^6.11.4", "babel-eslint": "^6.1.2", + "babel-plugin-transform-runtime": "^6.12.0", "babel-preset-es2015": "^6.13.2", "babel-preset-stage-0": "^6.5.0", "chai": "^3.4.1", From 01315dde52c3827fea2f8455df730abef76bcf94 Mon Sep 17 00:00:00 2001 From: Stuart Harris Date: Sat, 6 Aug 2016 13:40:28 +0100 Subject: [PATCH 06/12] add files to package.json --- package.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/package.json b/package.json index 2df7913..86f0433 100644 --- a/package.json +++ b/package.json @@ -27,6 +27,11 @@ "serverless.com" ], "main": "index.js", + "files": [ + "index.js", + "lib", + "1.0/index.js" + ], "bin": {}, "scripts": { "build": "babel -d 1.0 1.0/src/", From fbe39319d8dd758ef8b8713b2a2eb7068142b3c4 Mon Sep 17 00:00:00 2001 From: Stuart Harris Date: Sat, 6 Aug 2016 13:41:32 +0100 Subject: [PATCH 07/12] es6 modules --- 1.0/index.js | 45 +++++++++++++++++++++++++++++++-------------- 1.0/src/index.js | 6 +++--- 2 files changed, 34 insertions(+), 17 deletions(-) diff --git a/1.0/index.js b/1.0/index.js index f4f9d49..a96424d 100644 --- a/1.0/index.js +++ b/1.0/index.js @@ -1,19 +1,37 @@ 'use strict'; -var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); +var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); + +var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); + +var _createClass2 = require('babel-runtime/helpers/createClass'); + +var _createClass3 = _interopRequireDefault(_createClass2); + +var _regenerator = require('babel-runtime/regenerator'); + +var _regenerator2 = _interopRequireDefault(_regenerator); + +var _promise = require('babel-runtime/core-js/promise'); + +var _promise2 = _interopRequireDefault(_promise); + +var _asyncToGenerator2 = require('babel-runtime/helpers/asyncToGenerator'); + +var _asyncToGenerator3 = _interopRequireDefault(_asyncToGenerator2); var runWebpack = function () { - var _ref = _asyncToGenerator(regeneratorRuntime.mark(function _callee(config) { - return regeneratorRuntime.wrap(function _callee$(_context) { + var _ref = (0, _asyncToGenerator3.default)(_regenerator2.default.mark(function _callee(config) { + return _regenerator2.default.wrap(function _callee$(_context) { while (1) { switch (_context.prev = _context.next) { case 0: - return _context.abrupt('return', new Promise(function (resolve, reject) { + return _context.abrupt('return', new _promise2.default(function (resolve, reject) { (0, _webpack2.default)(config).run(function (err, stats) { if (err) { return reject(err); } - resolve(stats); + return resolve(stats); }); })); @@ -50,10 +68,6 @@ var _fp = require('lodash/fp'); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } -function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } - -function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { return step("next", value); }, function (err) { return step("throw", err); }); } } return step("next"); }); }; } - function format(stats) { return stats.toString({ colors: true, @@ -66,9 +80,13 @@ function format(stats) { var artifact = 'handler.js'; +var getConfig = function getConfig(servicePath) { + return require(_path2.default.resolve(servicePath, './webpack.config.js')); +}; // eslint-disable-line global-require + module.exports = function () { function ServerlessWebpack(serverless) { - _classCallCheck(this, ServerlessWebpack); + (0, _classCallCheck3.default)(this, ServerlessWebpack); this.serverless = serverless; this.hooks = { @@ -76,13 +94,13 @@ module.exports = function () { }; } - _createClass(ServerlessWebpack, [{ + (0, _createClass3.default)(ServerlessWebpack, [{ key: 'optimize', value: function optimize() { var _this = this; if (!this.serverless.getVersion().startsWith('1.0')) { - throw new this.serverless.classes.Error('WARNING: This version of serverless-webpack-plugin needs Serverless 1.0'); + throw new this.serverless.classes.Error('This version of serverless-webpack-plugin requires Serverless 1.0'); } var servicePath = this.serverless.config.servicePath; var serverlessTmpDirPath = _path2.default.join(servicePath, '.serverless'); @@ -94,7 +112,7 @@ module.exports = function () { return './' + h + '.js'; }, handlerNames); - var webpackConfig = require(_path2.default.resolve(servicePath, './webpack.config.js')); + var webpackConfig = getConfig(servicePath); webpackConfig.context = servicePath; webpackConfig.entry = (0, _fp.compact)((0, _fp.concat)(webpackConfig.entry, entrypoints)); webpackConfig.output = { @@ -123,6 +141,5 @@ module.exports = function () { }); } }]); - return ServerlessWebpack; }(); \ No newline at end of file diff --git a/1.0/src/index.js b/1.0/src/index.js index 7e235fc..ac93c73 100644 --- a/1.0/src/index.js +++ b/1.0/src/index.js @@ -37,7 +37,7 @@ const artifact = 'handler.js'; const getConfig = servicePath => require(path.resolve(servicePath, './webpack.config.js')); // eslint-disable-line global-require -module.exports = class ServerlessWebpack { +export default class ServerlessWebpack { constructor(serverless) { this.serverless = serverless; this.hooks = { @@ -48,7 +48,7 @@ module.exports = class ServerlessWebpack { optimize() { if (!this.serverless.getVersion().startsWith('1.0')) { throw new this.serverless.classes.Error( - 'WARNING: This version of serverless-webpack-plugin needs Serverless 1.0' + 'This version of serverless-webpack-plugin requires Serverless 1.0' ); } const servicePath = this.serverless.config.servicePath; @@ -86,4 +86,4 @@ module.exports = class ServerlessWebpack { this.serverless.service.package.artifact = artifactFilePath; }); } -}; +} From b903ff77ac4467fd330a9e06e813d269a64bab17 Mon Sep 17 00:00:00 2001 From: Stuart Harris Date: Sun, 7 Aug 2016 14:16:08 +0100 Subject: [PATCH 08/12] build output on pre-commit --- 1.0/index.js | 122 ++++++++++++++++++++++++++++++++------------------- package.json | 5 ++- 2 files changed, 82 insertions(+), 45 deletions(-) diff --git a/1.0/index.js b/1.0/index.js index a96424d..812d82f 100644 --- a/1.0/index.js +++ b/1.0/index.js @@ -1,5 +1,9 @@ 'use strict'; +Object.defineProperty(exports, "__esModule", { + value: true +}); + var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); @@ -84,7 +88,7 @@ var getConfig = function getConfig(servicePath) { return require(_path2.default.resolve(servicePath, './webpack.config.js')); }; // eslint-disable-line global-require -module.exports = function () { +var ServerlessWebpack = function () { function ServerlessWebpack(serverless) { (0, _classCallCheck3.default)(this, ServerlessWebpack); @@ -96,50 +100,80 @@ module.exports = function () { (0, _createClass3.default)(ServerlessWebpack, [{ key: 'optimize', - value: function optimize() { - var _this = this; + value: function () { + var _ref2 = (0, _asyncToGenerator3.default)(_regenerator2.default.mark(function _callee2() { + var servicePath, serverlessTmpDirPath, handlerNames, entrypoints, webpackConfig, stats, zip, data, zipFileName, artifactFilePath; + return _regenerator2.default.wrap(function _callee2$(_context2) { + while (1) { + switch (_context2.prev = _context2.next) { + case 0: + if (this.serverless.getVersion().startsWith('1.0')) { + _context2.next = 2; + break; + } - if (!this.serverless.getVersion().startsWith('1.0')) { - throw new this.serverless.classes.Error('This version of serverless-webpack-plugin requires Serverless 1.0'); + throw new this.serverless.classes.Error('This version of serverless-webpack-plugin requires Serverless 1.0'); + + case 2: + servicePath = this.serverless.config.servicePath; + serverlessTmpDirPath = _path2.default.join(servicePath, '.serverless'); + handlerNames = (0, _fp.uniq)((0, _fp.map)(function (f) { + return f.handler.split('.')[0]; + }, this.serverless.service.functions)); + entrypoints = (0, _fp.map)(function (h) { + return './' + h + '.js'; + }, handlerNames); + webpackConfig = getConfig(servicePath); + + webpackConfig.context = servicePath; + webpackConfig.entry = (0, _fp.compact)((0, _fp.concat)(webpackConfig.entry, entrypoints)); + webpackConfig.output = { + libraryTarget: 'commonjs', + path: serverlessTmpDirPath, + filename: artifact + }; + + _context2.next = 12; + return runWebpack(webpackConfig); + + case 12: + stats = _context2.sent; + + this.serverless.cli.log(format(stats)); + + zip = new _nodeZip2.default(); + + (0, _fp.forEach)(function (f) { + return zip.file(f, _fs2.default.readFileSync(_path2.default.resolve(serverlessTmpDirPath, f))); + }, [artifact, artifact + '.map']); + data = zip.generate({ + type: 'nodebuffer', + compression: 'DEFLATE', + platform: process.platform + }); + zipFileName = this.serverless.service.service + '-' + new Date().getTime().toString() + '.zip'; + artifactFilePath = _path2.default.resolve(serverlessTmpDirPath, zipFileName); + + + this.serverless.utils.writeFileSync(artifactFilePath, data); + this.serverless.service.package.artifact = artifactFilePath; + + case 21: + case 'end': + return _context2.stop(); + } + } + }, _callee2, this); + })); + + function optimize() { + return _ref2.apply(this, arguments); } - var servicePath = this.serverless.config.servicePath; - var serverlessTmpDirPath = _path2.default.join(servicePath, '.serverless'); - - var handlerNames = (0, _fp.uniq)((0, _fp.map)(function (f) { - return f.handler.split('.')[0]; - }, this.serverless.service.functions)); - var entrypoints = (0, _fp.map)(function (h) { - return './' + h + '.js'; - }, handlerNames); - - var webpackConfig = getConfig(servicePath); - webpackConfig.context = servicePath; - webpackConfig.entry = (0, _fp.compact)((0, _fp.concat)(webpackConfig.entry, entrypoints)); - webpackConfig.output = { - libraryTarget: 'commonjs', - path: serverlessTmpDirPath, - filename: artifact - }; - - return runWebpack(webpackConfig).then(function (stats) { - return _this.serverless.cli.log(format(stats)); - }).then(function () { - var zip = new _nodeZip2.default(); - (0, _fp.forEach)(function (f) { - return zip.file(f, _fs2.default.readFileSync(_path2.default.resolve(serverlessTmpDirPath, f))); - }, [artifact, artifact + '.map']); - var data = zip.generate({ - type: 'nodebuffer', - compression: 'DEFLATE', - platform: process.platform - }); - var zipFileName = _this.serverless.service.service + '-' + new Date().getTime().toString() + '.zip'; - var artifactFilePath = _path2.default.resolve(serverlessTmpDirPath, zipFileName); - - _this.serverless.utils.writeFileSync(artifactFilePath, data); - _this.serverless.service.package.artifact = artifactFilePath; - }); - } + + return optimize; + }() }]); return ServerlessWebpack; -}(); \ No newline at end of file +}(); + +exports.default = ServerlessWebpack; \ No newline at end of file diff --git a/package.json b/package.json index 86f0433..114b14f 100644 --- a/package.json +++ b/package.json @@ -34,6 +34,7 @@ ], "bin": {}, "scripts": { + "add-artifacts": "git add 1.0/index.js", "build": "babel -d 1.0 1.0/src/", "lint": "eslint --quiet --cache .", "prepublish": "npm run build", @@ -44,7 +45,9 @@ }, "pre-commit": [ "lint", - "test" + "test", + "build", + "add-artifacts" ], "devDependencies": { "babel-cli": "^6.11.4", From 6cd12f7f6259f0bb1d9d18c9c756f93911e78045 Mon Sep 17 00:00:00 2001 From: Stuart Harris Date: Sun, 7 Aug 2016 14:55:43 +0100 Subject: [PATCH 09/12] revert to module.exports as plugin system fails with babel 6 export default --- 1.0/index.js | 98 +++++++++++++++++++++++++++++++++++------------- 1.0/src/index.js | 49 ++++++++++++------------ 2 files changed, 97 insertions(+), 50 deletions(-) diff --git a/1.0/index.js b/1.0/index.js index 812d82f..96f1898 100644 --- a/1.0/index.js +++ b/1.0/index.js @@ -1,9 +1,5 @@ 'use strict'; -Object.defineProperty(exports, "__esModule", { - value: true -}); - var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); @@ -88,7 +84,62 @@ var getConfig = function getConfig(servicePath) { return require(_path2.default.resolve(servicePath, './webpack.config.js')); }; // eslint-disable-line global-require -var ServerlessWebpack = function () { +var zip = function () { + var _ref2 = (0, _asyncToGenerator3.default)(_regenerator2.default.mark(function _callee3(zipper, readFile, tmpDir) { + return _regenerator2.default.wrap(function _callee3$(_context3) { + while (1) { + switch (_context3.prev = _context3.next) { + case 0: + _context3.next = 2; + return _promise2.default.all((0, _fp.map)(function () { + var _ref3 = (0, _asyncToGenerator3.default)(_regenerator2.default.mark(function _callee2(file) { + return _regenerator2.default.wrap(function _callee2$(_context2) { + while (1) { + switch (_context2.prev = _context2.next) { + case 0: + _context2.t0 = zipper; + _context2.t1 = file; + _context2.next = 4; + return readFile(_path2.default.resolve(tmpDir, file)); + + case 4: + _context2.t2 = _context2.sent; + return _context2.abrupt('return', _context2.t0.file.call(_context2.t0, _context2.t1, _context2.t2)); + + case 6: + case 'end': + return _context2.stop(); + } + } + }, _callee2, undefined); + })); + + return function (_x5) { + return _ref3.apply(this, arguments); + }; + }(), [artifact, artifact + '.map'])); + + case 2: + return _context3.abrupt('return', zipper.generate({ + type: 'nodebuffer', + compression: 'DEFLATE', + platform: process.platform + })); + + case 3: + case 'end': + return _context3.stop(); + } + } + }, _callee3, undefined); + })); + + return function zip(_x2, _x3, _x4) { + return _ref2.apply(this, arguments); + }; +}(); + +module.exports = function () { function ServerlessWebpack(serverless) { (0, _classCallCheck3.default)(this, ServerlessWebpack); @@ -101,14 +152,14 @@ var ServerlessWebpack = function () { (0, _createClass3.default)(ServerlessWebpack, [{ key: 'optimize', value: function () { - var _ref2 = (0, _asyncToGenerator3.default)(_regenerator2.default.mark(function _callee2() { - var servicePath, serverlessTmpDirPath, handlerNames, entrypoints, webpackConfig, stats, zip, data, zipFileName, artifactFilePath; - return _regenerator2.default.wrap(function _callee2$(_context2) { + var _ref4 = (0, _asyncToGenerator3.default)(_regenerator2.default.mark(function _callee4() { + var servicePath, serverlessTmpDirPath, handlerNames, entrypoints, webpackConfig, stats, data, zipFileName, artifactFilePath; + return _regenerator2.default.wrap(function _callee4$(_context4) { while (1) { - switch (_context2.prev = _context2.next) { + switch (_context4.prev = _context4.next) { case 0: if (this.serverless.getVersion().startsWith('1.0')) { - _context2.next = 2; + _context4.next = 2; break; } @@ -133,24 +184,19 @@ var ServerlessWebpack = function () { filename: artifact }; - _context2.next = 12; + _context4.next = 12; return runWebpack(webpackConfig); case 12: - stats = _context2.sent; + stats = _context4.sent; this.serverless.cli.log(format(stats)); - zip = new _nodeZip2.default(); + _context4.next = 16; + return zip(new _nodeZip2.default(), _fs2.default.readFile, serverlessTmpDirPath); - (0, _fp.forEach)(function (f) { - return zip.file(f, _fs2.default.readFileSync(_path2.default.resolve(serverlessTmpDirPath, f))); - }, [artifact, artifact + '.map']); - data = zip.generate({ - type: 'nodebuffer', - compression: 'DEFLATE', - platform: process.platform - }); + case 16: + data = _context4.sent; zipFileName = this.serverless.service.service + '-' + new Date().getTime().toString() + '.zip'; artifactFilePath = _path2.default.resolve(serverlessTmpDirPath, zipFileName); @@ -160,20 +206,18 @@ var ServerlessWebpack = function () { case 21: case 'end': - return _context2.stop(); + return _context4.stop(); } } - }, _callee2, this); + }, _callee4, this); })); function optimize() { - return _ref2.apply(this, arguments); + return _ref4.apply(this, arguments); } return optimize; }() }]); return ServerlessWebpack; -}(); - -exports.default = ServerlessWebpack; \ No newline at end of file +}(); \ No newline at end of file diff --git a/1.0/src/index.js b/1.0/src/index.js index ac93c73..8e426de 100644 --- a/1.0/src/index.js +++ b/1.0/src/index.js @@ -6,7 +6,6 @@ import Zip from 'node-zip'; import { compact, concat, - forEach, map, uniq, } from 'lodash/fp'; @@ -37,7 +36,18 @@ const artifact = 'handler.js'; const getConfig = servicePath => require(path.resolve(servicePath, './webpack.config.js')); // eslint-disable-line global-require -export default class ServerlessWebpack { +const zip = async (zipper, readFile, tmpDir) => { + await Promise.all(map(async file => + zipper.file(file, await readFile(path.resolve(tmpDir, file)) + ), [artifact, `${artifact}.map`])); + return zipper.generate({ + type: 'nodebuffer', + compression: 'DEFLATE', + platform: process.platform, + }); +}; + +module.exports = class ServerlessWebpack { constructor(serverless) { this.serverless = serverless; this.hooks = { @@ -45,7 +55,7 @@ export default class ServerlessWebpack { }; } - optimize() { + async optimize() { if (!this.serverless.getVersion().startsWith('1.0')) { throw new this.serverless.classes.Error( 'This version of serverless-webpack-plugin requires Serverless 1.0' @@ -54,7 +64,8 @@ export default class ServerlessWebpack { const servicePath = this.serverless.config.servicePath; const serverlessTmpDirPath = path.join(servicePath, '.serverless'); - const handlerNames = uniq(map(f => f.handler.split('.')[0], this.serverless.service.functions)); + const handlerNames = uniq(map(f => + f.handler.split('.')[0], this.serverless.service.functions)); const entrypoints = map(h => `./${h}.js`, handlerNames); const webpackConfig = getConfig(servicePath); @@ -66,24 +77,16 @@ export default class ServerlessWebpack { filename: artifact, }; - return runWebpack(webpackConfig) - .then(stats => this.serverless.cli.log(format(stats))) - .then(() => { - const zip = new Zip(); - forEach(f => - zip.file(f, fs.readFileSync(path.resolve(serverlessTmpDirPath, f)) - ), [artifact, `${artifact}.map`]); - const data = zip.generate({ - type: 'nodebuffer', - compression: 'DEFLATE', - platform: process.platform, - }); - const zipFileName = - `${this.serverless.service.service}-${(new Date).getTime().toString()}.zip`; - const artifactFilePath = path.resolve(serverlessTmpDirPath, zipFileName); + const stats = await runWebpack(webpackConfig); + this.serverless.cli.log(format(stats)); - this.serverless.utils.writeFileSync(artifactFilePath, data); - this.serverless.service.package.artifact = artifactFilePath; - }); + const data = await zip(new Zip(), fs.readFile, serverlessTmpDirPath); + + const zipFileName = + `${this.serverless.service.service}-${(new Date).getTime().toString()}.zip`; + const artifactFilePath = path.resolve(serverlessTmpDirPath, zipFileName); + + this.serverless.utils.writeFileSync(artifactFilePath, data); + this.serverless.service.package.artifact = artifactFilePath; } -} +}; From a9235521ef395513d48f6ca41bf6779744d8ebdb Mon Sep 17 00:00:00 2001 From: Stuart Harris Date: Sun, 7 Aug 2016 15:30:24 +0100 Subject: [PATCH 10/12] fix zip bug --- 1.0/index.js | 90 +++++++++++------------------------------------- 1.0/src/index.js | 11 +++--- 2 files changed, 27 insertions(+), 74 deletions(-) diff --git a/1.0/index.js b/1.0/index.js index 96f1898..eed655f 100644 --- a/1.0/index.js +++ b/1.0/index.js @@ -84,60 +84,16 @@ var getConfig = function getConfig(servicePath) { return require(_path2.default.resolve(servicePath, './webpack.config.js')); }; // eslint-disable-line global-require -var zip = function () { - var _ref2 = (0, _asyncToGenerator3.default)(_regenerator2.default.mark(function _callee3(zipper, readFile, tmpDir) { - return _regenerator2.default.wrap(function _callee3$(_context3) { - while (1) { - switch (_context3.prev = _context3.next) { - case 0: - _context3.next = 2; - return _promise2.default.all((0, _fp.map)(function () { - var _ref3 = (0, _asyncToGenerator3.default)(_regenerator2.default.mark(function _callee2(file) { - return _regenerator2.default.wrap(function _callee2$(_context2) { - while (1) { - switch (_context2.prev = _context2.next) { - case 0: - _context2.t0 = zipper; - _context2.t1 = file; - _context2.next = 4; - return readFile(_path2.default.resolve(tmpDir, file)); - - case 4: - _context2.t2 = _context2.sent; - return _context2.abrupt('return', _context2.t0.file.call(_context2.t0, _context2.t1, _context2.t2)); - - case 6: - case 'end': - return _context2.stop(); - } - } - }, _callee2, undefined); - })); - - return function (_x5) { - return _ref3.apply(this, arguments); - }; - }(), [artifact, artifact + '.map'])); - - case 2: - return _context3.abrupt('return', zipper.generate({ - type: 'nodebuffer', - compression: 'DEFLATE', - platform: process.platform - })); - - case 3: - case 'end': - return _context3.stop(); - } - } - }, _callee3, undefined); - })); - - return function zip(_x2, _x3, _x4) { - return _ref2.apply(this, arguments); - }; -}(); +var zip = function zip(zipper, readFile, tmpDir) { + (0, _fp.forEach)(function (file) { + return zipper.file(file, readFile(_path2.default.resolve(tmpDir, file))); + }, [artifact, artifact + '.map']); + return zipper.generate({ + type: 'nodebuffer', + compression: 'DEFLATE', + platform: process.platform + }); +}; module.exports = function () { function ServerlessWebpack(serverless) { @@ -152,14 +108,14 @@ module.exports = function () { (0, _createClass3.default)(ServerlessWebpack, [{ key: 'optimize', value: function () { - var _ref4 = (0, _asyncToGenerator3.default)(_regenerator2.default.mark(function _callee4() { + var _ref2 = (0, _asyncToGenerator3.default)(_regenerator2.default.mark(function _callee2() { var servicePath, serverlessTmpDirPath, handlerNames, entrypoints, webpackConfig, stats, data, zipFileName, artifactFilePath; - return _regenerator2.default.wrap(function _callee4$(_context4) { + return _regenerator2.default.wrap(function _callee2$(_context2) { while (1) { - switch (_context4.prev = _context4.next) { + switch (_context2.prev = _context2.next) { case 0: if (this.serverless.getVersion().startsWith('1.0')) { - _context4.next = 2; + _context2.next = 2; break; } @@ -184,19 +140,15 @@ module.exports = function () { filename: artifact }; - _context4.next = 12; + _context2.next = 12; return runWebpack(webpackConfig); case 12: - stats = _context4.sent; + stats = _context2.sent; this.serverless.cli.log(format(stats)); - _context4.next = 16; - return zip(new _nodeZip2.default(), _fs2.default.readFile, serverlessTmpDirPath); - - case 16: - data = _context4.sent; + data = zip(new _nodeZip2.default(), _fs2.default.readFileSync, serverlessTmpDirPath); zipFileName = this.serverless.service.service + '-' + new Date().getTime().toString() + '.zip'; artifactFilePath = _path2.default.resolve(serverlessTmpDirPath, zipFileName); @@ -204,16 +156,16 @@ module.exports = function () { this.serverless.utils.writeFileSync(artifactFilePath, data); this.serverless.service.package.artifact = artifactFilePath; - case 21: + case 19: case 'end': - return _context4.stop(); + return _context2.stop(); } } - }, _callee4, this); + }, _callee2, this); })); function optimize() { - return _ref4.apply(this, arguments); + return _ref2.apply(this, arguments); } return optimize; diff --git a/1.0/src/index.js b/1.0/src/index.js index 8e426de..f9f53c2 100644 --- a/1.0/src/index.js +++ b/1.0/src/index.js @@ -6,6 +6,7 @@ import Zip from 'node-zip'; import { compact, concat, + forEach, map, uniq, } from 'lodash/fp'; @@ -36,10 +37,10 @@ const artifact = 'handler.js'; const getConfig = servicePath => require(path.resolve(servicePath, './webpack.config.js')); // eslint-disable-line global-require -const zip = async (zipper, readFile, tmpDir) => { - await Promise.all(map(async file => - zipper.file(file, await readFile(path.resolve(tmpDir, file)) - ), [artifact, `${artifact}.map`])); +const zip = (zipper, readFile, tmpDir) => { + forEach(file => + zipper.file(file, readFile(path.resolve(tmpDir, file)) + ), [artifact, `${artifact}.map`]); return zipper.generate({ type: 'nodebuffer', compression: 'DEFLATE', @@ -80,7 +81,7 @@ module.exports = class ServerlessWebpack { const stats = await runWebpack(webpackConfig); this.serverless.cli.log(format(stats)); - const data = await zip(new Zip(), fs.readFile, serverlessTmpDirPath); + const data = zip(new Zip(), fs.readFileSync, serverlessTmpDirPath); const zipFileName = `${this.serverless.service.service}-${(new Date).getTime().toString()}.zip`; From b06a99688a34690ef7f463f9e6ccb4d0ed95cae0 Mon Sep 17 00:00:00 2001 From: Stuart Harris Date: Sat, 17 Sep 2016 17:06:48 +0100 Subject: [PATCH 11/12] event hook name change to createDeploymentArtifacts --- 1.0/index.js | 2 +- 1.0/src/index.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/1.0/index.js b/1.0/index.js index eed655f..71096d3 100644 --- a/1.0/index.js +++ b/1.0/index.js @@ -101,7 +101,7 @@ module.exports = function () { this.serverless = serverless; this.hooks = { - 'before:deploy:createDeploymentPackage': this.optimize.bind(this) + 'before:deploy:createDeploymentArtifacts': this.optimize.bind(this) }; } diff --git a/1.0/src/index.js b/1.0/src/index.js index f9f53c2..67b5feb 100644 --- a/1.0/src/index.js +++ b/1.0/src/index.js @@ -52,7 +52,7 @@ module.exports = class ServerlessWebpack { constructor(serverless) { this.serverless = serverless; this.hooks = { - 'before:deploy:createDeploymentPackage': this.optimize.bind(this), + 'before:deploy:createDeploymentArtifacts': this.optimize.bind(this), }; } From ff70dc269a9b5b37d26104e07675ecd1d7194bf8 Mon Sep 17 00:00:00 2001 From: Stuart Harris Date: Sun, 18 Sep 2016 13:00:40 +0100 Subject: [PATCH 12/12] zip all webpack output --- 1.0/index.js | 21 ++++++++++++--------- 1.0/src/index.js | 12 +++++++----- 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/1.0/index.js b/1.0/index.js index 71096d3..92dacd5 100644 --- a/1.0/index.js +++ b/1.0/index.js @@ -84,10 +84,10 @@ var getConfig = function getConfig(servicePath) { return require(_path2.default.resolve(servicePath, './webpack.config.js')); }; // eslint-disable-line global-require -var zip = function zip(zipper, readFile, tmpDir) { +var zip = function zip(zipper, readFile, dir) { (0, _fp.forEach)(function (file) { - return zipper.file(file, readFile(_path2.default.resolve(tmpDir, file))); - }, [artifact, artifact + '.map']); + return zipper.file(file, readFile(_path2.default.resolve(dir, file))); + }, _fs2.default.readdirSync(dir)); return zipper.generate({ type: 'nodebuffer', compression: 'DEFLATE', @@ -109,7 +109,7 @@ module.exports = function () { key: 'optimize', value: function () { var _ref2 = (0, _asyncToGenerator3.default)(_regenerator2.default.mark(function _callee2() { - var servicePath, serverlessTmpDirPath, handlerNames, entrypoints, webpackConfig, stats, data, zipFileName, artifactFilePath; + var servicePath, serverlessTmpDirPath, handlerNames, entrypoints, webpackConfig, outputDir, stats, data, zipFileName, artifactFilePath; return _regenerator2.default.wrap(function _callee2$(_context2) { while (1) { switch (_context2.prev = _context2.next) { @@ -134,21 +134,24 @@ module.exports = function () { webpackConfig.context = servicePath; webpackConfig.entry = (0, _fp.compact)((0, _fp.concat)(webpackConfig.entry, entrypoints)); + + outputDir = _path2.default.join(serverlessTmpDirPath, 'output'); + webpackConfig.output = { libraryTarget: 'commonjs', - path: serverlessTmpDirPath, + path: outputDir, filename: artifact }; - _context2.next = 12; + _context2.next = 13; return runWebpack(webpackConfig); - case 12: + case 13: stats = _context2.sent; this.serverless.cli.log(format(stats)); - data = zip(new _nodeZip2.default(), _fs2.default.readFileSync, serverlessTmpDirPath); + data = zip(new _nodeZip2.default(), _fs2.default.readFileSync, outputDir); zipFileName = this.serverless.service.service + '-' + new Date().getTime().toString() + '.zip'; artifactFilePath = _path2.default.resolve(serverlessTmpDirPath, zipFileName); @@ -156,7 +159,7 @@ module.exports = function () { this.serverless.utils.writeFileSync(artifactFilePath, data); this.serverless.service.package.artifact = artifactFilePath; - case 19: + case 20: case 'end': return _context2.stop(); } diff --git a/1.0/src/index.js b/1.0/src/index.js index 67b5feb..7ca64b6 100644 --- a/1.0/src/index.js +++ b/1.0/src/index.js @@ -37,10 +37,10 @@ const artifact = 'handler.js'; const getConfig = servicePath => require(path.resolve(servicePath, './webpack.config.js')); // eslint-disable-line global-require -const zip = (zipper, readFile, tmpDir) => { +const zip = (zipper, readFile, dir) => { forEach(file => - zipper.file(file, readFile(path.resolve(tmpDir, file)) - ), [artifact, `${artifact}.map`]); + zipper.file(file, readFile(path.resolve(dir, file)) + ), fs.readdirSync(dir)); return zipper.generate({ type: 'nodebuffer', compression: 'DEFLATE', @@ -72,16 +72,18 @@ module.exports = class ServerlessWebpack { const webpackConfig = getConfig(servicePath); webpackConfig.context = servicePath; webpackConfig.entry = compact(concat(webpackConfig.entry, entrypoints)); + + const outputDir = path.join(serverlessTmpDirPath, 'output'); webpackConfig.output = { libraryTarget: 'commonjs', - path: serverlessTmpDirPath, + path: outputDir, filename: artifact, }; const stats = await runWebpack(webpackConfig); this.serverless.cli.log(format(stats)); - const data = zip(new Zip(), fs.readFileSync, serverlessTmpDirPath); + const data = zip(new Zip(), fs.readFileSync, outputDir); const zipFileName = `${this.serverless.service.service}-${(new Date).getTime().toString()}.zip`;