-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathbuild.ts
179 lines (157 loc) · 4.72 KB
/
build.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
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
import {exec} from 'child_process';
import del = require('del');
import {readFileSync} from 'fs';
import {dest, series, src} from 'gulp';
import rename = require('gulp-rename');
import replace = require('gulp-replace');
import path = require('path');
import webpack = require('webpack');
import TerserPlugin = require('terser-webpack-plugin');
const WASM_PACK_DEST = 'wasm';
const PROJ_NAME = 'rusty-typescript';
const TMP = 'tmp';
const DIST = 'dist';
const SNAKECASE_PROJ_NAME = PROJ_NAME.replace('-', '_');
const JS_FILENAME = `${SNAKECASE_PROJ_NAME}.js`;
const BG_JS_FILENAME = `${SNAKECASE_PROJ_NAME}_bg.js`;
const BG_WASM_FILENAME = `${SNAKECASE_PROJ_NAME}_bg.wasm`;
const BUNDLE_JS = 'wasm.js';
const BUNDLE_TS = BUNDLE_JS.replace('.js', '.ts');
const TYPESCRIPT_GIT_SUBMODULE = 'TypeScript';
const REPLACE = 'TypeScript-replace';
function cleanWasmPackDest() {
return del(path.resolve(__dirname, WASM_PACK_DEST));
}
function cleanTmp() {
return del(path.resolve(__dirname, TMP));
};
function cleanDist() {
return del(path.resolve(__dirname, DIST));
}
export const clean = series(
cleanWasmPackDest,
cleanTmp,
cleanDist,
resetTypeScriptGitSubmodule,
);
const execCommand = (command: string, cwd = '') => new Promise(
(resolve, reject) => {
exec(command, {cwd}, (error, stdout) => {
if (error) {
reject(error);
return;
}
resolve(stdout);
});
}
);
async function wasmPack() {
await execCommand(`wasm-pack build --target nodejs --out-dir ${WASM_PACK_DEST}`);
}
/**
* Inline the file rusty_typescript_bg.wasm into rusty_typescript_bg.js
* serialized as base64 and copy it into the tmp/ folder.
*/
function inlineWasm() {
const wasm = readFileSync(path.resolve(__dirname, WASM_PACK_DEST, BG_WASM_FILENAME));
const base64 = wasm.toString('base64');
const bytesLines = [
`const atob = typeof window !== 'undefined' ? window.atob : b64 => Buffer.from(b64, 'base64').toString('binary');`,
`const binaryString = atob('${base64}');`,
`const bytes = new Uint8Array(${wasm.length});`,
`for (let i = 0; i < ${wasm.length}; i++) {`,
` bytes[i] = binaryString.charCodeAt(i);`,
`}\n`
].join('\n');
return src([path.resolve(__dirname, WASM_PACK_DEST, BG_JS_FILENAME)])
// remove the import of 'path'
.pipe(replace(/const path = .*\n/g, ''))
// replace the loading of the wasm bytes to use the inlined base64 version
.pipe(replace(/const bytes = .*\n/g, bytesLines))
.pipe(dest(TMP));
}
/**
*
*/
function patchJsFile() {
return src([path.resolve(__dirname, WASM_PACK_DEST, JS_FILENAME)])
.pipe(replace(/const TextDecoder = .*\n/g, `require('fast-text-encoding');\n`))
.pipe(dest(TMP));
}
function copyToTmp() {
return src([
path.resolve(__dirname, WASM_PACK_DEST, '**'),
`!${path.resolve(__dirname, WASM_PACK_DEST, BG_WASM_FILENAME)}`,
`!${path.resolve(__dirname, WASM_PACK_DEST, BG_JS_FILENAME)}`,
`!${path.resolve(__dirname, WASM_PACK_DEST, JS_FILENAME)}`
])
.pipe(dest(TMP));
}
function bundle() {
const config: webpack.Configuration = {
entry: `./${JS_FILENAME}`,
output: {
filename: `./${BUNDLE_JS}`,
path: path.resolve(__dirname, DIST),
library: 'RustyTypeScript',
libraryTarget: 'var'
},
context: path.resolve(__dirname, TMP),
optimization: {
minimizer: [
new TerserPlugin({
extractComments: {
condition: true,
banner: false
}
})
]
}
};
return new Promise((resolve, reject) => webpack(
config,
(err) => {
if (err) {
console.error(err);
reject(err);
} else {
resolve();
}
}
));
}
export const build = series(
clean,
wasmPack,
inlineWasm,
patchJsFile,
copyToTmp,
bundle
);
function makeTsBundle() {
return src([path.resolve(__dirname, DIST, BUNDLE_JS)])
// inject the @ts-ignore magic comment to disable type checking
.pipe(replace(/^/, '// @ts-ignore\n'))
// inject the tslint:disable magic comment to disable tslint for this file
.pipe(replace(/^/, '// tslint:disable\n'))
.pipe(rename(BUNDLE_TS))
.pipe(dest(DIST));
}
async function resetTypeScriptGitSubmodule() {
await execCommand('git reset --hard', TYPESCRIPT_GIT_SUBMODULE);
await execCommand('git clean -f -d', TYPESCRIPT_GIT_SUBMODULE);
}
function injectTsBundle() {
return src([path.resolve(__dirname, DIST, BUNDLE_TS)])
.pipe(dest(path.resolve(__dirname, TYPESCRIPT_GIT_SUBMODULE, 'src', 'compiler')));
}
function replaceTypeScriptSources() {
return src([path.resolve(__dirname, REPLACE, '**')])
.pipe(dest(path.resolve(__dirname, TYPESCRIPT_GIT_SUBMODULE)));
}
export const inject = series(
build,
makeTsBundle,
injectTsBundle,
replaceTypeScriptSources
);