-
Notifications
You must be signed in to change notification settings - Fork 137
/
one-shot.ts
78 lines (66 loc) · 2.48 KB
/
one-shot.ts
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
import Plugin from 'broccoli-plugin';
import { Node } from 'broccoli-node-api';
import { Builder } from 'broccoli';
import { copySync } from 'fs-extra';
import heimdall from 'heimdalljs';
class NerfHeimdallBuilder extends Builder {
/*
Replace the code used to track heimdall nodes: https://github.com/broccolijs/broccoli/blob/v3.5.2/lib/builder.ts#L463-L503
This reduces the amount of memory that these one-shot's create by:
- Avoiding creating Heimdall nodes for each broccoli plugin
- Disabling the "re-parenting" process done by Broccoli builder (which ends up creating **double** the heimdall nodes)
*/
setupHeimdall() {}
buildHeimdallTree() {}
}
let seen = new WeakMap<Node, Node>();
// Wraps a broccoli tree such that it (and everything it depends on) will only
// build a single time.
export default class OneShot extends Plugin {
private builder: NerfHeimdallBuilder | null;
static create(originalTree: Node, privateAddonName: string) {
let output = seen.get(originalTree);
if (!output) {
output = new this(originalTree, privateAddonName);
seen.set(originalTree, output);
}
return output;
}
private constructor(originalTree: Node, private addonName: string) {
// from broccoli's perspective, we don't depend on any input trees!
super([], {
annotation: `@embroider/compat: ${addonName}`,
persistentOutput: true,
needsCache: false,
});
// create a nested builder in order to isolate the specific addon
this.builder = new NerfHeimdallBuilder(originalTree);
}
async build() {
const { builder } = this;
// only build the first time
if (builder === null) {
return;
}
this.builder = null;
// Make a heimdall node so that we know for sure, all nodes created during our
// inner builder can be remove easily
const oneshotCookie = heimdall.start({
name: `@embroider/compat: OneShot (${this.addonName})`,
});
const oneshotHeimdallNode = heimdall.current;
try {
await builder.build();
copySync(builder.outputPath, this.outputPath, { dereference: true });
await builder.cleanup();
} finally {
oneshotCookie.stop();
/*
Remove any of the current node's direct children, this ensures that we do not bloat the
current Broccoli builder's heimdall node graph (e.g. the one that is calling
OneShotPlugin; **not** the one that the OneShotPlugin internally creates).
*/
oneshotHeimdallNode.remove();
}
}
}