Skip to content

Remove unneeded modules with tsconfig verbatimModuleSyntax#741

Open
isker wants to merge 1 commit into
GoogleChrome:mainfrom
isker:verbatim-module-syntax
Open

Remove unneeded modules with tsconfig verbatimModuleSyntax#741
isker wants to merge 1 commit into
GoogleChrome:mainfrom
isker:verbatim-module-syntax

Conversation

@isker
Copy link
Copy Markdown

@isker isker commented May 18, 2026

I noticed when browsing the distributed code in the npm package that the various types modules are actually present in build output and reachable from package.json exports. If you use the type keyword with relevant import and export statements, these statements will be erased like any other types during the build, thereby making the various types.js modules unreachable.

This behavior can be enforced with the verbatimModuleSyntax tsconfig option: https://www.typescriptlang.org/tsconfig/#verbatimModuleSyntax.

The same final result would effectively be achieved by any bundler consuming the NPM package that does treeshaking (as the types.js modules all just contain export {}; as the only code), but this change could help other kinds of consumers, and also humans reading the code directly.

I noticed when browsing the distributed code in the npm package that the
various `types` modules are actually present in build output and
reachable from package.json `exports`. If you use the `type` keyword
with relevant import and export statements, these statements will be
erased like any other types during the build, thereby making the various
`types.js` modules unreachable.

This behavior can be enforced with the `verbatimModuleSyntax` tsconfig
option: https://www.typescriptlang.org/tsconfig/#verbatimModuleSyntax.

The same final result would effectively be achieved by any bundler
consuming the NPM package that does treeshaking (as the types.js modules
all just contain `export {};` as the only code), but this change could
help other kinds of consumers, and also humans reading the code
directly.
@tunetheweb
Copy link
Copy Markdown
Member

I'm failing to understand what exactly this gives us? It does make types.js smaller but at the expense of a slight increase in the other files. So I can't see how it's making the dist smaller or excluding any more details that shouldn't be part of the public API?

And I'm not sure this makes the code more readable, but that may just be may lack of familiarity with it.

@isker
Copy link
Copy Markdown
Author

isker commented May 22, 2026

Here's the full diff to distributed JS files:

diff --color=auto -x *.d.ts -ru /tmp/dist-before/modules/attribution/index.js /tmp/dist-after/modules/attribution/index.js
--- /tmp/dist-before/modules/attribution/index.js	2026-05-21 22:13:11
+++ /tmp/dist-after/modules/attribution/index.js	2026-05-21 22:11:59
@@ -23,4 +23,3 @@
 export { INPThresholds } from '../onINP.js';
 export { LCPThresholds } from '../onLCP.js';
 export { TTFBThresholds } from '../onTTFB.js';
-export * from '../types.js';
diff --color=auto -x *.d.ts -ru /tmp/dist-before/modules/attribution/onINP.js /tmp/dist-after/modules/attribution/onINP.js
--- /tmp/dist-before/modules/attribution/onINP.js	2026-05-21 22:13:11
+++ /tmp/dist-after/modules/attribution/onINP.js	2026-05-21 22:11:59
@@ -16,7 +16,7 @@
 import { getLoadState } from '../lib/getLoadState.js';
 import { getSelector } from '../lib/getSelector.js';
 import { initUnique } from '../lib/initUnique.js';
-import { InteractionManager } from '../lib/InteractionManager.js';
+import { InteractionManager, } from '../lib/InteractionManager.js';
 import { observe } from '../lib/observe.js';
 import { whenIdleOrHidden } from '../lib/whenIdleOrHidden.js';
 import { onINP as unattributedOnINP } from '../onINP.js';
diff --color=auto -x *.d.ts -ru /tmp/dist-before/modules/index.js /tmp/dist-after/modules/index.js
--- /tmp/dist-before/modules/index.js	2026-05-21 22:13:11
+++ /tmp/dist-after/modules/index.js	2026-05-21 22:11:59
@@ -18,4 +18,3 @@
 export { onINP, INPThresholds } from './onINP.js';
 export { onLCP, LCPThresholds } from './onLCP.js';
 export { onTTFB, TTFBThresholds } from './onTTFB.js';
-export * from './types.js';
diff --color=auto -x *.d.ts -ru /tmp/dist-before/modules/types.js /tmp/dist-after/modules/types.js
--- /tmp/dist-before/modules/types.js	2026-05-21 22:13:11
+++ /tmp/dist-after/modules/types.js	2026-05-21 22:11:59
@@ -13,9 +13,4 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-export * from './types/base.js';
-export * from './types/cls.js';
-export * from './types/fcp.js';
-export * from './types/inp.js';
-export * from './types/lcp.js';
-export * from './types/ttfb.js';
+export {};
  1. The index.js files stop referring to types.js at all.
  2. types.js is empty, but more importantly, it's not reachable from index.js or any other package entrypoint.

When you said "a slight increase in the other files", were you talking about the type declaration files? There is a dichotomy of files executed by JavaScript interpreters (the files in the above diff), and type declaration files, which are only used by TypeScript. The goal with verbatimModuleSyntax is to make the division between these halves more absolute, by requiring the type keyword on all imports of types (as opposed to JS values).

The TypeScript compiler then can erase those imports in the same way that it erases all other types, when outputting JavaScript. Without the type keyword, this erasure does not take place, resulting in needless linkage between JavaScript modules at runtime.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants