Static Imports Are Undermining JavaScript’s Isomorphism —…
    Neura MarketNeura Market/DeepSeek
    ChatGPTChatGPTClaudeClaudeGeminiGeminiCursorCursorGrokGrokPerplexityPerplexityDeepSeekDeepSeek
    CoPilotCoPilotStable DiffusionStable DiffusionMidjourneyMidjourney
    View All Directories
    OverviewRulesPromptsMCPsAgentsGamesBlogVideosGuidesCoursesCommunityTrending
    DeepSeekBlogStatic Imports Are Undermining JavaScript’s Isomorphism
    Back to Blog
    Static Imports Are Undermining JavaScript’s Isomorphism
    javascript

    Static Imports Are Undermining JavaScript’s Isomorphism

    Alex Gusev February 25, 2026
    0 views

    Early binding reduces runtime universality. Dependency Injection restores control at the composition root.


    title: Static Imports Are Undermining JavaScript’s Isomorphism published: true description: Early binding reduces runtime universality. Dependency Injection restores control at the composition root. tags: #javascript #webdev #architecture #designpatterns

    cover_image: https://direct_url_to_image.jpg

    Use a ratio of 100:42 for best results.

    published_at: 2026-02-24 14:51 +0000


    TL;DR

    • Static imports bind dependencies at module-load time.
    • Early binding encodes platform assumptions.
    • Declared dependencies move those decisions to the composition root.
    • This is not a new module system. It is standard Dependency Injection applied at the module level.

    JavaScript runs natively in both the browser and on the server. That makes true isomorphism possible.

    And yet modern JavaScript architecture quietly works against it.

    Consider:

    import fs from "node:fs";
    

    This line embeds a Node-only capability directly into the module. A browser cannot satisfy "node:fs" by default. The module is no longer isomorphic.

    The issue is not fs. The issue is early binding.

    Static imports resolve dependencies during module evaluation. The host fixes the graph before your code runs. If a dependency is platform-specific, the module becomes platform-specific.


    Making dependencies explicit

    Instead of binding immediately, a module can declare what it needs.

    // user-service.mjs
    
    export const __deps__ = {
      fs: "node:fs",
      logger: "./logger.mjs",
    };
    
    export default function makeUserService({ fs, logger }) {
      return {
        readUserJson(path) {
          const raw = fs.readFileSync(path, "utf8");
          logger.log(`Read ${raw.length} bytes`);
          return JSON.parse(raw);
        },
      };
    }
    

    The module imports nothing directly. It declares a dependency contract and receives concrete implementations from the outside.

    This is Dependency Injection applied at the module level. The composition root decides what gets passed in.


    Manual composition root

    Node

    // node-entry.mjs
    
    import fs from "node:fs";
    import logger from "./logger.mjs";
    import makeUserService from "./user-service.mjs";
    
    const service = makeUserService({ fs, logger });
    

    Browser

    // browser-entry.mjs
    
    import fsAdapter from "./browser-fs-adapter.mjs";
    import logger from "./logger.mjs";
    import makeUserService from "./user-service.mjs";
    
    const service = makeUserService({
      fs: fsAdapter,
      logger,
    });
    

    The module did not change. Only the composition root changed.

    Platform decisions stay at the edge of the system — and because dependencies are injected explicitly, tests can pass fakes directly instead of mocking module imports.


    Automating composition

    Because the contract is exposed via __deps__, the composition root can be made data-driven:

    // link.mjs
    
    export async function link(entrySpecifier, overrides = {}) {
      const mod = await import(entrySpecifier);
      const depsSpec = mod.__deps__ ?? {};
      const deps = {};
    
      for (const [name, specifier] of Object.entries(depsSpec)) {
        const finalSpecifier = overrides[specifier] ?? specifier;
        const imported = await import(finalSpecifier);
        deps[name] = imported.default ?? imported;
      }
    
      return mod.default(deps);
    }
    

    Node

    const service = await link("./user-service.mjs");
    

    Browser

    const service = await link("./user-service.mjs", {
      "node:fs": "./browser-fs-adapter.mjs",
    });
    

    Binding becomes explicit program logic, not loader side effects.


    How this differs from import maps and exports

    • Import maps control specifier resolution at load time (host-level).
    • package.json exports select entry points per environment (package-level).
    • Bundlers optimize graphs at build time.
    • Composition root + DI decides which concrete capabilities a module receives at runtime (application-level).

    Import maps answer: Where is this module? Composition root answers: Which capability does this module receive?

    Different layers, different concerns.


    Trade-offs

    This approach is not free:

    • You lose some static analyzability and tree-shaking precision.
    • TypeScript integration becomes more manual.
    • It’s unnecessary for small or purely single-runtime apps.
    • It introduces architectural discipline (composition root).

    This is a tool, not a default.


    When to use it

    Use it when:

    • You want true cross-runtime modules (Node + browser + edge).
    • You want environment decisions centralized.
    • You care about testability without heavy mocking.
    • You want explicit capability boundaries.

    Do not use it when:

    • Your app is single-runtime.
    • Build-time optimization and tree-shaking are primary concerns.
    • Simplicity outweighs architectural flexibility.

    Static imports are not wrong. They are efficient and idiomatic.

    But they bind early. And early binding encodes platform assumptions.

    If we care about preserving JavaScript’s isomorphism, we should be deliberate about where binding happens.

    Because once a module binds to a platform capability during evaluation, it has already chosen its platform.

    Tags

    javascriptwebdevarchitecturedesignpatterns

    Comments

    More Blog

    View all
    Five Gemma-4 models, one accelerator: what porting E2B 31B to AWS Inferentia2 taught megemma

    Five Gemma-4 models, one accelerator: what porting E2B 31B to AWS Inferentia2 taught me

    I ported the whole Gemma-4 family — E2B, E4B, 12B, 31B, and the 26B-A4B MoE — to run on...

    X
    xbill
    Hey DEV, I'm Tobore. Let's actually connect.community

    Hey DEV, I'm Tobore. Let's actually connect.

    Hey DEV, I'm Tobore. Let's actually connect. I've been on here for a while now, mostly writing and...

    L
    Laurina Ayarah
    I burned through thousands of AI tokens. Then a friend did it for freeai

    I burned through thousands of AI tokens. Then a friend did it for free

    (yep, kinda clickbait, just for the funsies 😊) At the beginning of the year, I relaunched my...

    P
    Paulo Henrique
    Claude might be saturating your machineai

    Claude might be saturating your machine

    My laptop was sitting idle with the fan at full tilt. Nothing was running that I knew of. The culprit...

    S
    Sidhant Panda
    Automated GitHub Code Reviews Using Google Geminigithubactions

    Automated GitHub Code Reviews Using Google Gemini

    I Built a Thing! TL;DR — Google Gemini-based Pull Request reviews and Issue Triaging for...

    D
    Darren "Dazbo" Lester
    What is an "agentic harness," actually?ai

    What is an "agentic harness," actually?

    I've been hearing the word "harness" thrown around a lot lately. I assumed it just meant "the IDE" or...

    T
    Tilde A. Thurium

    Stay up to date

    Get the latest DeepSeek prompts, rules, and resources delivered to your inbox weekly.

    Neura Market LogoNeura Market

    Discover the best AI prompts, plugins, and resources for DeepSeek and more.

    Content Types

    • Rules
    • Prompts
    • MCPs
    • Agents
    • Guides

    Platforms

    • ChatGPT Directory
    • Claude Directory
    • Gemini Directory
    • Cursor Directory
    • Grok Directory
    • Perplexity Directory
    • DeepSeek Directory
    • CoPilot Directory
    • Stable Diffusion Directory
    • Midjourney Directory
    • All Directories

    Resources

    • Blog
    • Documentation
    • Help Center
    • Marketplace

    Legal

    • Privacy Policy
    • Terms of Service

    © 2026 Neura Market. All rights reserved.

    |

    Not affiliated with any AI platform vendors.

    Neura Market

    Custom AI Systems & Services

    Our team of experienced AI builders will help build custom AI systems, workflows, and solutions for your business.

    Request custom work