Search code examples
javascripthtmlpreact

Is mixing bundled modules and JavaScript Modules possible


Inspired by preact's "no build tools route", I recently created a project with no build or bundling process. Conceptually, it looks like this (pseudo code following).

I have a dependency on react-button which uses e.g. microbundle to resolve the preact import through the node_modules folder.

// dependency 1: "preact-button" npm package (uses bundler)
import { h, Component, render } from 'preact';

const button = h('button', null, 'Click');
export default Button;

Then, there's my app which requires preact-button as a dependency. It's just a .html file for now.

<!doctype html>
<html>
  <head>
    <meta charset="utf-8"/>
    <title>SO App</title>
    <script type="module">
      import { h, Component, render } from 'https://unpkg.com/preact?module';
      import Button from "https://fantasycdn.com/preact-button?module"
    </script>
  </head>
  <body>
  </body>
</html>

However, my app is not using any bundler and hence imports preact-button's code. If I had a bundler, this wouldn't be a problem, as the import ... from "preact" would be resolved through the bundler. But now, taking advantage of the type="module" syntax, this global module name cannot be imported anymore. Instead, an error is thrown:

react-button.js:
Uncaught TypeError: Error resolving module specifier “preact”. Relative module specifiers must start with “./”, “../” or “/”.

As the author of preact-button, what I want though is that my module:

  • can be used with a bundler (as shown above)
  • can be used within a JavaScript module by somehow resolving it's dependencies (dynamically?)

Since preact advertises this approach on their website, I took a quick look into their build process. They have a simple advantage, which is that they don't have to deal with any kind of dependencies (e.g. peer or regular), as they simply don't have any.

But is it possible to mix bundled modules and JavaScript modules without any heavy build process? Is there maybe even a commonly agreed upon approach?


Solution

  • Notice that UNPKG claims:

    ?module

    Expands all “bare” import specifiers in JavaScript modules to unpkg URLs. This feature is very experimental

    This means that your build would be transformed and cached courtesy of UNPKG into:

    import { h, Component, render } from 'https://unpkg.com/preact@^10.4.6?module';
    
    const button = h('button', null, 'Click');
    export default Button;
    

    As a confirmation of this claim, I checked how ?module handles one of my bundled libraries on UNPKG, and it transforms:

    import { Parser, Grammar } from 'nearley';
    import moo from 'moo';
    

    into:

    import { Parser, Grammar } from "https://unpkg.com/nearley@^2.19.1?module";
    import moo from "https://unpkg.com/moo@^0.5.1?module";
    

    Assuming that your preact-button module is published on npm, the current usage of bare import specifiers in your code should not be an issue.