/
Pipeline.js
139 lines (121 loc) Β· 3.69 KB
/
Pipeline.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
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;