Browser use

Native modules or one global.

Choose standards-first ES modules for new work, or keep an existing script-tag integration with the supported browser-global file.

Native ES modules

When your server exposes node_modules or copies package assets into a public directory, import the canonical module directly.

<script type="module">
    import Message from './node_modules/js-message/index.js';

    const ready = new Message({
        type: 'page.ready',
        data: { path: location.pathname }
    });

    console.log(ready.JSON);
</script>

A bundler may still resolve import Message from 'js-message', but js-message itself does not require one.

Browser-global entry

<script src="./node_modules/js-message/js-message-vanilla.js"></script>
<script>
    const message = new Message();
    message.type = 'legacy.ready';
    message.data = { ok: true };
</script>

The side-effect file assigns the class to globalThis.Message. It is behaviorally tested against the module class, including object and JSON loading, invalid shapes, and serializable errors.

Use a closing script tag.

HTML script elements are not self-closing. The explicit </script> prevents the browser from treating later markup as script content.

WebSockets and workers

const socket = new WebSocket(url);

socket.addEventListener('message', (event) => {
    const message = new Message(event.data);

    if (message.type === 'error') {
        console.error(message.data.err);
        return;
    }

    dispatch(message.type, message.data);
});

In a worker, use the ES-module entry or load the global file through your existing worker strategy. The global entry targets globalThis, not only window.