Skip to content

Use the compilation cache when running typescript files through --experimental-transform-types #54741

Closed
@ShenHongFei

Description

@ShenHongFei

What is the problem this feature will solve?

The flags --experimental-strip-types and --experimental-transform-types enable Node.js to run almost all TypeScript files. #54283

This feature of running .ts files directly is great. I recently removed the step of compiling .ts files to .js and started the project directly through node entry.ts, and then directly imported other .ts modules.

However, in a large project with many files, compiling .ts files takes up a lot of startup time (about 200ms for all files using .js, and about 700ms for .ts). If there is a compilation cache, skipping the compilation of the same .ts file and directly using the .js compilation result, it will be very efficient.

What is the feature you are proposing to solve the problem?

After I got this idea, I tried to simply modify lib/internal/modules/esm/translators.js and add local file cache. Now the speed of running .ts file for the second time is exactly the same as .js.

I hope someone can combine .ts compilation cache with the current .js compilation cache in node.js.

diff --git a/lib/internal/modules/esm/translators.js b/lib/internal/modules/esm/translators.js
index b1e7b860..8eb172b1 100644
--- a/lib/internal/modules/esm/translators.js
+++ b/lib/internal/modules/esm/translators.js
@@ -24,8 +24,9 @@ const {
 
 const { BuiltinModule } = require('internal/bootstrap/realm');
 const assert = require('internal/assert');
-const { readFileSync } = require('fs');
-const { dirname, extname, isAbsolute } = require('path');
+const { readFileSync, writeFileSync } = require('fs');
+const { dirname, extname, basename, isAbsolute } = require('path');
+const crypto = require('crypto')
 const {
   assertBufferSource,
   loadBuiltinModule,
@@ -484,11 +485,38 @@ translators.set('commonjs-typescript', function(url, source) {
   return FunctionPrototypeCall(translators.get('commonjs'), this, url, code, false);
 });
 
+
+// --- patch: Compile .ts esm files with typescirpt and cache
+const filepath_cache = process.env.NODE_COMPILE_CACHE + '/'
+
 // Strategy for loading an esm TypeScript module
 translators.set('module-typescript', function(url, source) {
-  emitExperimentalWarning('Type Stripping');
-  assertBufferSource(source, false, 'load');
-  const code = stripTypeScriptTypes(stringify(source), url);
-  debug(`Translating TypeScript ${url}`);
-  return FunctionPrototypeCall(translators.get('module'), this, url, code, false);
-});
+    emitExperimentalWarning('Type Stripping');
+    assertBufferSource(source, false, 'load')
+    
+    const str_source = stringify(source)
+    
+    const [
+      code = stripTypeScriptTypes(str_source, url),
+      filepath_js
+    ] = (() => {
+        const filepath_js = filepath_cache +
+            url.slice('file:///'.length).replaceAll(':', '_').replaceAll('/', '_').slice(0, -2) +
+            crypto.hash('sha256', str_source).slice(0, 8) +
+            '.js'
+        
+        try {
+            return [readFileSync(filepath_js, 'utf-8')]
+        } catch { }
+        
+        return [undefined, filepath_js]
+    })()
+    
+    if (filepath_js)
+        try {
+            writeFileSync(filepath_js, code)
+        } catch { }
+    
+    return FunctionPrototypeCall(translators.get('module'), this, url, code, false)
+})
+

@nodejs/typescript
@marco-ippolito @joyeecheung

What alternatives have you considered?

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    feature requestIssues that request new features to be added to Node.js.loadersIssues and PRs related to ES module loadersstrip-typesIssues or PRs related to strip-types support

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions