Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reduce size of parser-typescript.js #12531

Closed
wants to merge 16 commits into from
56 changes: 2 additions & 54 deletions scripts/build/config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import path from "node:path";
import { createRequire } from "node:module";
import createEsmUtils from "esm-utils";
import { PROJECT_ROOT } from "../utils/index.mjs";
import replaceTypescriptModule from "./replace-typescript-module.mjs";

const { require } = createEsmUtils(import.meta);

Expand Down Expand Up @@ -101,62 +102,9 @@ const parsers = [
},
{
module: require.resolve("typescript"),
process(text) {
return text.replace(
/(?<=\n)(?<indentString>\s+)function tryGetNodePerformanceHooks\(\) {.*?\n\k<indentString>}(?=\n)/s,
"function tryGetNodePerformanceHooks() {}"
);
},
process: replaceTypescriptModule,
},

...Object.entries({
// `typescript/lib/typescript.js` expose extra global objects
// `TypeScript`, `toolsVersion`, `globalThis`
'typeof process === "undefined" || process.browser': "false",
'typeof globalThis === "object"': "true",

"_fs.realpathSync.native":
"_fs.realpathSync && _fs.realpathSync.native",
// Remove useless `ts.sys`
"ts.sys = ": "ts.sys = undefined && ",

// Remove useless language service
"ts.realizeDiagnostics = ": "ts.realizeDiagnostics = undefined && ",
"ts.TypeScriptServicesFactory = ":
"ts.TypeScriptServicesFactory = undefined && ",
"var ShimBase = ": "var ShimBase = undefined && ",
"var TypeScriptServicesFactory = ":
"var TypeScriptServicesFactory = undefined && ",
"var LanguageServiceShimObject = ":
"var LanguageServiceShimObject = undefined && ",
"var CoreServicesShimHostAdapter = ":
"var CoreServicesShimHostAdapter = undefined && ",
"var LanguageServiceShimHostAdapter = ":
"var LanguageServiceShimHostAdapter = undefined && ",
"var ScriptSnapshotShimAdapter = ":
"var ScriptSnapshotShimAdapter = undefined && ",
"var ClassifierShimObject = ":
"var ClassifierShimObject = undefined && ",
"var CoreServicesShimObject = ":
"var CoreServicesShimObject = undefined && ",
"function simpleForwardCall(": "0 && function simpleForwardCall(",
"function forwardJSONCall(": "0 && function forwardJSONCall(",
"function forwardCall(": "0 && function forwardCall(",
"function realizeDiagnostics(": "0 && function realizeDiagnostics(",
"function realizeDiagnostic(": "0 && function realizeDiagnostic(",
"function convertClassifications(":
"0 && function convertClassifications(",

// Dynamic `require()`s
"ts.sys && ts.sys.require": "false",
"require(etwModulePath)": "undefined",
'require("source-map-support").install()': "",
"require(modulePath)": "undefined",
}).map(([find, replacement]) => ({
module: require.resolve("typescript"),
find,
replacement,
})),
{
module: require.resolve("debug/src/browser.js"),
path: require.resolve("./shims/debug.cjs"),
Expand Down
274 changes: 274 additions & 0 deletions scripts/build/replace-typescript-module.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,274 @@
import createEsmUtils from "esm-utils";
import { replaceAlignedCode } from "./utils.mjs";

const { require } = createEsmUtils(import.meta);

/*
In typescript package, there are many block in shape like

```js
var ts;
(function (ts) {
// ...
})(ts || (ts = {}));
```
*/
function removeBlock(text, test) {
if (typeof test === "string") {
const testString = test;
test = (text) => text.includes(testString);
}

return replaceAlignedCode(text, {
start: "var ts;\n(function (ts) {",
end: "})(ts || (ts = {}));",
replacement: (part) => (test(part) ? "" : part),
});
}

function replaceTypescriptModule(text) {
// Deprecated apis
text = removeBlock(
text,
"// The following are deprecations for the public API."
);

// Remove useless language service
text = removeBlock(
text,
"ts.TypeScriptServicesFactory = TypeScriptServicesFactory;"
);

// Remove useless file accessing
text = removeBlock(
text,
"ts.createSystemWatchFunctions = createSystemWatchFunctions;"
);

// Remove useless compiler
text = removeBlock(
text,
"ts.convertCompilerOptionsFromJson = convertCompilerOptionsFromJson;"
);

// Remove useless performance
text = removeBlock(
text,
"ts.tryGetNativePerformanceHooks = tryGetNativePerformanceHooks;"
);
text = removeBlock(
text,
"performance = ts.performance || (ts.performance = {})"
);

// Remove useless performance tracing
text = removeBlock(
text,
"ts.startTracing = tracingEnabled.startTracing;"
);
text = removeBlock(
text,
"ts.trace = trace;"
);

// Remove useless path related
// text = removeBlock(text, "ts.resolvePath = resolvePath;");

// Remove useless diagnosticMessages
// text = removeBlock(text, "ts.Diagnostics = {");
text = removeBlock(
text,
"ts.sortAndDeduplicateDiagnostics = sortAndDeduplicateDiagnostics;"
);

text = removeBlock(
text,
"ts.createSourceMapGenerator = createSourceMapGenerator;"
);
text = removeBlock(
text,
"ts.isBuildInfoFile = isBuildInfoFile;"
);
text = removeBlock(
text,
"ts.findConfigFile = findConfigFile;"
);
text = removeBlock(
text,
"ts.createBuilderProgram = createBuilderProgram;"
);
text = removeBlock(
text,
"moduleSpecifiers = ts.moduleSpecifiers || (ts.moduleSpecifiers = {})"
);
text = removeBlock(
text,
"ts.resolveConfigFileProjectName = resolveConfigFileProjectName;"
);
text = removeBlock(
text,
"Completions = ts.Completions || (ts.Completions = {})"
);
text = removeBlock(
text,
"DocumentHighlights = ts.DocumentHighlights || (ts.DocumentHighlights = {})"
);
text = removeBlock(
text,
"ts.createDocumentRegistry = createDocumentRegistry;"
);
text = removeBlock(
text,
"FindAllReferences = ts.FindAllReferences || (ts.FindAllReferences = {})"
);
text = removeBlock(
text,
"CallHierarchy = ts.CallHierarchy || (ts.CallHierarchy = {})"
);
text = removeBlock(
text,
"ts.getEditsForFileRename = getEditsForFileRename;"
);
text = removeBlock(
text,
"GoToDefinition = ts.GoToDefinition || (ts.GoToDefinition = {})"
);
text = removeBlock(
text,
"JsDoc = ts.JsDoc || (ts.JsDoc = {})"
);
text = removeBlock(
text,
"NavigateTo = ts.NavigateTo || (ts.NavigateTo = {})"
);
text = removeBlock(
text,
"NavigationBar = ts.NavigationBar || (ts.NavigationBar = {})"
);
text = removeBlock(
text,
"OrganizeImports = ts.OrganizeImports || (ts.OrganizeImports = {})"
);
text = removeBlock(
text,
"classifier = ts.classifier || (ts.classifier = {})"
);

//
text = removeBlock(
text,
"ts.getScriptTargetFeatures = getScriptTargetFeatures;"
);

//
text = removeBlock(
text,
"BuilderState = ts.BuilderState || (ts.BuilderState = {})"
);

//
text = removeBlock(
text,
"codefix = ts.codefix || (ts.codefix = {})"
);
text = removeBlock(
text,
"BreakpointResolver = ts.BreakpointResolver || (ts.BreakpointResolver = {})"
);
text = removeBlock(
text,
"ts.transform = transform;"
);
text = removeBlock(
text,
"ts.getDefaultLibFilePath = getDefaultLibFilePath;"
);
text = removeBlock(
text,
"refactor = ts.refactor || (ts.refactor = {})"
);
text = removeBlock(
text,
"textChanges = ts.textChanges || (ts.textChanges = {})"
);
text = removeBlock(
text,
"formatting = ts.formatting || (ts.formatting = {})"
);
text = removeBlock(
text,
"ts.fixupCompilerOptions = fixupCompilerOptions;"
);
text = removeBlock(
text,
"SymbolDisplay = ts.SymbolDisplay || (ts.SymbolDisplay = {})"
);
text = removeBlock(
text,
"ts.canBeConvertedToAsync = canBeConvertedToAsync;"
);
text = removeBlock(
text,
"ts.getSourceMapper = getSourceMapper;"
);
text = removeBlock(
text,
"InlayHints = ts.InlayHints || (ts.InlayHints = {})"
);
text = removeBlock(
text,
"SignatureHelp = ts.SignatureHelp || (ts.SignatureHelp = {})"
);
text = removeBlock(
text,
"SmartSelectionRange = ts.SmartSelectionRange || (ts.SmartSelectionRange = {})"
);
text = removeBlock(
text,
"Rename = ts.Rename || (ts.Rename = {})"
);
text = removeBlock(
text,
"ts.preProcessFile = preProcessFile;"
);


// `typescript/lib/typescript.js` expose extra global objects
// `TypeScript`, `toolsVersion`, `globalThis`
text = replaceAlignedCode(text, {
start: 'if (typeof process === "undefined" || process.browser) {',
end: "}",
replacement: "",
});

text = replaceAlignedCode(text, {
start: "((function () {",
end: "})());",
replacement(part) {
return part.includes("__magic__") ? "" : part;
},
});

text = replaceAlignedCode(text, {
start: "try {",
end: "}",
replacement(part) {
return part.includes("require(etwModulePath)") ? "try {}" : part;
},
});

text = replaceAlignedCode(text, {
start: "if (ts.sys && ts.sys.require) {",
end: "}",
replacement: "",
});

require("fs").writeFileSync(
require.resolve("typescript") + ".modified.js",
text
);

return text;
}

export default replaceTypescriptModule;
29 changes: 29 additions & 0 deletions scripts/build/utils.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import escapeStringRegexp from "escape-string-regexp";

function replaceAlignedCode(text, { start, end, replacement }) {
const regex = new RegExp(
[
"(?<=\\n)",
"(?<indentString>\\s*)",
escapeStringRegexp(start),
"\\n",
".*?",
"\\n",
"\\k<indentString>",
escapeStringRegexp(end),
"(?=\\n)",
].join(""),
"gs"
);

const replaced = text.replaceAll(regex, replacement);

if (replaced === text) {
console.log({ start, end, replacement });
throw new Error("Code didn't change.");
}

return replaced;
}

export { replaceAlignedCode };