Skip to content

Commit

Permalink
Serialized compile to address #299
Browse files Browse the repository at this point in the history
  • Loading branch information
asprouse committed Jun 14, 2019
1 parent eaee022 commit 99f6401
Show file tree
Hide file tree
Showing 6 changed files with 110 additions and 54 deletions.
9 changes: 7 additions & 2 deletions lib/Configuration.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ const DefaultConfig = {
packager: 'npm',
packagerOptions: {},
keepOutputDirectory: false,
config: null
config: null,
serializedCompile: false
};

class Configuration {
Expand Down Expand Up @@ -75,9 +76,13 @@ class Configuration {
return this._config.keepOutputDirectory;
}

get serializedCompile() {
return this._config.serializedCompile;
}

toJSON() {
return _.omitBy(this._config, _.isNil);
}
}

module.exports = Configuration;
module.exports = Configuration;
14 changes: 9 additions & 5 deletions lib/Configuration.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ describe('Configuration', () => {
packager: 'npm',
packagerOptions: {},
keepOutputDirectory: false,
config: null
config: null,
serializedCompile: false
};
});

Expand Down Expand Up @@ -56,7 +57,7 @@ describe('Configuration', () => {
});

it('should add defaults', () => {
const testCustom = {
const testCustom = {
webpackIncludeModules: { forceInclude: ['mod1'] },
webpack: 'myWebpackFile.js'
};
Expand All @@ -68,7 +69,8 @@ describe('Configuration', () => {
packager: 'npm',
packagerOptions: {},
keepOutputDirectory: false,
config: null
config: null,
serializedCompile: false
});
});
});
Expand All @@ -88,7 +90,8 @@ describe('Configuration', () => {
packager: 'npm',
packagerOptions: {},
keepOutputDirectory: false,
config: null
config: null,
serializedCompile: false
});
});

Expand All @@ -107,7 +110,8 @@ describe('Configuration', () => {
packager: 'npm',
packagerOptions: {},
keepOutputDirectory: false,
config: null
config: null,
serializedCompile: false
});
});
});
Expand Down
77 changes: 44 additions & 33 deletions lib/compile.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,46 +5,57 @@ const BbPromise = require('bluebird');
const webpack = require('webpack');
const tty = require('tty');

