Add build via esbuild

This configures the existing build tasks to use esbuild by default. If
using the plain files is desired, passing `--bundle=false` will build
using plain files and still produce a runnable system.

This is only a basic build; a more efficient build is provided later
when gulp is replaced by hereby.
This commit is contained in:
Jake Bailey
2022-09-13 16:21:03 -07:00
parent 36e29448e9
commit 4139807e75
47 changed files with 955 additions and 409 deletions

View File

@@ -0,0 +1 @@
export const localizationDirectories = ["cs", "de", "es", "fr", "it", "ja", "ko", "pl", "pt-br", "ru", "tr", "zh-cn", "zh-tw"].map(f => f.toLowerCase());

View File

@@ -4,7 +4,7 @@ import os from "os";
const ci = ["1", "true"].includes(process.env.CI ?? "");
const parsed = minimist(process.argv.slice(2), {
boolean: ["dirty", "light", "colors", "lkg", "soft", "fix", "failed", "keepFailed", "force", "built", "ci"],
boolean: ["dirty", "light", "colors", "lkg", "soft", "fix", "failed", "keepFailed", "force", "built", "ci", "bundle"],
string: ["browser", "tests", "break", "host", "reporter", "stackTraceLimit", "timeout", "shards", "shardId"],
alias: {
/* eslint-disable quote-props */
@@ -39,6 +39,7 @@ const parsed = minimist(process.argv.slice(2), {
dirty: false,
built: false,
ci,
bundle: true
}
});
@@ -77,5 +78,7 @@ export default options;
* @property {boolean} ci
* @property {string} shards
* @property {string} shardId
* @property {string} break
* @property {boolean} bundle
*/
void 0;

View File

@@ -1,61 +0,0 @@
import stream from "stream";
import ts from "../../lib/typescript.js";
import fs from "fs";
import { base64VLQFormatEncode } from "./sourcemaps.mjs";
/**
* @param {string | ((file: import("vinyl")) => string)} data
*/
export function prepend(data) {
return new stream.Transform({
objectMode: true,
/**
* @param {string | Buffer | import("vinyl")} input
* @param {(error: Error | null, data?: any) => void} cb
*/
transform(input, _, cb) {
if (typeof input === "string" || Buffer.isBuffer(input)) return cb(new Error("Only Vinyl files are supported."));
if (!input.isBuffer()) return cb(new Error("Streams not supported."));
try {
const output = input.clone();
const prependContent = typeof data === "function" ? data(input) : data;
output.contents = Buffer.concat([Buffer.from(prependContent, "utf8"), input.contents]);
if (input.sourceMap) {
if (typeof input.sourceMap === "string") input.sourceMap = /**@type {import("./sourcemaps.mjs").RawSourceMap}*/(JSON.parse(input.sourceMap));
const lineStarts = /**@type {*}*/(ts).computeLineStarts(prependContent);
let prependMappings = "";
for (let i = 1; i < lineStarts.length; i++) {
prependMappings += ";";
}
const offset = prependContent.length - lineStarts[lineStarts.length - 1];
if (offset > 0) {
prependMappings += base64VLQFormatEncode(offset) + ",";
}
output.sourceMap = {
version: input.sourceMap.version,
file: input.sourceMap.file,
sources: input.sourceMap.sources,
sourceRoot: input.sourceMap.sourceRoot,
mappings: prependMappings + input.sourceMap.mappings,
names: input.names,
sourcesContent: input.sourcesContent
};
}
// eslint-disable-next-line local/boolean-trivia, no-null/no-null
return cb(null, output);
}
catch (e) {
return cb(/** @type {Error} */(e));
}
}
});
}
/**
* @param {string | ((file: import("vinyl")) => string)} file
*/
export function prependFile(file) {
const data = typeof file === "string" ? fs.readFileSync(file, "utf8") :
(/** @type {import("vinyl")} */ vinyl) => fs.readFileSync(file(vinyl), "utf8");
return prepend(data);
}

View File

@@ -1,69 +1,57 @@
import { exec, Debouncer } from "./utils.mjs";
import { resolve } from "path";
import { findUpRoot } from "./findUpDir.mjs";
import assert from "assert";
import cmdLineOptions from "./options.mjs";
class ProjectQueue {
/**
* @param {(projects: string[], lkg: boolean, force: boolean) => Promise<any>} action
* @param {(projects: string[]) => Promise<any>} action
*/
constructor(action) {
/** @type {{ lkg: boolean, force: boolean, projects?: string[], debouncer: Debouncer }[]} */
this._debouncers = [];
this._action = action;
/** @type {string[] | undefined} */
this._projects = undefined;
this._debouncer = new Debouncer(100, async () => {
const projects = this._projects;
if (projects) {
this._projects = undefined;
await action(projects);
}
});
}
/**
* @param {string} project
* @param {{ lkg?: boolean; force?: boolean; }} options
*/
enqueue(project, { lkg = true, force = false } = {}) {
let entry = this._debouncers.find(entry => entry.lkg === lkg && entry.force === force);
if (!entry) {
const debouncer = new Debouncer(100, async () => {
assert(entry);
const projects = entry.projects;
if (projects) {
entry.projects = undefined;
await this._action(projects, lkg, force);
}
});
this._debouncers.push(entry = { lkg, force, debouncer });
}
if (!entry.projects) entry.projects = [];
entry.projects.push(project);
return entry.debouncer.enqueue();
enqueue(project) {
if (!this._projects) this._projects = [];
this._projects.push(project);
return this._debouncer.enqueue();
}
}
const execTsc = (/** @type {boolean} */ lkg, /** @type {string[]} */ ...args) =>
const execTsc = (/** @type {string[]} */ ...args) =>
exec(process.execPath,
[resolve(findUpRoot(), lkg ? "./lib/tsc" : "./built/local/tsc"),
[resolve(findUpRoot(), cmdLineOptions.lkg ? "./lib/tsc.js" : "./built/local/tsc.js"),
"-b", ...args],
{ hidePrompt: true });
const projectBuilder = new ProjectQueue((projects, lkg, force) => execTsc(lkg, ...(force ? ["--force"] : []), ...projects));
const projectBuilder = new ProjectQueue((projects) => execTsc(...projects));
/**
* @param {string} project
* @param {object} options
* @param {boolean} [options.lkg=true]
* @param {boolean} [options.force=false]
*/
export const buildProject = (project, { lkg, force } = {}) => projectBuilder.enqueue(project, { lkg, force });
export const buildProject = (project) => projectBuilder.enqueue(project);
const projectCleaner = new ProjectQueue((projects, lkg) => execTsc(lkg, "--clean", ...projects));
const projectCleaner = new ProjectQueue((projects) => execTsc("--clean", ...projects));
/**
* @param {string} project
*/
export const cleanProject = (project) => projectCleaner.enqueue(project);
const projectWatcher = new ProjectQueue((projects) => execTsc(/*lkg*/ true, "--watch", ...projects));
const projectWatcher = new ProjectQueue((projects) => execTsc("--watch", ...projects));
/**
* @param {string} project
* @param {object} options
* @param {boolean} [options.lkg=true]
*/
export const watchProject = (project, { lkg } = {}) => projectWatcher.enqueue(project, { lkg });
export const watchProject = (project) => projectWatcher.enqueue(project);

View File

@@ -122,17 +122,6 @@ export async function runConsoleTests(runJs, defaultReporter, runInParallel, _wa
errorStatus = exitCode;
error = new Error(`Process exited with status code ${errorStatus}.`);
}
else if (cmdLineOptions.ci && runJs.startsWith("built")) {
// finally, do a sanity check and build the compiler with the built version of itself
log.info("Starting sanity check build...");
// Cleanup everything except lint rules (we'll need those later and would rather not waste time rebuilding them)
await exec("gulp", ["clean-tsc", "clean-services", "clean-tsserver", "clean-lssl", "clean-tests"]);
const { exitCode } = await exec("gulp", ["local", "--lkg=false"]);
if (exitCode !== 0) {
errorStatus = exitCode;
error = new Error(`Sanity check build process exited with status code ${errorStatus}.`);
}
}
}
catch (e) {
errorStatus = undefined;

View File

@@ -3,6 +3,7 @@ import path from "path";
import glob from "glob";
import url from "url";
import del from "del";
import { localizationDirectories } from "./build/localization.mjs";
const __filename = url.fileURLToPath(new URL(import.meta.url));
const __dirname = path.dirname(__filename);
@@ -29,15 +30,9 @@ async function copyLibFiles() {
}
async function copyLocalizedDiagnostics() {
const dir = await fs.readdir(source);
const ignoredFolders = ["enu"];
for (const d of dir) {
for (const d of localizationDirectories) {
const fileName = path.join(source, d);
if (
fs.statSync(fileName).isDirectory() &&
ignoredFolders.indexOf(d) < 0
) {
if (fs.statSync(fileName).isDirectory()) {
await fs.copy(fileName, path.join(dest, d));
}
}
@@ -48,21 +43,18 @@ async function copyTypesMap() {
}
async function copyScriptOutputs() {
await copyWithCopyright("cancellationToken.js");
await copyWithCopyright("tsc.release.js", "tsc.js");
await copyWithCopyright("tsserver.js");
await copyWithCopyright("dynamicImportCompat.js");
await copyFromBuiltLocal("tsserverlibrary.js"); // copyright added by build
await copyFromBuiltLocal("typescript.js"); // copyright added by build
await copyFromBuiltLocal("typescriptServices.js"); // copyright added by build
await copyWithCopyright("typingsInstaller.js");
await copyWithCopyright("watchGuard.js");
await copyFromBuiltLocal("cancellationToken.js");
await copyFromBuiltLocal("tsc.js");
await copyFromBuiltLocal("tsserver.js");
await copyFromBuiltLocal("tsserverlibrary.js");
await copyFromBuiltLocal("typescript.js");
await copyFromBuiltLocal("typingsInstaller.js");
await copyFromBuiltLocal("watchGuard.js");
}
async function copyDeclarationOutputs() {
await copyFromBuiltLocal("tsserverlibrary.d.ts"); // copyright added by build
await copyFromBuiltLocal("typescript.d.ts"); // copyright added by build
await copyFromBuiltLocal("typescriptServices.d.ts"); // copyright added by build
await copyWithCopyright("tsserverlibrary.d.ts");
await copyWithCopyright("typescript.d.ts");
}
async function writeGitAttributes() {