Browse Source

Merge branch 'master' of https://github.com/cyyuen/serverless-webpack into cyyuen-master

master
Nicola Peduzzi 8 years ago
parent
commit
25f443caa5
  1. 38
      README.md
  2. 7
      examples/include-external-npm-packages/package.json
  3. 3
      examples/include-external-npm-packages/serverless.yml
  4. 4
      examples/include-external-npm-packages/webpack.config.js
  5. 7
      index.js
  6. 1
      lib/compile.js
  7. 91
      lib/packExternalModules.js

38
README.md

@ -67,26 +67,46 @@ module.exports = {
By default, the plugin will try to bundle all dependencies. However, you don't 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 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, builtin package (ie: `aws-sdk`) and handling webpack-incompatible modules.
you add all the modules, you want to exclude from bundled files, into `externals` field
of your `webpack.config.js` and add those, you want to include in final distribution,
into `serverless.yml`:
```javascript In this case you might add external modules in
[Webpack `externals` configuration](https://webpack.github.io/docs/configuration.html#externals).
Those modules can be included in the Serverless bundle with the `webpackIncludeModules`
option in `serverless.yml`:
```js
// webpack.config.js // webpack.config.js
{ var nodeExternals = require('webpack-node-externals')
externals: ["module1", "module2"] // modules to be excluded from bundled file
modules.export = {
// we use webpack-node-externals to excludes all node deps.
// You can manually set the externals too.
externals: [nodeExternals()],
} }
``` ```
```yaml
# serverless.yml
custom:
webpackIncludeModules: true # enable auto-packing of external modules
```
All modules stated in `externals` will be excluded from bundled files. If an excluded module
is stated as `dependencies` in `package.json`, it will be packed into the Serverless
artifact under the `node_modules` directory.
By default, the plugin will use the `package.json` file in working directory, If you want to
use a different package conf, set `packagePath` to your custom package.json. eg:
```yaml ```yaml
# serverless.yml # serverless.yml
custom: custom:
webpackIncludeModules: webpackIncludeModules:
- module1 # modules to be included in distribution packagePath: '../package.json' # relative path to custom package.json file.
``` ```
> Note that only relative path is supported at the moment.
You can find an example setup in the [`examples`](./examples) folder. You can find an example setups in the [`examples`](./examples) folder.
## Usage ## Usage

7
examples/include-external-npm-packages/package.json

@ -10,10 +10,11 @@
"license": "MIT", "license": "MIT",
"devDependencies": { "devDependencies": {
"serverless-webpack": "^1.0.0-beta.2", "serverless-webpack": "^1.0.0-beta.2",
"webpack": "^1.13.1" "webpack": "^1.13.1",
"webpack-node-externals": "^1.3.3",
"aws-sdk": "^2.5.3" // packages in devDependencies won't be included in distribution
}, },
"dependencies": { "dependencies": { // packages in dependencies will be included in distribution if required
"aws-sdk": "^2.5.3",
"fbgraph": "^1.3.0" "fbgraph": "^1.3.0"
} }
} }

3
examples/include-external-npm-packages/serverless.yml

@ -9,8 +9,7 @@ provider:
runtime: nodejs4.3 runtime: nodejs4.3
custom: custom:
webpackIncludeModules: # modules to be included in distribution webpackIncludeModules: true # enable auto including modules
- fbgraph
functions: functions:
first: first:

4
examples/include-external-npm-packages/webpack.config.js

@ -1,7 +1,7 @@
var path = require('path'); var nodeExternals = require('webpack-node-externals');
module.exports = { module.exports = {
entry: './handler.js', entry: './handler.js',
target: 'node', target: 'node',
externals: ["fbgraph", "aws-sdk"] // modules to be excluded from bundled file externals: [nodeExternals()] // exclude external modules
}; };

7
index.js

