Simplify build and development steps

This commit is contained in:
Asher 2019-10-18 19:10:55 -05:00
parent 88cef85f62
commit 4cd2f2cd52
No known key found for this signature in database
GPG Key ID: D63C1EF81242354A
3 changed files with 50 additions and 58 deletions

View File

@ -58,17 +58,13 @@ arguments when launching code-server with Docker. See
### Build ### Build
- If you also plan on developing, set the `OUT` environment variable. Otherwise ```shell
it will build in this directory which will cause issues because `yarn watch` export OUT=/path/to/output/build # Optional if only building. Required if also developing.
will try to compile the build directory as well. yarn build ${vscodeVersion} ${codeServerVersion} # See travis.yml for the VS Code version to use.
- Run `yarn build ${vscodeVersion} ${codeServerVersion}` in this directory (for # The code-server version can be anything you want.
example: `yarn build 1.36.0 development`). node ~/path/to/output/build/out/vs/server/main.js # You can run the built JavaScript with Node.
- If you target the same VS Code version our Travis builds do everything will yarn binary ${vscodeVersion} ${codeServerVersion} # Or you can package it into a binary.
work but if you target some other version it might not (we have to do some ```
patching to VS Code so different versions aren't always compatible).
- You can run the built code with `node path/to/build/out/vs/server/main.js` or run
`yarn binary` with the same arguments in the previous step to package the
code into a single binary.
## Known Issues ## Known Issues
@ -109,11 +105,12 @@ data collected to improve code-server.
```shell ```shell
git clone https://github.com/microsoft/vscode git clone https://github.com/microsoft/vscode
cd vscode cd vscode
git checkout <see travis.yml for the VS Code version to use here> git checkout ${vscodeVersion} # See travis.yml for the version to use.
yarn
git clone https://github.com/cdr/code-server src/vs/server git clone https://github.com/cdr/code-server src/vs/server
cd src/vs/server cd src/vs/server
yarn patch:apply
yarn yarn
yarn patch:apply
yarn watch yarn watch
# Wait for the initial compilation to complete (it will say "Finished compilation"). # Wait for the initial compilation to complete (it will say "Finished compilation").
# Run the next command in another shell. # Run the next command in another shell.

View File