module.exports = {
compile() {
this.serverless.cli.log('Bundling with Webpack...');

const compiler = webpack(this.webpackConfig);

return BbPromise
.fromCallback(cb => compiler.run(cb))
.then(stats => {
const defaultStatsConfig = {
colors: tty.isatty(process.stdout.fd),
hash: false,
version: false,
chunks: false,
children: false
};

if (!this.multiCompile) {
stats = { stats: [stats] };
function ensureArray(obj) {
return _.isArray(obj) ? obj : [obj];
}

function getStatsLogger(statsConfig, consoleLog) {
return stats => consoleLog(stats.toString(statsConfig || defaultStatsConfig));
}

function webpackCompile(config, logStats) {
return BbPromise
.fromCallback(cb => webpack(config).run(cb))
.then(stats => {
// ensure stats in any array in the case of multiCompile
stats = stats.stats ? stats.stats : [stats];

_.forEach(stats, compileStats => {
logStats(compileStats);
if (compileStats.hasErrors()) {
throw new Error('Webpack compilation error, see stats above');
}
});

const compileOutputPaths = [];
const consoleStats = this.webpackConfig.stats || _.get(this, 'webpackConfig[0].stats') || {
colors: tty.isatty(process.stdout.fd),
hash: false,
version: false,
chunks: false,
children: false
};

_.forEach(stats.stats, compileStats => {
const statsOutput = compileStats.toString(consoleStats);
if (statsOutput) {
this.serverless.cli.consoleLog(statsOutput);
}
return stats;
});
}

if (compileStats.compilation.errors.length) {
throw new Error('Webpack compilation error, see above');
}
function webpackCompileSerial(configs, logStats) {
return BbPromise
.mapSeries(configs, config => webpackCompile(config, logStats))
.then(stats => _.flatten(stats));
}

compileOutputPaths.push(compileStats.compilation.compiler.outputPath);
});
module.exports = {
compile() {
this.serverless.cli.log('Bundling with Webpack...');

this.compileOutputPaths = compileOutputPaths;
this.compileStats = stats;
const configs = ensureArray(this.webpackConfig);
const logStats = getStatsLogger(configs[0].stats, this.serverless.cli.consoleLog);

return (this.serializedCompile ? webpackCompileSerial : webpackCompile)(configs, logStats)
.then(stats => {
this.compileStats = { stats };
return BbPromise.resolve();
});
},
}
};
3 changes: 2 additions & 1 deletion lib/validate.js
Original file line number Diff line number Diff line change
Expand Up @@ -164,8 +164,9 @@ module.exports = {

// In case of individual packaging we have to create a separate config for each function
if (_.has(this.serverless, 'service.package') && this.serverless.service.package.individually) {
this.options.verbose && this.serverless.cli.log('Using multi-compile (individual packaging)');
this.multiCompile = true;
this.serializedCompile = this.configuration.serializedCompile;
this.options.verbose && this.serverless.cli.log(`Using ${this.serializedCompile ? 'serialized' : 'multi'}-compile (individual packaging)`);

if (this.webpackConfig.entry && !_.isEqual(this.webpackConfig.entry, entries)) {
return BbPromise.reject(new this.serverless.classes
Expand Down
58 changes: 45 additions & 13 deletions tests/compile.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ describe('compile', () => {
module.webpackConfig = testWebpackConfig;
return expect(module.compile()).to.be.fulfilled
.then(() => {
expect(webpackMock).to.have.been.calledWith(testWebpackConfig);
expect(webpackMock).to.have.been.calledWith([testWebpackConfig]);
expect(webpackMock.compilerMock.run).to.have.been.calledOnce;
return null;
});
Expand All @@ -78,16 +78,19 @@ describe('compile', () => {
});

it('should work with multi compile', () => {
const testWebpackConfig = 'testconfig';
const multiStats = [{
compilation: {
errors: [],
compiler: {
outputPath: 'statsMock-outputPath',
const testWebpackConfig = ['testconfig'];
const multiStats = {
stats: [{
compilation: {
errors: [],
compiler: {
outputPath: 'statsMock-outputPath',
},
},
},
toString: sandbox.stub().returns('testStats'),
}];
toString: sandbox.stub().returns('testStats'),
hasErrors: _.constant(false)
}]
};
module.webpackConfig = testWebpackConfig;
module.multiCompile = true;
webpackMock.compilerMock.run.reset();
Expand All @@ -100,6 +103,33 @@ describe('compile', () => {
});
});

it('should work with serialized compile', () => {
const testWebpackConfig = ['testconfig'];
const multiStats = {
stats: [{
compilation: {
errors: [],
compiler: {
outputPath: 'statsMock-outputPath',
},
},
toString: sandbox.stub().returns('testStats'),
hasErrors: _.constant(false)
}]
};
module.webpackConfig = testWebpackConfig;
module.multiCompile = true;
module.serializedCompile = true;
webpackMock.compilerMock.run.reset();
webpackMock.compilerMock.run.yields(null, multiStats);
return expect(module.compile()).to.be.fulfilled
.then(() => {
expect(webpackMock).to.have.been.calledWith(testWebpackConfig);
expect(webpackMock.compilerMock.run).to.have.been.calledOnce;
return null;
});
});

it('should use correct stats option', () => {
const testWebpackConfig = {
stats: 'minimal'
Expand All @@ -111,22 +141,24 @@ describe('compile', () => {
outputPath: 'statsMock-outputPath'
}
},
toString: sandbox.stub().returns('testStats')
toString: sandbox.stub().returns('testStats'),
hasErrors: _.constant(false)
};

module.webpackConfig = testWebpackConfig;
webpackMock.compilerMock.run.reset();
webpackMock.compilerMock.run.yields(null, mockStats);
return (expect(module.compile()).to.be.fulfilled)
.then(() => {
expect(webpackMock).to.have.been.calledWith(testWebpackConfig);
expect(webpackMock).to.have.been.calledWith([testWebpackConfig]);
expect(mockStats.toString.firstCall.args).to.eql([testWebpackConfig.stats]);
module.webpackConfig = [testWebpackConfig];
return (expect(module.compile()).to.be.fulfilled);
})
.then(() => {
expect(webpackMock).to.have.been.calledWith([testWebpackConfig]);
expect(mockStats.toString.args).to.eql([[testWebpackConfig.stats], [testWebpackConfig.stats]]);
expect(mockStats.toString.args).to.eql([ [testWebpackConfig.stats], [testWebpackConfig.stats] ]);
return null;
});
});
});
3 changes: 3 additions & 0 deletions tests/webpack.mock.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ const StatsMock = () => ({
},
},
toString: sinon.stub().returns('testStats'),
hasErrors() {
return Boolean(this.compilation.errors.length);
},
});


Expand Down

0 comments on commit 99f6401

Please sign in to comment.