htmx icon indicating copy to clipboard operation
htmx copied to clipboard

Add ES Module (ESM) support to the factory

Open codingjoe opened this issue 1 year ago • 17 comments

Hi there 👋,

Currently, the factory supports AMD, CJS and browser environments. However, modern websites and browsers have proper module (ESM) support.

Let's say you want to do something like this:

<!DOCTYPE html>
<html lang="en">
<head>
<title>HTMX via ESM</title>
</head>
<body>
<script type="module">
import htmx from 'https://unpkg.com/htmx.org'
htmx.logAll()
</script>
</body>
</html>

Your browser will tell you that htmx.org doesn't export a default. Similarly, something like this also does not work:

import { logAll } from 'https://unpkg.com/htmx.org'
logAll()

Both are completely valid use cases and have, as of writing this, over 97% browser support.

I think adoption would be rather simple. Everything already works in NodeJS or rather CommonJS (CJS). All that's needed would be to extend the factory to export ESM modules in a browser.

If you want to take this one step further, we could also consider to properly defining entry points via NodeJS' exports. This would be particularly helpful if you wish to load extensions.

I would be happy to contribute a small patch.

Cheers! Joe

codingjoe avatar Feb 01 '24 18:02 codingjoe

Hey, it seems (I know nothing about all this so you tell me 😆) we have esm support in v2 alpha, if you're willing to take a look and test if things work as expected?

Telroshan avatar Feb 25 '24 21:02 Telroshan

Hey, it seems (I know nothing about all this so you tell me 😆) we have esm support in v2 alpha, if you're willing to take a look and test if things work as expected?

Nope, no luck. 2.0 doesn't export anything. And the extensions are not declared in the package.json file, either.

I happen to know a thing or two about ESM, I am happy to help. Just say the word and I will gladly submit a patch.

codingjoe avatar Feb 26 '24 17:02 codingjoe

in v2.0 we have a .esm.js file that does export htmx:

https://github.com/bigskysoftware/htmx/blob/f004978bbbf68befb49bfef7f17a2ec25ce35ae0/dist/htmx.esm.js#L3917

1cg avatar Feb 26 '24 18:02 1cg

in v2.0 we have a .esm.js file that does export htmx:

https://github.com/bigskysoftware/htmx/blob/f004978bbbf68befb49bfef7f17a2ec25ce35ae0/dist/htmx.esm.js#L3917

Yes, I saw that, but that's not how you export an ESM module ;)

codingjoe avatar Feb 26 '24 18:02 codingjoe

I must have missed what export stands for. ;)

And for the sake of everyone’s sanity, let’s not overcomplicate it for nothing.

andryyy avatar Feb 26 '24 18:02 andryyy

in v2.0 we have a .esm.js file that does export htmx: https://github.com/bigskysoftware/htmx/blob/f004978bbbf68befb49bfef7f17a2ec25ce35ae0/dist/htmx.esm.js#L3917

Yes, I saw that, but that's not how you export an ESM module ;)

Would you like to elaborate on this...? I too have been laboring under the delusion that one exported ECMAScript modules with the export command.

alexpetros avatar Feb 26 '24 18:02 alexpetros

Please excuse my previous response. I didn't explain it well. Let me try again:

Yes, export is used to export in ESM, but nothing is ever simple in JavaScript. htmx is an anonymous function. Anonymous functions may only be exported as a default. So, you either name the export, name the function, or export it as a default. Defaults don't need to be named.

Again, super happy to provide a patch, with tests. If my help is still welcome ❤️‍🩹

codingjoe avatar Feb 26 '24 19:02 codingjoe

is it an anonymous function? I thought it was a plain javascript object returned by the IIFE...

1cg avatar Feb 26 '24 19:02 1cg

is it an anonymous function? I thought it was a plain javascript object returned by the IIFE...

https://github.com/bigskysoftware/htmx/blob/f004978bbbf68befb49bfef7f17a2ec25ce35ae0/src/htmx.js#L1

It's exporting the outer wrapper, not the object. Both would not be leading to the desired result. The latter would allow at least something like import * as htmx from 'htmx.org'. But that's maybe not the way to go here. A default export might be the most elegant and intuitive solution for most.

codingjoe avatar Feb 26 '24 20:02 codingjoe

Please excuse my previous response. I didn't explain it well. Let me try again:

