Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Experiment with ESM modules in browser #20

Closed
adzialocha opened this issue Mar 6, 2023 · 11 comments · Fixed by #25
Closed

Experiment with ESM modules in browser #20

adzialocha opened this issue Mar 6, 2023 · 11 comments · Fixed by #25

Comments

@adzialocha
Copy link
Member

adzialocha commented Mar 6, 2023

<script type="module">
  import 'https://cdn.jsdelivr.net/npm/graphql-request@5.2.0/build/esm/index.js';
  import 'https://cdn.jsdelivr.net/npm/p2panda-js@0.7.0/lib/esm/index.js';
  import { initWebAssembly, KeyPair } from './lib/esm/index.js';

  initWebAssembly().then(() => {
    const keyPair = new KeyPair();
    console.log(keyPair.publicKey());
  });
</script>
@sandreae
Copy link
Member

I had a play with this and at first it didn't work, but now I got it going like so:

<script type="module">
  import { init } from './scripts/init.js';
  import { initWebAssembly, KeyPair } from './libs/shirokuma.js';

  initWebAssembly().then(() => {
    // Do your thing!
  });
</script>

Which is pretty ideal!

There were a couple of changes required to make it work:

  1. Changes to the rollup config to include external dependencies in the esm build with browser resolutions configured
if (format === 'umd' || format === 'esm') {
  result.push(
    pluginNodeResolve({
      // Use the "browser" module resolutions in the dependencies' package.json
      browser: true,
    }),
  );
}
  const external =
    format === 'umd' || format === 'esm' ? [] : Object.keys(pkg.dependencies);
  1. The graphql lib we're using has some issues with their browser builds (process is not defined in browsers graphql/graphql-js#3758) that seem to be not fully resolved and I hit the same issue (process not available), but no problem, graphql-web-lite to the rescue.

@adzialocha
Copy link
Member Author

Oh great!

Do we want to include external libraries in ESM builds? Haven't seen this being a practice yet, let's check maybe how other projects do it?

@sandreae
Copy link
Member

sandreae commented Jul 20, 2023

Hmmm, maybe not, I'm not sure to be honest. We should have an option to use shirokuma without build tooling though, cos you can do a lot with that on it's own.

@adzialocha
Copy link
Member Author

adzialocha commented Jul 20, 2023

Hmmm, maybe not, I'm not sure to be honest. We should have an option to use shirokuma without build tooling though, cos you can do a lot with that on it's own.

Yeah totally agree with that. Does it not work if you don't bundle 3rd party dependencies? Not sure I understand the problem.

The thing with ESM is that they got introduced to finally have native modules in browser contexts without bundlers, bundling 3rd party code in our library is somewhat contradictory but I see advantages and disadvantages.

Advantage is easy: it works out of the box.

Disadvantages: larger bundle size, no chance for the browsers to cache individual modules smartly when some parts didn't change, no deduplication when consumers of our module need similar dependencies. All of that stuff is what a modern bundler would do and I somehow assume that should still be given by browsers?!

I haven't been using ESM enough to understand the best practice really, a first search on the internet was not very successful 🤔

@sandreae
Copy link
Member

a first search on the internet was not very successful

Yeh, my experience too 🤣

I'll look at some other projects which aim to be low-barrier-to-entry and see how they do it.

@sandreae
Copy link
Member

Minified ESM shirokuma.min.js with everything bundled is 1.4M.

@sandreae
Copy link
Member

We could have another target which was just the bundled version, and leave the default ESM to not include external dependencies. Then we get the best of both worlds.

@sandreae
Copy link
Member

sandreae commented Jul 20, 2023

Yeah totally agree with that. Does it not work if you don't bundle 3rd party dependencies? Not sure I understand the problem.

Nah, doesn't work if you don't bundle dependencies, at least not how I have been trying, which is to import shirokuma.js locally. Maybe through https://www.jsdelivr.com/package/npm/shirokuma it might work now with the graphql fix.

@adzialocha
Copy link
Member Author

Yeah totally agree with that. Does it not work if you don't bundle 3rd party dependencies? Not sure I understand the problem.

Nah, doesn't work if you don't bundle dependencies, at least not how I have been trying, which is to import shirokuma.js locally. Maybe through https://www.jsdelivr.com/package/npm/shirokuma it might work now with the graphql fix.

Ah this sounds more like a rollup configuration issue then.

@adzialocha
Copy link
Member Author

We could have another target which was just the bundled version, and leave the default ESM to not include external dependencies. Then we get the best of both worlds.

Interesting! I'll do a little bit more "pattern seeking" and if non bundling is the vibe then we should totally do that.

@adzialocha
Copy link
Member Author

I've tried to use import maps to find out how far one gets with them:

<html>
  <head>
    <title>Shirokuma Test</title>
    <script type="importmap">
    {
      "imports": {
        "cross-fetch": "https://cdn.jsdelivr.net/npm/cross-fetch@4.0.0/dist/cross-fetch.js",
        "graphql": "https://cdn.jsdelivr.net/npm/graphql@16.7.1/index.min.js",
        "graphql-request": "https://cdn.jsdelivr.net/npm/graphql-request@6.1.0/build/esm/index.js",
        "p2panda-js": "https://cdn.jsdelivr.net/npm/p2panda-js@0.7.0/lib/esm/index.js",
        "shirokuma": "https://cdn.jsdelivr.net/npm/shirokuma@0.1.0/lib/esm/index.js"
      }
    }
    </script>
  </head>
  <body>
    <script type="module">
      import { initWebAssembly, KeyPair } from 'shirokuma';

      initWebAssembly().then(() => {
        const keyPair = new KeyPair();
        console.log(keyPair.publicKey());
      });
    </script>
  </body>
</html>

One ends up in quite a bit of trouble here with the dependencies not following what the browser wants to see. Maybe ESM is still too bleeding edge?

# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants