Skip to content

Commit bfad8de

Browse files
authored
Merge pull request serverless-heaven#336 from serverless-heaven/refactor-configuration
Refactor configuration
2 parents 5502b08 + d36f9a8 commit bfad8de

9 files changed

+461
-186
lines changed

README.md

+34-14
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ WebPack's [Tree-Shaking][link-webpack-tree] optimization.
2929
## Recent improvements and important changes
3030

3131
* Webpack 2 support has been dropped in favor of Webpack 4
32+
* Cleaned up configuration. You should now use a `custom.webpack` object to configure everything relevant for the plugin. The old configuration still works but will be removed in the next major release. For details see below.
3233
* This 5.0.0 prerelease is based on the current 4.4.0
3334

3435
For the complete release notes see the end of this document.
@@ -48,12 +49,27 @@ plugins:
4849
4950
## Configure
5051
51-
By default the plugin will look for a `webpack.config.js` in the service directory.
52-
Alternatively, you can specify a different file or configuration in `serverless.yml`:
52+
The configuration of the plugin is done by defining a `custom: webpack` object in your `serverless.yml` with your specific configuration. All settings are optional and will be set to reasonable defaults if missing.
53+
54+
See the sections below for detailed descriptions of the settings. The defaults are:
55+
56+
```yaml
57+
custom:
58+
webpack:
59+
webpackConfig: 'webpack.config.js' # Name of webpack configuration file
60+
webpackIncludeModules: false # Node modules configuration for packaging
61+
packager: 'npm' # Reserved for future use. Any other values will not work right now.
62+
packExternalModulesMaxBuffer: 200 * 1024 # Size of stdio buffers for spawned child processes
63+
```
64+
65+
### Webpack configuration file
66+
67+
By default the plugin will look for a `webpack.config.js` in the service directory. Alternatively, you can specify a different file or configuration in `serverless.yml`.
5368

5469
```yaml
5570
custom:
56-
webpack: ./folder/my-webpack.config.js
71+
webpack:
72+
webpackConfig: ./folder/my-webpack.config.js
5773
```
5874

