UNPKG

3.77 kBJavaScriptView Raw
1const Parser = require('./Parser');
2const path = require('path');
3const {errorUtils} = require('@parcel/utils');
4
5/**
6 * A Pipeline composes multiple Asset types together.
7 */
8class Pipeline {
9 constructor(options) {
10 this.options = options;
11 this.parser = new Parser(options);
12 }
13
14 async process(path, isWarmUp) {
15 let options = this.options;
16 if (isWarmUp) {
17 options = Object.assign({isWarmUp}, options);
18 }
19
20 let asset = this.parser.getAsset(path, options);
21 let error = null;
22 let generatedMap = {};
23 try {
24 let generated = await this.processAsset(asset);
25 for (let rendition of generated) {
26 generatedMap[rendition.type] = rendition.value;
27 }
28 } catch (err) {
29 error = errorUtils.errorToJson(err);
30 error.fileName = path;
31 }
32
33 return {
34 id: asset.id,
35 dependencies: Array.from(asset.dependencies.values()),
36 generated: generatedMap,
37 sourceMaps: asset.sourceMaps,
38 error: error,
39 hash: asset.hash,
40 cacheData: asset.cacheData
41 };
42 }
43
44 async processAsset(asset) {
45 try {
46 await asset.process();
47 } catch (err) {
48 throw asset.generateErrorMessage(err);
49 }
50
51 let inputType = path.extname(asset.name).slice(1);
52 let generated = [];
53 for (let rendition of this.iterateRenditions(asset)) {
54 let {type, value} = rendition;
55 if (typeof value !== 'string' || rendition.final) {
56 generated.push(rendition);
57 continue;
58 }
59
60 // Find an asset type for the rendition type.
61 // If the asset is not already an instance of this asset type, process it.
62 let AssetType = this.parser.findParser(
63 asset.name.slice(0, -inputType.length) + type,
64 true
65 );
66 if (!(asset instanceof AssetType)) {
67 let opts = Object.assign({}, asset.options, {rendition});
68 let subAsset = new AssetType(asset.name, opts);
69 subAsset.id = asset.id;
70 subAsset.contents = value;
71 subAsset.dependencies = asset.dependencies;
72 subAsset.cacheData = Object.assign(asset.cacheData, subAsset.cacheData);
73
74 let processed = await this.processAsset(subAsset);
75 if (rendition.meta) {
76 for (let res of processed) {
77 res.meta = rendition.meta;
78 res.isMain = res.type === subAsset.type;
79 }
80 }
81
82 generated = generated.concat(processed);
83 } else {
84 generated.push(rendition);
85 }
86 }
87
88 // Post process. This allows assets a chance to modify the output produced by sub-asset types.
89 try {
90 generated = await asset.postProcess(generated);
91 } catch (err) {
92 throw asset.generateErrorMessage(err);
93 }
94
95 let hasMap = false;
96 let sourceMaps = {};
97 for (let rendition of generated) {
98 if (rendition.map && rendition.type == asset.type) {
99 sourceMaps[rendition.type] = rendition.map;
100 hasMap = true;
101 }
102 }
103
104 if (hasMap) {
105 asset.sourceMaps = sourceMaps;
106 }
107
108 asset.generated = generated;
109 asset.hash = await asset.generateHash();
110
111 return generated;
112 }
113
114 *iterateRenditions(asset) {
115 if (Array.isArray(asset.generated)) {
116 return yield* asset.generated;
117 }
118
119 if (typeof asset.generated === 'string') {
120 return yield {
121 type: asset.type,
122 value: asset.generated
123 };
124 }
125
126 // Backward compatibility support for the old API.
127 // Assume all renditions are final - don't compose asset types together.
128 for (let type in asset.generated) {
129 yield {
130 type,
131 value: asset.generated[type],
132 // for scope hoisting, we need to post process all JS
133 final: !(type === 'js' && this.options.scopeHoist)
134 };
135 }
136 }
137}
138
139module.exports = Pipeline;