react-saasify-chrisvxd
Version:
React components for Saasify web clients.
140 lines (121 loc) • 3.77 kB
JavaScript
const Parser = require('./Parser');
const path = require('path');
const {errorUtils} = require('@parcel/utils');
/**
* A Pipeline composes multiple Asset types together.
*/
class Pipeline {
constructor(options) {
this.options = options;
this.parser = new Parser(options);
}
async process(path, isWarmUp) {
let options = this.options;
if (isWarmUp) {
options = Object.assign({isWarmUp}, options);
}
let asset = this.parser.getAsset(path, options);
let error = null;
let generatedMap = {};
try {
let generated = await this.processAsset(asset);
for (let rendition of generated) {
generatedMap[rendition.type] = rendition.value;
}
} catch (err) {
error = errorUtils.errorToJson(err);
error.fileName = path;
}
return {
id: asset.id,
dependencies: Array.from(asset.dependencies.values()),
generated: generatedMap,
sourceMaps: asset.sourceMaps,
error: error,
hash: asset.hash,
cacheData: asset.cacheData
};
}
async processAsset(asset) {
try {
await asset.process();
} catch (err) {
throw asset.generateErrorMessage(err);
}
let inputType = path.extname(asset.name).slice(1);
let generated = [];
for (let rendition of this.iterateRenditions(asset)) {
let {type, value} = rendition;
if (typeof value !== 'string' || rendition.final) {
generated.push(rendition);
continue;
}
// Find an asset type for the rendition type.
// If the asset is not already an instance of this asset type, process it.
let AssetType = this.parser.findParser(
asset.name.slice(0, -inputType.length) + type,
true
);
if (!(asset instanceof AssetType)) {
let opts = Object.assign({}, asset.options, {rendition});
let subAsset = new AssetType(asset.name, opts);
subAsset.id = asset.id;
subAsset.contents = value;
subAsset.dependencies = asset.dependencies;
subAsset.cacheData = Object.assign(asset.cacheData, subAsset.cacheData);
let processed = await this.processAsset(subAsset);
if (rendition.meta) {
for (let res of processed) {
res.meta = rendition.meta;
res.isMain = res.type === subAsset.type;
}
}
generated = generated.concat(processed);
} else {
generated.push(rendition);
}
}
// Post process. This allows assets a chance to modify the output produced by sub-asset types.
try {
generated = await asset.postProcess(generated);
} catch (err) {
throw asset.generateErrorMessage(err);
}
let hasMap = false;
let sourceMaps = {};
for (let rendition of generated) {
if (rendition.map && rendition.type == asset.type) {
sourceMaps[rendition.type] = rendition.map;
hasMap = true;
}
}
if (hasMap) {
asset.sourceMaps = sourceMaps;
}
asset.generated = generated;
asset.hash = await asset.generateHash();
return generated;
}
*iterateRenditions(asset) {
if (Array.isArray(asset.generated)) {
return yield* asset.generated;
}
if (typeof asset.generated === 'string') {
return yield {
type: asset.type,
value: asset.generated
};
}
// Backward compatibility support for the old API.
// Assume all renditions are final - don't compose asset types together.
for (let type in asset.generated) {
yield {
type,
value: asset.generated[type],
// for scope hoisting, we need to post process all JS
final: !(type === 'js' && this.options.scopeHoist)
};
}
}
}
module.exports = Pipeline;