-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathfastbuild.js
135 lines (108 loc) · 3.39 KB
/
fastbuild.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
/* eslint-disable @typescript-eslint/no-var-requires */
const { readFileSync, writeFileSync } = require('fs')
const path = require('path')
const Project = require('@lerna/project')
const QueryGraph = require('@lerna/query-graph')
const globIgnore = require('glob-gitignore')
const ignore = require('ignore')
const execa = require('execa')
const commonPrefix = require('common-prefix')
const { glob } = globIgnore
const CWD = process.cwd()
const TSCONFIG_FILENAME = 'tsconfig.json'
const IGNORE_FILENAME = '.buildignore'
const OUT_DIR = './lib'
const PACKAGE_GLOB = 'src/**/*.{ts,tsx}'
const tsconfig = () =>
JSON.parse(readFileSync(path.join(CWD, TSCONFIG_FILENAME)))
const buildIgnore = () => {
let rules = ''
try {
rules = readFileSync(path.join(CWD, IGNORE_FILENAME)).toString()
} catch (e) {
if (e.code !== 'ENOENT') {
throw e
}
}
return ignore().add(rules)
}
const splitIterations = async graph => {
let readyPackages = await graph.getAvailablePackages()
const iterations = []
while (readyPackages.length > 0) {
iterations.push(readyPackages)
// Mark these packages as complete on the graph
readyPackages.forEach(package => graph.markAsDone(package))
readyPackages = await graph.getAvailablePackages()
}
return iterations
}
const calcIncludes = location =>
glob([path.relative(CWD, path.join(location, PACKAGE_GLOB))], {
cwd: CWD,
ignore: buildIgnore()
})
const cleanPackages = locations =>
Promise.all([
...locations.map(location =>
execa.command(`rm -rf ${path.join(location, OUT_DIR)}`, {
stdio: 'inherit'
})
),
execa.command(`rm -rf ${path.join(CWD, OUT_DIR)}`, { stdio: 'inherit' })
])
const copyBuiltFiles = async location => {
const includes = await calcIncludes(location)
if (includes.length === 0) {
return
}
const paths = includes.map(include => path.parse(include).dir)
const fromRelative = commonPrefix(paths)
const from = path.join(CWD, OUT_DIR, fromRelative)
const to = path.join(location, OUT_DIR)
return execa.command(`cp -r ${from} ${to}`, { stdio: 'inherit' })
}
const buildIteration = async (iteration, n) => {
const locations = iteration.map(package => package.location)
console.log(`Build iteration ${n}: ${locations.length} packages`)
const filename = `${TSCONFIG_FILENAME}.${n}`
const iterationTsconfig = {
...tsconfig(),
compilerOptions: {
...tsconfig().compilerOptions,
rootDir: CWD,
outDir: OUT_DIR
},
include: (
await Promise.all(locations.map(location => calcIncludes(location)))
).reduce((acc, arr) => acc.concat(arr), [])
}
writeFileSync(
path.join(CWD, filename),
JSON.stringify(iterationTsconfig, null, 4)
)
await execa.command(`npx tsc --project ${filename}`, {
stdio: 'inherit'
})
for (const location of locations) {
await copyBuiltFiles(location)
}
}
const build = async () => {
const project = new Project(CWD)
const packages = await project.getPackages()
const graph = new QueryGraph(packages, {
graphType: 'allDependencies',
rejectCycles: false
})
const locations = packages.map(package => package.location)
const iterations = await splitIterations(graph)
await cleanPackages(locations)
for (let i = 0; i < iterations.length; i++) {
await buildIteration(iterations[i], i)
}
}
build().catch(e => {
console.error(`Build failed: ${String(e)}`)
process.exit(1)
})