feat(modules/pipeline): move pipeline into its own module plugin

This is the first step of refactoring Embark's pipeline abstraction into
dedicated plugin modules that take advantage of Embark's event system.

With this commit we're moving `Pipeline` into `lib/modules/pipeline` and
introduce a new command handler `pipeline:build`. Embark's engine now
requests builds via this command handler.

Notice that `Watch` still lives in `lib/pipeline` as this is a step-by-step
refactoring to reduce chances of introducing regressions.
This commit is contained in:
Pascal Precht 2018-10-03 16:02:29 +02:00
parent 6b4321874b
commit a0ef234fea
No known key found for this signature in database
GPG Key ID: 0EE28D8D6FD85D7D
8 changed files with 68 additions and 88 deletions

View File

@ -419,12 +419,12 @@ class EmbarkController {
ejectWebpack() {
var fs = require('../lib/core/fs.js');
var embarkConfig = fs.embarkPath('lib/pipeline/webpack.config.js');
var embarkConfig = fs.embarkPath('lib/modules/pipeline/webpack.config.js');
var dappConfig = fs.dappPath('webpack.config.js');
fs.copyPreserve(embarkConfig, dappConfig);
console.log(__('webpack config ejected to:').dim.yellow);
console.log(`${dappConfig}`.green);
var embarkOverrides = fs.embarkPath('lib/pipeline/babel-loader-overrides.js');
var embarkOverrides = fs.embarkPath('lib/modules/pipeline/babel-loader-overrides.js');
var dappOverrides = fs.dappPath('babel-loader-overrides.js');
fs.copyPreserve(embarkOverrides, dappOverrides);
console.log(__('webpack overrides ejected to:').dim.yellow);

View File

@ -7,6 +7,8 @@ const deepEqual = require('deep-equal');
const constants = require('../constants');
const {canonicalHost, defaultHost} = require('../utils/host');
const DEFAULT_CONFIG_PATH = 'config/';
var Config = function(options) {
const self = this;
this.env = options.env;

View File

@ -103,21 +103,12 @@ class Engine {
pipelineService(_options) {
const self = this;
this.events.emit("status", "Building Assets");
const Pipeline = require('../pipeline/pipeline.js');
const pipeline = new Pipeline({
env: this.env,
buildDir: this.config.buildDir,
contractsFiles: this.config.contractsFiles,
assetFiles: this.config.assetFiles,
events: this.events,
logger: this.logger,
plugins: this.plugins,
this.registerModule('pipeline', {
webpackConfigName: this.webpackConfigName
});
this.events.on('code-generator-ready', function () {
self.events.request('code', function (abi, contractsJSON) {
pipeline.build(abi, contractsJSON, null, () => {
self.events.request('pipeline:build', {abi, contractsJSON}, () => {
self.events.emit('outputDone');
});
});

View File

@ -1,64 +1,60 @@
const fs = require('../core/fs.js');
const fs = require('../../core/fs.js');
const async = require('async');
const ProcessLauncher = require('../core/processes/processLauncher');
const utils = require('../utils/utils.js');
const constants = require('../constants');
const utils = require('../../utils/utils.js');
const ProcessLauncher = require('../../core/processes/processLauncher');
const constants = require('../../constants');
class Pipeline {
constructor(options) {
this.env = options.env;
this.buildDir = options.buildDir;
this.contractsFiles = options.contractsFiles;
this.assetFiles = options.assetFiles;
this.events = options.events;
this.logger = options.logger;
this.plugins = options.plugins;
constructor(embark, options) {
this.env = embark.config.env;
this.buildDir = embark.config.buildDir;
this.contractsFiles = embark.config.contractsFiles;
this.assetFiles = embark.config.assetFiles;
this.events = embark.events;
this.logger = embark.config.logger;
this.plugins = embark.config.plugins;
this.webpackConfigName = options.webpackConfigName;
this.pipelinePlugins = this.plugins.getPluginsFor('pipeline');
this.isFirstBuild = true;
this.events.setCommandHandler('pipeline:build', (options, callback) => this.build(callback));
fs.removeSync(this.buildDir);
}
build(abi, contractsJSON, path, callback) {
build(callback) {
let self = this;
const importsList = {};
let placeholderPage;
if (!this.assetFiles || !Object.keys(this.assetFiles).length) {
if (!self.assetFiles || !Object.keys(self.assetFiles).length) {
return self.buildContracts(callback);
}
async.waterfall([
function createPlaceholderPage(next){
function createPlaceholderPage(next) {
if (self.isFirstBuild) {
self.isFirstBuild = false;
return next();
}
self.events.request('build-placeholder', next);
},
function buildTheContracts(next) {
self.buildContracts(next);
},
function buildWeb3(next) {
self.buildWeb3JS(next);
},
(next) => self.buildContracts(next),
(next) => self.buildWeb3JS(next),
function createImportList(next) {
importsList["Embark/EmbarkJS"] = fs.dappPath(".embark", 'embark.js');
importsList["Embark/web3"] = fs.dappPath(".embark", 'web3_instance.js');
importsList["Embark/contracts"] = fs.dappPath(".embark/contracts", '');
self.plugins.getPluginsProperty('imports', 'imports').forEach(function (importObject) {
self.plugins.getPluginsProperty('imports', 'imports').forEach(importObject => {
let [importName, importLocation] = importObject;
importsList[importName] = importLocation;
});
next();
},
function writeContracts(next) {
self.events.request('contracts:list', (_err, contracts) => {
// ensure the .embark/contracts directory exists (create if not exists)
fs.mkdirp(fs.dappPath(".embark/contracts", ''), (err) => {
fs.mkdirp(fs.dappPath(".embark/contracts", ''), err => {
if(err) return next(err);
// Create a file .embark/contracts/index.js that requires all contract files
@ -69,7 +65,7 @@ class Pipeline {
importsHelperFile.write('module.exports = {\n');
async.eachOf(contracts, (contract, idx, eachCb) => {
self.events.request('code-generator:contract', contract.className, (contractCode) => {
self.events.request('code-generator:contract', contract.className, contractCode => {
let filePath = fs.dappPath(".embark/contracts", contract.className + '.js');
importsList["Embark/contracts/" + contract.className] = filePath;
fs.writeFile(filePath, contractCode, eachCb);
@ -78,7 +74,7 @@ class Pipeline {
importsHelperFile.write(`"${contract.className}": require('./${contract.className}').default`);
if(idx < contracts.length - 1) importsHelperFile.write(',\n'); // add a comma if we have more contracts to add
});
}, function(){
}, () => {
importsHelperFile.write('\n}'); // close the module.exports = {}
importsHelperFile.close(next); // close the write stream
});
@ -87,8 +83,7 @@ class Pipeline {
},
function runWebpack(next) {
self.logger.info(__(`running webpack with '${self.webpackConfigName}' config...`));
const assets = Object.keys(self.assetFiles)
.filter(key => key.match(/\.js$/));
const assets = Object.keys(self.assetFiles).filter(key => key.match(/\.js$/));
if (!assets || !assets.length) {
return next();
}
@ -100,7 +95,7 @@ class Pipeline {
modulePath: utils.joinPath(__dirname, 'webpackProcess.js'),
logger: self.logger,
events: self.events,
exitCallback: function (code) {
exitCallback: code => {
if (!built) {
return next(`Webpack build exited with code ${code} before the process finished`);
}
@ -137,7 +132,7 @@ class Pipeline {
files,
function (file, fileCb) {
self.logger.trace("reading " + file.filename);
return file.content(function (fileContent) {
return file.content(fileContent => {
self.runPlugins(file, fileContent, fileCb);
});
},
@ -166,14 +161,14 @@ class Pipeline {
return;
}
let content = contentFiles.map(function (file) {
let content = contentFiles.map(file => {
if (file === undefined) {
return "";
}
return file.content;
}).join("\n");
if(new RegExp(/^index.html?/i).test(targetFile)){
if (new RegExp(/^index.html?/i).test(targetFile)) {
targetFile = targetFile.replace('index', 'index-temp');
placeholderPage = targetFile;
}
@ -197,49 +192,22 @@ class Pipeline {
], callback);
}
runPlugins(file, fileContent, fileCb) {
const self = this;
if (self.pipelinePlugins.length <= 0) {
return fileCb(null, {content: fileContent, filename: file.filename, path: file.path, basedir: file.basedir, modified: true});
}
async.eachSeries(
self.pipelinePlugins,
function(plugin, pluginCB) {
if (file.options && file.options.skipPipeline) {
return pluginCB();
}
fileContent = plugin.runPipeline({targetFile: file.filename, source: fileContent});
file.modified = true;
pluginCB();
},
function (err) {
if (err) {
self.logger.error(err.message);
}
return fileCb(null, {content: fileContent, filename: file.filename, path: file.path, basedir: file.basedir, modified: true});
}
);
}
buildContracts(cb) {
const self = this;
async.waterfall([
function makeDirectory(next) {
fs.mkdirp(fs.dappPath(self.buildDir, 'contracts'), (err, _result) => {
next(err);
});
fs.mkdirp(fs.dappPath(self.buildDir, 'contracts'), err => next(err));
},
function getContracts(next) {
self.events.request('contracts:list', (err, contracts) => {
next(err, contracts);
});
self.events.request('contracts:list', next);
},
function writeContractsJSON(contracts, next) {
async.each(contracts, (contract, eachCb) => {
fs.writeJson(fs.dappPath(self.buildDir, 'contracts', contract.className + ".json"), contract, {spaces: 2}, eachCb);
}, () => { next(); });
async.each(contracts,(contract, eachCb) => {
fs.writeJson(fs.dappPath(
self.buildDir,
'contracts', contract.className + '.json'
), contract, {spaces: 2}, eachCb);
}, () => next());
}
], cb);
}
@ -248,9 +216,7 @@ class Pipeline {
const self = this;
async.waterfall([
function makeDirectory(next) {
fs.mkdirp(fs.dappPath(".embark"), (err, _result) => {
next(err);
});
fs.mkdirp(fs.dappPath(".embark"), err => next(err));
},
function getWeb3Code(next) {
self.events.request('code-generator:web3js', next);
@ -260,6 +226,28 @@ class Pipeline {
}
], cb);
}
runPlugins(file, fileContent, fileCb) {
const self = this;
if (self.pipelinePlugins.length <= 0) {
return fileCb(null, {content: fileContent, filename: file.filename, path: file.path, basedir: file.basedir, modified: true});
}
async.eachSeries(self.pipelinePlugins, (plugin, pluginCB) => {
if (file.options && file.options.skipPipeline) {
return pluginCB();
}
fileContent = plugin.runPipeline({targetFile: file.filename, source: fileContent});
file.modified = true;
pluginCB();
}, err => {
if (err) {
self.logger.error(err.message);
}
return fileCb(null, {content: fileContent, filename: file.filename, path: file.path, basedir: file.basedir, modified: true});
});
}
}
module.exports = Pipeline;

View File

@ -1,6 +1,6 @@
const constants = require('../constants');
const fs = require('../core/fs');
const ProcessWrapper = require('../core/processes/processWrapper');
const constants = require('../../constants');
const fs = require('../../core/fs');
const ProcessWrapper = require('../../core/processes/processWrapper');
const webpack = require('webpack');
const writeFile = require('util').promisify(require('fs').writeFile);
const {errorMessage, recursiveMerge} = require('../utils/utils');
@ -58,7 +58,7 @@ class WebpackProcess extends ProcessWrapper {
}
const dappConfigPath = fs.dappPath('webpack.config.js');
const defaultConfigPath = fs.embarkPath('lib/pipeline', 'webpack.config.js');
const defaultConfigPath = fs.embarkPath('lib/modules/pipeline', 'webpack.config.js');
let config, configPath;
try {

View File

@ -1 +0,0 @@
{}