forked from Carroted/Bimulo
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathbuild.js
286 lines (273 loc) · 11.9 KB
/
build.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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
// This is a super simple script for `npm run build` that creates a `dist-package.json` file based on the `package.json` file.
// Since it's not supposed to be in `dist`, it's not a TypeScript file to build and is just a plain JS file. It works cross-platform.
import fs from 'fs';
import * as url from "url";
const __filename = url.fileURLToPath(import.meta.url);
const __dirname = url.fileURLToPath(new URL(".", import.meta.url));
import path from 'path';
import chalk from 'chalk';
// import child_process
import { exec } from 'child_process';
const packageJson = JSON.parse(fs.readFileSync(__dirname + '/package.json', 'utf8'));
function capitalizeFirstLetter(string) {
return string.charAt(0).toUpperCase() + string.slice(1);
}
var buildLogPath = path.join(__dirname, 'build-log.json');
var buildInfo = chalk.bold('Building ' + capitalizeFirstLetter(packageJson.name) + ' v' + packageJson.version + '...\n');
var prevBuildTime = null;
if (fs.existsSync(buildLogPath)) {
var buildLog = JSON.parse(fs.readFileSync(buildLogPath, 'utf8'));
var timeToBuild;
if (buildLog.prevBuildTime) {
var timeToBuild1 = buildLog.buildTime; // ms
var timeToBuild2 = buildLog.prevBuildTime; // ms
timeToBuild = (timeToBuild1 + timeToBuild2) / 2; // average
}
else {
timeToBuild = buildLog.buildTime;
}
var timeToBuildSeconds = timeToBuild / 1000;
// ceil it
timeToBuildSeconds = Math.ceil(timeToBuildSeconds);
console.log(buildInfo + 'Estimated time to build: ' + timeToBuildSeconds + 's\n');
prevBuildTime = timeToBuild;
}
else {
console.log(buildInfo);
}
var startTime = Date.now();
function indentLines(str, count) {
var lines = str.split('\n');
var newLines = [];
for (var line of lines) {
newLines.push(' '.repeat(count) + line);
}
return newLines.join('\n');
}
var steps = [
// remove dist folder
async (stepInfo) => {
// first, remove dist folder
const distPath = path.join(__dirname, 'dist');
if (fs.existsSync(distPath)) {
console.log(stepInfo, 'Clearing previous build...');
fs.rmSync(distPath, { recursive: true });
}
else {
console.log(stepInfo, 'No previous build');
}
},
// run tsc
async (stepInfo) => {
console.log(stepInfo, 'Compiling TypeScript...');
var srcDirs = ['client', 'server', 'shared'];
var promises = [];
for (var srcDir of srcDirs) {
promises.push(new Promise((resolve, reject) => {
const child = exec('tsc -p ' + srcDir, { cwd: __dirname });
child.stdout.on('data', (data) => {
console.log(chalk.bold(chalk.redBright(indentLines(data.toString(), 4))));
});
child.stderr.on('data', (data) => {
console.error(chalk.bold(chalk.redBright(indentLines(data.toString(), 4))));
});
child.on('close', (code) => {
if (code !== 0) {
reject(new Error(`TypeScript compiler exited with code ${code}`));
} else {
resolve();
}
});
}));
}
await Promise.all(promises);
},
/*// make dist/client folder if doesnt exist
async (stepInfo) => {
if (!fs.existsSync(path.join(__dirname, 'dist', 'client'))) {
console.log(stepInfo, 'Creating dist/client folder...');
fs.mkdirSync(path.join(__dirname, 'dist', 'client'));
}
else {
console.log(stepInfo, 'dist/client folder already exists');
}
},*/
// generate distPackage
async (stepInfo) => {
console.log(stepInfo, 'Creating dist-package.json...');
// create a `dist-package.json` file
var distPackage = {
name: packageJson.name,
version: packageJson.version,
main: 'server/src/index.js',
scripts: {
start: 'node server/src/index.js',
build: 'echo "This is a build, run this on the source" && exit 1' // for convenience since people will likely accidentally run this
},
dependencies: packageJson.dependencies,
engines: packageJson.engines,
type: packageJson.type
};
// write to dist/package.json with 4 spaces
fs.writeFileSync(path.join(__dirname, 'dist', 'package.json'), JSON.stringify(distPackage, null, 4));
},
// recursively copy client/assets to dist/client/assets, client/icons to dist/client/icons, client/index.css and client/index.html to dist/client and media to dist/media. finally, node_modules to dist/node_modules and client/src to dist/client/src
async (stepInfo) => {
// we'll do above in separate steps
console.log(stepInfo, 'Copying client/assets to dist/client/assets...');
copyFolderRecursiveSync(path.join(__dirname, 'client', 'assets'), path.join(__dirname, 'dist', 'client', 'assets'));
},
async (stepInfo) => {
console.log(stepInfo, 'Copying client/icons to dist/client/icons...');
copyFolderRecursiveSync(path.join(__dirname, 'client', 'icons'), path.join(__dirname, 'dist', 'client', 'icons'));
},
async (stepInfo) => {
console.log(stepInfo, 'Copying client/index.css to dist/client...');
fs.copyFileSync(path.join(__dirname, 'client', 'index.css'), path.join(__dirname, 'dist', 'client', 'index.css'));
},
async (stepInfo) => {
console.log(stepInfo, 'Copying client/index.html to dist/client...');
fs.copyFileSync(path.join(__dirname, 'client', 'index.html'), path.join(__dirname, 'dist', 'client', 'index.html'));
},
async (stepInfo) => {
console.log(stepInfo, 'Copying client/manifest.json to dist/client...');
fs.copyFileSync(path.join(__dirname, 'client', 'manifest.json'), path.join(__dirname, 'dist', 'client', 'manifest.json'));
},
async (stepInfo) => {
console.log(stepInfo, 'Copying client/sw.js to dist/client...');
fs.copyFileSync(path.join(__dirname, 'client', 'sw.js'), path.join(__dirname, 'dist', 'client', 'sw.js'));
},
async (stepInfo) => {
console.log(stepInfo, 'Copying media to dist/media...');
copyFolderRecursiveSync(path.join(__dirname, 'media'), path.join(__dirname, 'dist', 'media'));
},
// copy box2d-wasm-7.0.0.tgz to dist
async (stepInfo) => {
console.log(stepInfo, 'Copying box2d-wasm-7.0.0.tgz to dist...');
fs.copyFileSync(path.join(__dirname, 'box2d-wasm-7.0.0.tgz'), path.join(__dirname, 'dist', 'box2d-wasm-7.0.0.tgz'));
},
async (stepInfo) => {
console.log(stepInfo, 'Installing node_modules...');
// install node_modules in dist
await new Promise((resolve, reject) => {
const child = exec('npm install --omit=dev', { cwd: path.join(__dirname, 'dist') });
child.stdout.on('data', (data) => {
console.log(indentLines(data.toString(), 4));
});
child.stderr.on('data', (data) => {
console.error(chalk.bold(chalk.redBright(indentLines(data.toString(), 4))));
});
child.on('close', (code) => {
if (code !== 0) {
reject(new Error(`npm install exited with code ${code}`));
} else {
resolve();
}
});
});
},
async (stepInfo) => {
console.log(stepInfo, 'Copying client/src to dist/client/src...');
copyFolderRecursiveSync(path.join(__dirname, 'client', 'src'), path.join(__dirname, 'dist', 'client', 'src'));
},
// copy shared/src/intersect.js to dist/shared/src
async (stepInfo) => {
console.log(stepInfo, 'Copying shared/src/intersect.js to dist/shared/src...');
fs.copyFileSync(path.join(__dirname, 'shared', 'src', 'intersect.js'), path.join(__dirname, 'dist', 'shared', 'src', 'intersect.js'));
},
// read all files in client and list them in dist/client/filelist.txt for serviceworker caching
async (stepInfo) => {
console.log(stepInfo, 'Creating dist/client/filelist.txt...');
var files = [];
var clientPath = path.join(__dirname, 'dist', 'client');
var walkSync = function (dir, prepend) {
// get all files of the current directory & iterate over them
var dirFiles = fs.readdirSync(dir);
dirFiles.forEach(function (file) {
// construct whole file-path & retrieve file's stats
var filePath = path.join(dir, file);
var fileStat = fs.statSync(filePath);
if (fileStat.isDirectory()) {
// recursive call if it's a directory
walkSync(path.join(dir, file), prepend + file + '/');
}
else {
// add current file to fileList array
if (!filePath.endsWith('.ts')) {
// make relative
var relativePath = path.relative(dir, filePath);
files.push(prepend + relativePath);
}
}
});
};
// start recursion to fill fileList
walkSync(clientPath, '/');
var sharedPath = path.join(__dirname, 'dist', 'shared');
walkSync(sharedPath, '/shared/');
var mediaPath = path.join(__dirname, 'dist', 'media');
walkSync(mediaPath, '/media/');
var box2DPath = path.join(__dirname, 'dist', 'node_modules', 'box2d-wasm', 'dist');
walkSync(box2DPath, '/node_modules/box2d-wasm/dist/');
// remove /sw.js (its a bit silly to cache the service worker itself, how would it get itself from the cache if its not active to do so? and it seems to cause error too)
files = files.filter(function (file) { return file !== '/sw.js'; });
files.push('/Simulo');
files.push('/');
// remove / from the start of each one
files = files.map(function (file) { return file.substring(1); });
// create dist/client/filelist.txt file with fileList content
fs.writeFileSync(path.join(clientPath, 'filelist.txt'), files.join('\n'));
},
// add the date to version.json
async (stepInfo) => {
console.log(stepInfo, 'Creating dist/version.json...');
var version = {
date: new Date().getTime(),
version: packageJson.version
};
fs.writeFileSync(path.join(__dirname, 'dist', 'version.json'), JSON.stringify(version, null, 4));
},
async (stepInfo) => {
console.log(stepInfo, 'Creating log...');
var endTime = Date.now();
var log;
if (prevBuildTime) {
log = {
buildTime: endTime - startTime,
prevBuildTime: prevBuildTime,
};
}
else {
log = {
buildTime: endTime - startTime
};
}
fs.writeFileSync(buildLogPath, JSON.stringify(log, null, 4));
}
];
function copyFolderRecursiveSync(source, target) {
var files = [];
// check if folder needs to be created or integrated
var targetFolder = target;
if (!fs.existsSync(targetFolder)) {
fs.mkdirSync(targetFolder);
}
// copy
if (fs.lstatSync(source).isDirectory()) {
files = fs.readdirSync(source);
files.forEach(function (file) {
var curSource = path.join(source, file);
if (fs.lstatSync(curSource).isDirectory()) {
copyFolderRecursiveSync(curSource, path.join(targetFolder, path.basename(curSource)));
}
else {
fs.copyFileSync(curSource, path.join(targetFolder, path.basename(curSource)));
}
});
}
}
// run steps
for (var i = 0; i < steps.length; i++) {
await steps[i]((i + 1) + '/' + steps.length);
}
console.log(chalk.greenBright.bold('\nBuild complete!'));