@ -2,15 +2,13 @@
"license": "MIT", "license": "MIT",
"scripts": { "scripts": {
"runner": "cd ./scripts && node --max-old-space-size=32384 -r ts-node/register ./build.ts", "runner": "cd ./scripts && node --max-old-space-size=32384 -r ts-node/register ./build.ts",
"preinstall": "yarn runner ensure-in-vscode && cd ../../../ && yarn || true", "start": "nodemon --watch ../../../out --verbose ../../../out/vs/server/main.js",
"postinstall": "rm -rf node_modules/@types/node", "watch": "cd ../../../ && yarn watch",
"start": "yarn runner ensure-in-vscode && nodemon --watch ../../../out --verbose ../../../out/vs/server/main.js", "build": "yarn && yarn runner build",
"watch": "yarn runner ensure-in-vscode && cd ../../../ && yarn watch",
"build": "yarn --ignore-scripts && yarn runner build",
"package": "yarn runner package", "package": "yarn runner package",
"binary": "yarn runner binary", "binary": "yarn runner binary",
"patch:generate": "yarn runner ensure-in-vscode && cd ../../../ && git diff --staged > ./src/vs/server/scripts/vscode.patch", "patch:generate": "cd ../../../ && git diff --staged > ./src/vs/server/scripts/vscode.patch",
"patch:apply": "yarn runner ensure-in-vscode && cd ../../../ && git apply ./src/vs/server/scripts/vscode.patch" "patch:apply": "cd ../../../ && git apply ./src/vs/server/scripts/vscode.patch"
}, },
"devDependencies": { "devDependencies": {
"@coder/nbin": "^1.2.2", "@coder/nbin": "^1.2.2",

View File

@ -20,21 +20,34 @@ class Builder {
private readonly rootPath = path.resolve(__dirname, ".."); private readonly rootPath = path.resolve(__dirname, "..");
private readonly outPath = process.env.OUT || this.rootPath; private readonly outPath = process.env.OUT || this.rootPath;
private _target?: "darwin" | "alpine" | "linux"; private _target?: "darwin" | "alpine" | "linux";
private task?: Task; private currentTask?: Task;
public run(task: Task | undefined, args: string[]): void { public run(task: Task | undefined, args: string[]): void {
this.task = task; this.currentTask = task;
this.doRun(task, args).catch((error) => { this.doRun(task, args).catch((error) => {
console.error(error.message); console.error(error.message);
process.exit(1); process.exit(1);
}); });
} }
private async task<T>(message: string, fn: () => Promise<T>): Promise<T> {
const time = Date.now();
this.log(`${message}...`, true);
try {
const t = await fn();
process.stdout.write(`took ${Date.now() - time}ms\n`);
return t;
} catch (error) {
process.stdout.write("failed\n");
throw error;
}
}
/** /**
* Writes to stdout with an optional newline. * Writes to stdout with an optional newline.
*/ */
private log(message: string, skipNewline: boolean = false): void { private log(message: string, skipNewline: boolean = false): void {
process.stdout.write(`[${this.task || "default"}] ${message}`); process.stdout.write(`[${this.currentTask || "default"}] ${message}`);
if (!skipNewline) { if (!skipNewline) {
process.stdout.write("\n"); process.stdout.write("\n");
} }
@ -140,24 +153,9 @@ class Builder {
* Build code-server within VS Code. * Build code-server within VS Code.
*/ */
private async build(vscodeSourcePath: string, vscodeVersion: string, codeServerVersion: string, finalBuildPath: string): Promise<void> { private async build(vscodeSourcePath: string, vscodeVersion: string, codeServerVersion: string, finalBuildPath: string): Promise<void> {
const task = async <T>(message: string, fn: () => Promise<T>): Promise<T> => {
const time = Date.now();
this.log(`${message}...`, true);
try {
const t = await fn();
process.stdout.write(`took ${Date.now() - time}ms\n`);
return t;
} catch (error) {
process.stdout.write("failed\n");
throw error;
}
};
// Install dependencies (should be cached by CI). // Install dependencies (should be cached by CI).
// Ignore scripts since we'll install VS Code dependencies separately. await this.task("Installing code-server dependencies", async () => {
await task("Installing code-server dependencies", async () => { await util.promisify(cp.exec)("yarn", { cwd: this.rootPath });
await util.promisify(cp.exec)("yarn --ignore-scripts", { cwd: this.rootPath });
await util.promisify(cp.exec)("yarn postinstall", { cwd: this.rootPath });
}); });
// Download and prepare VS Code if necessary (should be cached by CI). // Download and prepare VS Code if necessary (should be cached by CI).
@ -165,18 +163,18 @@ class Builder {
if (exists) { if (exists) {
this.log("Using existing VS Code directory"); this.log("Using existing VS Code directory");
} else { } else {
await task("Cloning VS Code", () => { await this.task("Cloning VS Code", () => {
return util.promisify(cp.exec)( return util.promisify(cp.exec)(
"git clone https://github.com/microsoft/vscode" "git clone https://github.com/microsoft/vscode"
+ ` --quiet --branch "${vscodeVersion}"` + ` --quiet --branch "${vscodeVersion}"`
+ ` --single-branch --depth=1 "${vscodeSourcePath}"`); + ` --single-branch --depth=1 "${vscodeSourcePath}"`);
}); });
await task("Installing VS Code dependencies", () => { await this.task("Installing VS Code dependencies", () => {
return util.promisify(cp.exec)("yarn", { cwd: vscodeSourcePath }); return util.promisify(cp.exec)("yarn", { cwd: vscodeSourcePath });
}); });
await task("Building default extensions", () => { await this.task("Building default extensions", () => {
return util.promisify(cp.exec)( return util.promisify(cp.exec)(
"yarn gulp compile-extensions-build --max-old-space-size=32384", "yarn gulp compile-extensions-build --max-old-space-size=32384",
{ cwd: vscodeSourcePath }, { cwd: vscodeSourcePath },
@ -185,14 +183,14 @@ class Builder {
} }
// Clean before patching or it could fail if already patched. // Clean before patching or it could fail if already patched.
await task("Patching VS Code", async () => { await this.task("Patching VS Code", async () => {
await util.promisify(cp.exec)("git reset --hard", { cwd: vscodeSourcePath }); await util.promisify(cp.exec)("git reset --hard", { cwd: vscodeSourcePath });
await util.promisify(cp.exec)("git clean -fd", { cwd: vscodeSourcePath }); await util.promisify(cp.exec)("git clean -fd", { cwd: vscodeSourcePath });
await util.promisify(cp.exec)(`git apply ${this.rootPath}/scripts/vscode.patch`, { cwd: vscodeSourcePath }); await util.promisify(cp.exec)(`git apply ${this.rootPath}/scripts/vscode.patch`, { cwd: vscodeSourcePath });
}); });
const serverPath = path.join(vscodeSourcePath, "src/vs/server"); const serverPath = path.join(vscodeSourcePath, "src/vs/server");
await task("Copying code-server into VS Code", async () => { await this.task("Copying code-server into VS Code", async () => {
await fs.remove(serverPath); await fs.remove(serverPath);
await fs.mkdirp(serverPath); await fs.mkdirp(serverPath);
await Promise.all(["main.js", "node_modules", "src", "typings"].map((fileName) => { await Promise.all(["main.js", "node_modules", "src", "typings"].map((fileName) => {
@ -200,16 +198,16 @@ class Builder {
})); }));
}); });
await task("Building VS Code", () => { await this.task("Building VS Code", () => {
return util.promisify(cp.exec)("yarn gulp compile-build --max-old-space-size=32384", { cwd: vscodeSourcePath }); return util.promisify(cp.exec)("yarn gulp compile-build --max-old-space-size=32384", { cwd: vscodeSourcePath });
}); });
await task("Optimizing VS Code", async () => { await this.task("Optimizing VS Code", async () => {
await fs.copyFile(path.join(this.rootPath, "scripts/optimize.js"), path.join(vscodeSourcePath, "coder.js")); await fs.copyFile(path.join(this.rootPath, "scripts/optimize.js"), path.join(vscodeSourcePath, "coder.js"));
await util.promisify(cp.exec)(`yarn gulp optimize --max-old-space-size=32384 --gulpfile ./coder.js`, { cwd: vscodeSourcePath }); await util.promisify(cp.exec)(`yarn gulp optimize --max-old-space-size=32384 --gulpfile ./coder.js`, { cwd: vscodeSourcePath });
}); });
const { productJson, packageJson } = await task("Generating final package.json and product.json", async () => { const { productJson, packageJson } = await this.task("Generating final package.json and product.json", async () => {
const merge = async (name: string, extraJson: { [key: string]: string } = {}): Promise<{ [key: string]: string }> => { const merge = async (name: string, extraJson: { [key: string]: string } = {}): Promise<{ [key: string]: string }> => {
const [aJson, bJson] = (await Promise.all([ const [aJson, bJson] = (await Promise.all([
fs.readFile(path.join(vscodeSourcePath, `${name}.json`), "utf8"), fs.readFile(path.join(vscodeSourcePath, `${name}.json`), "utf8"),
@ -247,13 +245,13 @@ class Builder {
}); });
if (process.env.MINIFY) { if (process.env.MINIFY) {
await task("Minifying VS Code", () => { await this.task("Minifying VS Code", () => {
return util.promisify(cp.exec)("yarn gulp minify --max-old-space-size=32384 --gulpfile ./coder.js", { cwd: vscodeSourcePath }); return util.promisify(cp.exec)("yarn gulp minify --max-old-space-size=32384 --gulpfile ./coder.js", { cwd: vscodeSourcePath });
}); });
} }
const finalServerPath = path.join(finalBuildPath, "out/vs/server"); const finalServerPath = path.join(finalBuildPath, "out/vs/server");
await task("Copying into final build directory", async () => { await this.task("Copying into final build directory", async () => {
await fs.remove(finalBuildPath); await fs.remove(finalBuildPath);
await fs.mkdirp(finalBuildPath); await fs.mkdirp(finalBuildPath);
await Promise.all([ await Promise.all([
@ -271,7 +269,7 @@ class Builder {
}); });
if (process.env.MINIFY) { if (process.env.MINIFY) {
await task("Restricting to production dependencies", async () => { await this.task("Restricting to production dependencies", async () => {
await Promise.all(["package.json", "yarn.lock"].map((fileName) => { await Promise.all(["package.json", "yarn.lock"].map((fileName) => {
Promise.all([ Promise.all([
fs.copy(path.join(this.rootPath, fileName), path.join(finalServerPath, fileName)), fs.copy(path.join(this.rootPath, fileName), path.join(finalServerPath, fileName)),
@ -279,10 +277,9 @@ class Builder {
]); ]);
})); }));
await Promise.all([ await Promise.all([finalServerPath, finalBuildPath].map((cwd) => {
util.promisify(cp.exec)("yarn --production --ignore-scripts", { cwd: finalServerPath }), return util.promisify(cp.exec)("yarn --production", { cwd });
util.promisify(cp.exec)("yarn --production", { cwd: finalBuildPath }), }));
]);
await Promise.all(["package.json", "yarn.lock"].map((fileName) => { await Promise.all(["package.json", "yarn.lock"].map((fileName) => {
return Promise.all([ return Promise.all([
@ -293,7 +290,7 @@ class Builder {
}); });
} }
await task("Writing final package.json and product.json", () => { await this.task("Writing final package.json and product.json", () => {
return Promise.all([ return Promise.all([
fs.writeFile(path.join(finalBuildPath, "package.json"), JSON.stringify(packageJson, null, 2)), fs.writeFile(path.join(finalBuildPath, "package.json"), JSON.stringify(packageJson, null, 2)),
fs.writeFile(path.join(finalBuildPath, "product.json"), JSON.stringify(productJson, null, 2)), fs.writeFile(path.join(finalBuildPath, "product.json"), JSON.stringify(productJson, null, 2)),
@ -301,7 +298,7 @@ class Builder {
}); });
// This is so it doesn't get cached along with VS Code (no point). // This is so it doesn't get cached along with VS Code (no point).
await task("Removing copied server", () => fs.remove(serverPath)); await this.task("Removing copied server", () => fs.remove(serverPath));
// Prepend code to the target which enables finding files within the binary. // Prepend code to the target which enables finding files within the binary.
const prependLoader = async (relativeFilePath: string): Promise<void> => { const prependLoader = async (relativeFilePath: string): Promise<void> => {
@ -322,7 +319,7 @@ class Builder {
await fs.writeFile(filePath, shim + (await fs.readFile(filePath, "utf8"))); await fs.writeFile(filePath, shim + (await fs.readFile(filePath, "utf8")));
}; };
await task("Prepending nbin loader", () => { await this.task("Prepending nbin loader", () => {
return Promise.all([ return Promise.all([
prependLoader("out/vs/server/main.js"), prependLoader("out/vs/server/main.js"),
prependLoader("out/bootstrap-fork.js"), prependLoader("out/bootstrap-fork.js"),