Skip to content

Commit

Permalink
Added support for async webpack config object
Browse files Browse the repository at this point in the history
Webpack 2+ support async configuration object by exporting a promise as configuration object.
This PR added support for async configuration object.
Closes serverless-heaven#412
  • Loading branch information
nidin authored Jun 20, 2018
1 parent d542eb6 commit 32fbab4
Showing 1 changed file with 91 additions and 82 deletions.
173 changes: 91 additions & 82 deletions lib/validate.js
Original file line number Diff line number Diff line change
Expand Up @@ -118,103 +118,112 @@ module.exports = {
}
}

// Default context
if (!this.webpackConfig.context) {
this.webpackConfig.context = this.serverless.config.servicePath;
}

// Default target
if (!this.webpackConfig.target) {
this.webpackConfig.target = 'node';
}

// Default output
if (!this.webpackConfig.output || _.isEmpty(this.webpackConfig.output)) {
const outputPath = path.join(this.serverless.config.servicePath, '.webpack');
this.webpackConfig.output = {
libraryTarget: 'commonjs',
path: outputPath,
filename: '[name].js',
};
}
const processConfig = _config => {
this.webpackConfig = _config;
// Default context
if (!this.webpackConfig.context) {
this.webpackConfig.context = this.serverless.config.servicePath;
}

// Custom output path
if (this.options.out) {
this.webpackConfig.output.path = path.join(this.serverless.config.servicePath, this.options.out);
}
// Default target
if (!this.webpackConfig.target) {
this.webpackConfig.target = 'node';
}

if (this.skipCompile) {
this.serverless.cli.log('Skipping build and using existing compiled output');
if (!fse.pathExistsSync(this.webpackConfig.output.path)) {
return BbPromise.reject(new this.serverless.classes
.Error('No compiled output found'));
// Default output
if (!this.webpackConfig.output || _.isEmpty(this.webpackConfig.output)) {
const outputPath = path.join(this.serverless.config.servicePath, '.webpack');
this.webpackConfig.output = {
libraryTarget: 'commonjs',
path: outputPath,
filename: '[name].js',
};
}
this.keepOutputDirectory = true;
}

if (!this.keepOutputDirectory) {
this.options.verbose && this.serverless.cli.log(`Removing ${this.webpackConfig.output.path}`);
fse.removeSync(this.webpackConfig.output.path);
}
this.webpackOutputPath = this.webpackConfig.output.path;
// Custom output path
if (this.options.out) {
this.webpackConfig.output.path = path.join(this.serverless.config.servicePath, this.options.out);
}

// 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;
if (this.skipCompile) {
this.serverless.cli.log('Skipping build and using existing compiled output');
if (!fse.pathExistsSync(this.webpackConfig.output.path)) {
return BbPromise.reject(new this.serverless.classes
.Error('No compiled output found'));
}
this.keepOutputDirectory = true;
}

if (this.webpackConfig.entry && !_.isEqual(this.webpackConfig.entry, entries)) {
return BbPromise.reject(new this.serverless.classes
.Error('Webpack entry must be automatically resolved when package.individually is set to true. ' +
'In webpack.config.js, remove the entry declaration or set entry to slsw.lib.entries.'));
if (!this.keepOutputDirectory) {
this.options.verbose && this.serverless.cli.log(`Removing ${this.webpackConfig.output.path}`);
fse.removeSync(this.webpackConfig.output.path);
}
this.webpackOutputPath = this.webpackConfig.output.path;

// Lookup associated Serverless functions
const allEntryFunctions = _.map(
this.serverless.service.getAllFunctions(),
funcName => {
const func = this.serverless.service.getFunction(funcName);
const handler = func.handler;
const handlerFile = path.relative('.', getHandlerFile(handler));
return {
handlerFile,
funcName,
func
};
// 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;

if (this.webpackConfig.entry && !_.isEqual(this.webpackConfig.entry, entries)) {
return BbPromise.reject(new this.serverless.classes
.Error('Webpack entry must be automatically resolved when package.individually is set to true. ' +
'In webpack.config.js, remove the entry declaration or set entry to slsw.lib.entries.'));
}
);

this.entryFunctions = _.flatMap(entries, (value, key) => {
const entry = path.relative('.', value);
const entryFile = _.replace(entry, new RegExp(`${path.extname(entry)}$`), '');
// Lookup associated Serverless functions
const allEntryFunctions = _.map(
this.serverless.service.getAllFunctions(),
funcName => {
const func = this.serverless.service.getFunction(funcName);
const handler = func.handler;
const handlerFile = path.relative('.', getHandlerFile(handler));
return {
handlerFile,
funcName,
func
};
}
);

this.entryFunctions = _.flatMap(entries, (value, key) => {
const entry = path.relative('.', value);
const entryFile = _.replace(entry, new RegExp(`${path.extname(entry)}$`), '');

const entryFuncs = _.filter(allEntryFunctions, [ 'handlerFile', entryFile ]);
if (_.isEmpty(entryFuncs)) {
// We have to make sure that for each entry there is an entry function item.
entryFuncs.push({});
}
_.forEach(entryFuncs, entryFunc => {
entryFunc.entry = {
key,
value
};
});
return entryFuncs;
});

const entryFuncs = _.filter(allEntryFunctions, [ 'handlerFile', entryFile ]);
if (_.isEmpty(entryFuncs)) {
// We have to make sure that for each entry there is an entry function item.
entryFuncs.push({});
}
_.forEach(entryFuncs, entryFunc => {
entryFunc.entry = {
key,
value
this.webpackConfig = _.map(this.entryFunctions, entryFunc => {
const config = _.cloneDeep(this.webpackConfig);
config.entry = {
[entryFunc.entry.key]: entryFunc.entry.value
};
const compileName = entryFunc.funcName || _.camelCase(entryFunc.entry.key);
config.output.path = path.join(config.output.path, compileName);
return config;
});
return entryFuncs;
});
} else {
this.webpackConfig.output.path = path.join(this.webpackConfig.output.path, 'service');
}

this.webpackConfig = _.map(this.entryFunctions, entryFunc => {
const config = _.cloneDeep(this.webpackConfig);
config.entry = {
[entryFunc.entry.key]: entryFunc.entry.value
};
const compileName = entryFunc.funcName || _.camelCase(entryFunc.entry.key);
config.output.path = path.join(config.output.path, compileName);
return config;
});
} else {
this.webpackConfig.output.path = path.join(this.webpackConfig.output.path, 'service');
return BbPromise.resolve();
}

return BbPromise.resolve();
if (this.webpackConfig instanceof Promise) {
this.webpackConfig.then(config => processConfig(config));
} else {
processConfig(this.webpackConfig);
}
},
};

0 comments on commit 32fbab4

Please sign in to comment.