Appreciated! And don't worry about it.

The latter would allow at least something like import * as htmx from 'htmx.org'.

Correct me if I'm wrong, but the current export { htmx } statement we have in the the esm wrapper supports this, right?

alexpetros avatar Feb 26 '24 20:02 alexpetros

The latter would allow at least something like import * as htmx from 'htmx.org'.

Correct me if I'm wrong, but the current export { htmx } statement we have in the the esm wrapper supports this, right?

No, it does not. export htmx without the breakets might work… I would need to check.

But again, whether there is a bug, this is fairy easy to reproduce:

Here is HTMX.org 2.0-alpha2 Screenshot 2024-02-26 at 21 41 22

Here is Lit, just to show how a module should look like in a browser. Screenshot 2024-02-26 at 21 41 45

codingjoe avatar Feb 26 '24 20:02 codingjoe

Oh, I know exactly what you're talking about—you can't export anonymous objects from an export statement i.e. the export {} just doesn't work. I completely forgot about that. Okay so the existing factory is bugged—we can fix that.

Is the change you were going to suggest just export default htmx?

alexpetros avatar Feb 26 '24 20:02 alexpetros

I am adding myself to this as I also need ESM exports to allow reuse.

there are some hacks to overcome it....

https://github.com/terrablue/htmx-esm btw, is used by

https://github.com/primatejs/primate https://primatejs.com/modules/htmx

gedw99 avatar Feb 29 '24 13:02 gedw99

If this is implemented, it would be nice to add deep exports in package.json for the extensions such that it's possible to do something like export * from "htmx.org/client-side-templates/handlebars"; to be picked up by the bundler, see https://github.com/terrablue/htmx-esm/blob/master/package.json#L11-L38

I would be more than happy to get rid of the needless vendoring, seeing as I need to update it every time a new HTMX version comes out.

terrablue avatar Feb 29 '24 14:02 terrablue

If this is implemented, it would be nice to add deep exports in package.json for the extensions such that it's possible to do something like export * from "htmx.org/client-side-templates/handlebars"; to be picked up by the bundler, see https://github.com/terrablue/htmx-esm/blob/master/package.json#L11-L38

I would be more than happy to get rid of the needless vendoring, seeing as I need to update it every time a new HTMX version comes out.

Yes, I mentioned that in the original ticket report. I will submit a patch for that.

codingjoe avatar Mar 01 '24 13:03 codingjoe

Is the change you were going to suggest just export default htmx?

Yes, I believe this would be most consistent with the docs, where you call htmx.someFunction. Be it on a window or module scope. I will be easy copy and paste for most people.

codingjoe avatar Mar 01 '24 13:03 codingjoe

Since there seems to be plenty of traffic on this issue, I will submit a patch targeting the 2.0 release.

codingjoe avatar Mar 01 '24 13:03 codingjoe

I looked at the code for 2.0 and decided to discontinue using HTMX. Maybe someone else will pick this up someday.

codingjoe avatar Mar 23 '24 08:03 codingjoe

I looked at the code for 2.0 and decided to discontinue using HTMX. Maybe someone else will pick this up someday.

Would you like to share what it was about the 2.0 code that discouraged you? It's really not that different

alexpetros avatar Mar 23 '24 14:03 alexpetros

I looked at the code for 2.0 and decided to discontinue using HTMX. Maybe someone else will pick this up someday.

Would you like to share what it was about the 2.0 code that discouraged you? It's really not that different

Hi @alexpetros, I would rather not discourage anyone. I know how much work goes into a project this size. Thus, will stick to errors:

  1. extensions are not built in 2.0
  2. test suite wasn't fully working (some files were renamed, but not their references)
  3. extension are neither CSJ or ESM compatible

As a personal note: Tools like Wireit and Rollup or ESbuild might make the build processes more smooth. Lifting browser support to Baseline 2023 might also simplify things.

I appreciate the effort put into this package <3 We use mostly Web Components and are fairly happy writing JavaScript code and have maybe not the ideal user profile.

codingjoe avatar Mar 24 '24 12:03 codingjoe

Ok! Well, anyway, we're going to switch to default exports for htmx 2.0: https://github.com/bigskysoftware/htmx/pull/2428

alexpetros avatar Mar 24 '24 21:03 alexpetros