Setup esbuild and Typescript with React served from CDN

Add to HTML:

	<script src="/node_modules/react/umd/react.production.min.js"></script>
	<script src="/node_modules/react-dom/umd/react-dom.production.min.js"></script>

In typescript, import React like so:

import React from "react";

When using something from the React library, use e.g. React.useEffect rather than import {useEffect} from "react".

In esbuild.config.js:

let skipReactImports = {
    name: 'skipReactImports',
    setup(build) {
        build.onResolve({ filter: /^react(-dom)?$/ }, (args) => {
            return {
                path: args.path,
                namespace: `globalExternal_${args.path}`,
            };
        });

        build.onLoad(
            { filter: /.*/, namespace: 'globalExternal_react' },
            () => {
                return {
                    contents: `module.exports = globalThis.React`,
                    loader: 'js',
                };
            }
        );

        build.onLoad(
            { filter: /.*/, namespace: 'globalExternal_react-dom' },
            () => {
                return {
                    contents: `module.exports = globalThis.ReactDOM`,
                    loader: 'js',
                };
            }
        );
    },
};

And in the build config:

        plugins: [skipReactImports],
        external: ['react', 'react-dom'],

Note – perhaps not every step above is necessary, but after a lot of searching I did this here and it finally worked.

The motivation for this was that if the React code is bundled with the app, then Mozilla Linter raises warnings on direct DOM manipulation without sanitizing.

Due to both security and performance concerns, this may not be set using dynamic values which have not been adequately sanitized. This can lead to security issues or fairly serious performance degradation.

Inspired by this answer: https://github.com/evanw/esbuild/issues/806#issuecomment-779138268