Search code examples
javascripttypescriptcommonjs

Export TS to support ES6, CommonJS, and HTML <script> tag


I'm coding up a TS library that exports an object like this:

export const MyLibName: SDKExport = { ... }

This library will be distributed on npm and I want others to be able to import it regardless of their setup, i.e. it should be able to be used in the following ways:

// ES6
import { MyLibName } from './myLib';

// CommonJS
const { MyLibName } = require('./myLib');

// Browser
<script src="https://cdn.jsdelivr.net/npm/myLib/dist/dist.min.js"></script>
<script console.log(MyLibName) </script>

The browser part is proving to be the most tricky since it requires "polluting" the global namespace with the MyLibName object. I can do that, but it's unclear to me how to do it in a way that doesn't pollute the global namespace when importing the library explicitly using CommonJS/ES6.

Here's my tsconfig.json:

{
  "compilerOptions": {
    "lib": ["ES2019"],
    "module": "es6",
    "target": "es5",
    "moduleResolution": "node",
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "sourceMap": true,
    "outDir": "build",
    "strict": true,
    "noImplicitAny": true,
  },
  "include": ["./**/*.ts"],
  "exclude": ["node_modules", ".vscode", "test"]
}

Solution

  • It's clear that the script you're importing in the browser must be a different thing than your CommonJS/ES6 import if you want one to pollute the global namespace but not the other. Just create a file like this one and use your bundler on it to create a "browser build" of your library:

    import { MyLibName } from './myLib';
    window.MyLibName = MyLibName;
    

    (You seem to have a bundler/minifier in your project already so I won't go into detail on how to set up those.)