@ -7,7 +7,7 @@ const compile = require('./lib/compile');
const cleanup = require('./lib/cleanup'); const cleanup = require('./lib/cleanup');
const run = require('./lib/run'); const run = require('./lib/run');
const serve = require('./lib/serve'); const serve = require('./lib/serve');
const packExternalModules = require('./lib/packExternalModules') const packExternalModules = require('./lib/packExternalModules');
class ServerlessWebpack { class ServerlessWebpack {
constructor(serverless, options) { constructor(serverless, options) {
@ -30,7 +30,6 @@ class ServerlessWebpack {
lifecycleEvents: [ lifecycleEvents: [
'validate', 'validate',
'compile', 'compile',
'packExternalModules',
], ],
options: { options: {
out: { out: {
@ -102,9 +101,7 @@ class ServerlessWebpack {
.then(this.validate), .then(this.validate),
'webpack:compile': () => BbPromise.bind(this) 'webpack:compile': () => BbPromise.bind(this)
.then(this.compile), .then(this.compile)
'webpack:packExternalModules': () => BbPromise.bind(this)
.then(this.packExternalModules), .then(this.packExternalModules),
'webpack:invoke:invoke': () => BbPromise.bind(this) 'webpack:invoke:invoke': () => BbPromise.bind(this)

1
lib/compile.js

@ -12,6 +12,7 @@ module.exports = {
return BbPromise return BbPromise
.fromCallback(cb => compiler.run(cb)) .fromCallback(cb => compiler.run(cb))
.then(stats => { .then(stats => {
this.serverless.cli.consoleLog(stats.toString({ this.serverless.cli.consoleLog(stats.toString({
colors: true, colors: true,
hash: false, hash: false,

91
lib/packExternalModules.js

@ -5,8 +5,69 @@ const fs = require('fs');
const path = require('path'); const path = require('path');
const npm = require('npm-programmatic'); const npm = require('npm-programmatic');
function getProdModules(externalModules, packagePath) {
const packageJson = require(path.join(process.cwd(), packagePath));
const prodModules = [];
// only process the module stated in dependencies section
if (!packageJson.dependencies) {
return []
}
externalModules.forEach(module => {
const moduleVersion = packageJson.dependencies[module];
if (moduleVersion) {
prodModules.push(`${module}@${moduleVersion}`);
}
});
return prodModules;
}
function getExternalModuleName(module) {
const path = /^external "(.*)"$/.exec(module.identifier())[1];
const pathComponents = path.split('/');
const main = pathComponents[0];
// this is a package within a namespace
if (main.charAt(0) == '@') {
return `${main}/${pathComponents[1]}`
}
return main
}
function isExternalModule(module) {
return module.identifier().indexOf('external ') === 0;
}
function getExternalModules(stats) {
const externals = new Set();
stats.compilation.chunks.forEach(function(chunk) {
// Explore each module within the chunk (built inputs):
chunk.modules.forEach(function(module) {
// Explore each source file path that was included into the module:
if (isExternalModule(module)) {
externals.add(getExternalModuleName(module));
}
});
});
return Array.from(externals);
}
module.exports = { module.exports = {
packExternalModules() { packExternalModules(stats) {
const includes = ( const includes = (
this.serverless.service.custom && this.serverless.service.custom &&
@ -14,11 +75,23 @@ module.exports = {
); );
return BbPromise.resolve().then(() => { return BbPromise.resolve().then(() => {
if (!includes || includes.length === 0) {
if (!includes) {
return; return;
} }
this.serverless.cli.log('Packing external modules: ' + includes.join(",")); const packagePath = includes.packagePath || './package.json';
const externalModules = getExternalModules(stats);
// this plugin will only install modules stated in dependencies section of package.json
const prodModules = getProdModules(externalModules, packagePath);
if (prodModules.length === 0) {
return;
}
this.serverless.cli.log('Packing external modules: ' + prodModules.join(", "));
const tmpPackageJson = path.join(this.serverless.config.servicePath, 'package.json'); const tmpPackageJson = path.join(this.serverless.config.servicePath, 'package.json');
@ -26,17 +99,17 @@ module.exports = {
fs.writeFileSync(tmpPackageJson, "{}"); fs.writeFileSync(tmpPackageJson, "{}");
return new BbPromise((resolve, reject) => { return new BbPromise((resolve, reject) => {
npm.install(includes, { npm.install(prodModules, {
cwd: this.serverless.config.servicePath, cwd: this.serverless.config.servicePath,
save: false save: true
}).then(() => { }).then(() => {
fs.unlink(tmpPackageJson); // fs.unlink(tmpPackageJson);
resolve() resolve()
}).catch(e => { }).catch(e => {
fs.unlink(tmpPackageJson); // fs.unlink(tmpPackageJson);
reject(e); reject(e);
}) })
}) })
}) });
}, }
}; };

Loading…
Cancel
Save