5975
A base Webpack configuration might look like this:
@@ -209,7 +225,8 @@ module.exports = {
209225
```yaml
210226
# serverless.yml
211227
custom:
212-
webpackIncludeModules: true # enable auto-packing of external modules
228+
webpack:
229+
webpackIncludeModules: true # enable auto-packing of external modules
213230
```
214231

215232

@@ -223,8 +240,9 @@ use a different package file, set `packagePath` to your custom `package.json`:
223240
```yaml
224241
# serverless.yml
225242
custom:
226-
webpackIncludeModules:
227-
packagePath: '../package.json' # relative path to custom package.json file.
243+
webpack:
244+
webpackIncludeModules:
245+
packagePath: '../package.json' # relative path to custom package.json file.
228246
```
229247
> Note that only relative path is supported at the moment.
230248

@@ -246,10 +264,11 @@ your service's production dependencies in `package.json`.
246264
```yaml
247265
# serverless.yml
248266
custom:
249-
webpackIncludeModules:
250-
forceInclude:
251-
- module1
252-
- module2
267+
webpack:
268+
webpackIncludeModules:
269+
forceInclude:
270+
- module1
271+
- module2
253272
```
254273

255274
#### Forced exclusion
@@ -262,10 +281,11 @@ Just add them to the `forceExclude` array property and they will not be packaged
262281
```yaml
263282
# serverless.yml
264283
custom:
265-
webpackIncludeModules:
266-
forceExclude:
267-
- module1
268-
- module2
284+
webpack:
285+
webpackIncludeModules:
286+
forceExclude:
287+
- module1
288+
- module2
269289
```
270290

271291
If you specify a module in both arrays, `forceInclude` and `forceExclude`, the

lib/Configuration.js

+78
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
'use strict';
2+
/**
3+
* Plugin configuration.
4+
*/
5+
6+
const _ = require('lodash');
7+
8+
/**
9+
* Plugin defaults
10+
*/
11+
const DefaultConfig = {
12+
webpackConfig: 'webpack.config.js',
13+
webpackIncludeModules: false,
14+
packager: 'npm',
15+
packExternalModulesMaxBuffer: 200 * 1024,
16+
config: null
17+
};
18+
19+
class Configuration {
20+
21+
constructor(custom) {
22+
23+
this._config = {};
24+
this._hasLegacyConfig = false;
25+
26+
// Set configuration from sls.service.custom. We fall back to the
27+
// old configuration to keep backwards compatibility.
28+
if (custom) {
29+
if (custom.webpackIncludeModules) {
30+
this._config.webpackIncludeModules = custom.webpackIncludeModules;
31+
this._hasLegacyConfig = true;
32+
}
33+
if (custom.packExternalModulesMaxBuffer) {
34+
this._config.packExternalModulesMaxBuffer = custom.packExternalModulesMaxBuffer;
35+
this._hasLegacyConfig = true;
36+
}
37+
if (_.isString(custom.webpack)) {
38+
this._config.webpackConfig = custom.webpack;
39+
this._hasLegacyConfig = true;
40+
} else {
41+
_.assign(this._config, custom.webpack || {});
42+
}
43+
}
44+
45+
// Set defaults for all missing properties
46+
_.defaults(this._config, DefaultConfig);
47+
}
48+
49+
get webpackConfig() {
50+
return this._config.webpackConfig;
51+
}
52+
53+
get webpackIncludeModules() {
54+
return this._config.webpackIncludeModules;
55+
}
56+
57+
get packExternalModulesMaxBuffer() {
58+
return this._config.packExternalModulesMaxBuffer;
59+
}
60+
61+
get packager() {
62+
return this._config.packager;
63+
}
64+
65+
get config() {
66+
return this._config.config;
67+
}
68+
69+
get hasLegacyConfig() {
70+
return this._hasLegacyConfig;
71+
}
72+
73+
toJSON() {
74+
return _.omitBy(this._config, _.isNil);
75+
}
76+
}
77+
78+
module.exports = Configuration;

lib/Configuration.test.js

+116
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
'use strict';
2+
/**
3+
* Unit tests for Configuration.
4+
*/
5+
6+
const chai = require('chai');
7+
const Configuration = require('./Configuration');
8+
9+
const expect = chai.expect;
10+
11+
describe('Configuration', () => {
12+
describe('defaults', () => {
13+
let expectedDefaults;
14+
15+
before(() => {
16+
expectedDefaults = {
17+
webpackConfig: 'webpack.config.js',
18+
webpackIncludeModules: false,
19+
packager: 'npm',
20+
packExternalModulesMaxBuffer: 200 * 1024,
21+
config: null
22+
};
23+
});
24+
25+
it('should set default configuration without custom', () => {
26+
const config = new Configuration();
27+
expect(config).to.have.a.property('_config').that.deep.equals(expectedDefaults);
28+
expect(config).to.have.a.property('hasLegacyConfig').that.is.false;
29+
});
30+
31+
it('should set default configuration without webpack property', () => {
32+
const config = new Configuration({});
33+
expect(config).to.have.a.property('_config').that.deep.equals(expectedDefaults);
34+
expect(config).to.have.a.property('hasLegacyConfig').that.is.false;
35+
});
36+
});
37+
38+
describe('with legacy configuration', () => {
39+
it('should use custom.webpackIncludeModules', () => {
40+
const testCustom = { webpackIncludeModules: { forceInclude: ['mod1'] } };
41+
const config = new Configuration(testCustom);
42+
expect(config).to.have.a.property('webpackIncludeModules').that.deep.equals(testCustom.webpackIncludeModules);
43+
});
44+
45+
it('should use custom.packExternalModulesMaxBuffer', () => {
46+
const testCustom = { packExternalModulesMaxBuffer: 4711 };
47+
const config = new Configuration(testCustom);
48+
expect(config).to.have.a.property('packExternalModulesMaxBuffer').that.equals(4711);
49+
});
50+
51+
it('should use custom.webpack as string', () => {
52+
const testCustom = { webpack: 'myWebpackFile.js' };
53+
const config = new Configuration(testCustom);
54+
expect(config).to.have.a.property('webpackConfig').that.equals('myWebpackFile.js');
55+
});
56+
57+
it('should detect it', () => {
58+
const testCustom = { webpack: 'myWebpackFile.js' };
59+
const config = new Configuration(testCustom);
60+
expect(config).to.have.a.property('hasLegacyConfig').that.is.true;
61+
});
62+
63+
it('should add defaults', () => {
64+
const testCustom = {
65+
webpackIncludeModules: { forceInclude: ['mod1'] },
66+
webpack: 'myWebpackFile.js'
67+
};
68+
const config = new Configuration(testCustom);
69+
expect(config).to.have.a.property('webpackIncludeModules').that.deep.equals(testCustom.webpackIncludeModules);
70+
expect(config._config).to.deep.equal({
71+
webpackConfig: 'myWebpackFile.js',
72+
webpackIncludeModules: { forceInclude: ['mod1'] },
73+
packager: 'npm',
74+
packExternalModulesMaxBuffer: 200 * 1024,
75+
config: null
76+
});
77+
});
78+
});
79+
80+
describe('with a configuration object', () => {
81+
it('should use it and add any defaults', () => {
82+
const testCustom = {
83+
webpack: {
84+
webpackIncludeModules: { forceInclude: ['mod1'] },
85+
webpackConfig: 'myWebpackFile.js'
86+
}
87+
};
88+
const config = new Configuration(testCustom);
89+
expect(config._config).to.deep.equal({
90+
webpackConfig: 'myWebpackFile.js',
91+
webpackIncludeModules: { forceInclude: ['mod1'] },
92+
packager: 'npm',
93+
packExternalModulesMaxBuffer: 200 * 1024,
94+
config: null
95+
});
96+
});
97+
98+
it('should favor new configuration', () => {
99+
const testCustom = {
100+
webpackIncludeModules: { forceExclude: ['mod2'] },
101+
webpack: {
102+
webpackIncludeModules: { forceInclude: ['mod1'] },
103+
webpackConfig: 'myWebpackFile.js'
104+
}
105+
};
106+
const config = new Configuration(testCustom);
107+
expect(config._config).to.deep.equal({
108+
webpackConfig: 'myWebpackFile.js',
109+
webpackIncludeModules: { forceInclude: ['mod1'] },
110+
packager: 'npm',
111+
packExternalModulesMaxBuffer: 200 * 1024,
112+
config: null
113+
});
114+
});
115+
});
116+
});

lib/packExternalModules.js

+3-6
Original file line numberDiff line numberDiff line change
@@ -174,10 +174,7 @@ module.exports = {
174174

175175
const stats = this.compileStats;
176176

177-
const includes = (
178-
this.serverless.service.custom &&
179-
this.serverless.service.custom.webpackIncludeModules
180-
);
177+
const includes = this.configuration.webpackIncludeModules;
181178

182179
if (!includes) {
183180
return BbPromise.resolve();
@@ -190,11 +187,11 @@ module.exports = {
190187
const packageJsonPath = path.join(process.cwd(), packagePath);
191188

192189
// Determine and create packager
193-
return BbPromise.try(() => Packagers.get.call(this, 'npm'))
190+
return BbPromise.try(() => Packagers.get.call(this, this.configuration.packager))
194191
.then(packager => {
195192
// Get first level dependency graph
196193
this.options.verbose && this.serverless.cli.log(`Fetch dependency graph from ${packageJsonPath}`);
197-
const maxExecBufferSize = this.serverless.service.custom.packExternalModulesMaxBuffer || 200 * 1024;
194+
const maxExecBufferSize = this.configuration.packExternalModulesMaxBuffer;
198195

199196
return packager.getProdDependencies(path.dirname(packageJsonPath), 1, maxExecBufferSize)
200197
.then(dependencyGraph => {

lib/validate.js

+9-5
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ const fse = require('fs-extra');
66
const glob = require('glob');
77
const lib = require('./index');
88
const _ = require('lodash');
9+
const Configuration = require('./Configuration');
910

1011
/**
1112
* For automatic entry detection we sort the found files to solve ambiguities.
@@ -74,11 +75,14 @@ module.exports = {
7475
};
7576
};
7677

77-
this.webpackConfig = (
78-
this.serverless.service.custom &&
79-
this.serverless.service.custom.webpack ||
80-
'webpack.config.js'
81-
);
78+
// Initialize plugin configuration
79+
this.configuration = new Configuration(this.serverless.service.custom);
80+
this.options.verbose && this.serverless.cli.log(`Using configuration:\n${JSON.stringify(this.configuration, null, 2)}`);
81+
if (this.configuration.hasLegacyConfig) {
82+
this.serverless.cli.log('Legacy configuration detected. Consider to use "custom.webpack" as object (see README).');
83+
}
84+
85+
this.webpackConfig = this.configuration.config || this.configuration.webpackConfig;
8286

8387
// Expose entries - must be done before requiring the webpack configuration
8488
const entries = {};

0 commit comments

Comments
 (0)