keichi / binary-parser

A blazing-fast declarative parser builder for binary data
MIT License
864 stars 134 forks source link

feat: add ESM package export #176

Closed manzt closed 2 years ago

manzt commented 2 years ago

Thank you for your work on this excellent project.

This PR adds an extra build step to produce a "pure" ESM entrypoint for binary-parser. ESM is now natively supported in Node>12 and all major browsers.

The postscript to add an .mjs extensions to the TSC output is added because 1.) the package.json is not set to "type": "module", and 2.) ESM does not allow for relative imports without file extensions (so import ... from "./context" cannot be resolved by the Node ESM resolver or in browsers). ESM is additionally a desirable target for bundlers.

Finally, if the polyfill for TextDecoder is removed, this script can be loaded natively in the browser via a local server (or a cdn).

<script type="module">
import { Parser } from 'http://localhost:8080/dist/esm/binary_parser.mjs';

// in the future
import { Parser } from 'https://unpkg.com/binary_parser/dist/esm/binary_parser.mjs';
import { Parser } from 'https://cdn.skypack.dev/binary_parser'; // supports package exports fields

</script>
manzt commented 2 years ago

Done! An alternative to merging the source files would be to use a bundler (see: https://github.com/manzt/binary-parser/tree/manzt/esm-esbuild), but this is probably the most simple build as is.

keichi commented 2 years ago

Thanks! Yes, I've looked into esbuild but let's not overcomplicate things for now.

keichi commented 2 years ago

Just published a new release. Can you test if the ESM support works as expected?

manzt commented 2 years ago

Wonderful! Everything seems to be working:

// package.json
{
  "name": "demos",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "binary-parser": "^2.0.0"
  }
}
// index.js
const { Parser } = require('binary-parser');
console.log(Parser);

// index.mjs
import { Parser } from 'binary-parser';
console.log(Parser);
~/demos is 📦 v1.0.0 via  v16.9.1 took 14s
❯ node index.js
[Function: Parser] { start: [Function (anonymous)] }

~/demos is 📦 v1.0.0 via  v16.9.1
❯ node index.mjs
[class Parser]

Additionally, you can import the package in the browser now directly via a CDN:

<script type="module">
  import { Parser } from 'https://cdn.skypack.dev/binary-parser'; // recognizes package.exports fields
  import { Parser } from 'https://unpkg.com/binary-parser/dist/esm/binary_parser.js';
</script>

live example: https://observablehq.com/d/003b4f096ee7c6b2

EDIT: Oh! also binary-parser runs in deno:

❯ echo "import('https://cdn.skypack.dev/binary-parser').then(console.log)" | deno run --allow-net -
Module { Parser: [Function: Parser], default: null }