Skip to content

FR: provide a "modern" ESM build without jsbi #155

@taralx

Description

@taralx

There's a babel plug-in for it, but it would be nice to have a ready-to-import version.

Activity

12wrigja

12wrigja commented on May 12, 2022

@12wrigja
Contributor

#138 (comment) seems related.

For your use-case, are you planning on using this polyfill:

  • only within applications (that don't themselves become NPM packages) and can made the decision whether they need JSBI
  • only within an ecosystem of packages where native BigInt is considered available on the platform?

Are you aware of any other packages that have this sort of a problem and how they went about solving it? I'm not opposed to having a solution, but I'd prefer not to create a bifurcation in the ecosystem where there are some packages using this dependency assuming that native BigInt is available only to find that someone who wants to depend on those needs JSBI.

Would it work for your use-case to have JSBI defer to native BigInt if available, but still pay the code-size cost of JSBI itself? This used to be a feature in JSBI but was removed.

taralx

taralx commented on May 12, 2022

@taralx
Author

I'm using it on browser, where we expect all users to have bigint (we need newer features anyway). Having it defer would be ok, but we're trying to keep download sizes down as well, preferably without introducing an additional transpile step.

taralx

taralx commented on May 12, 2022

@taralx
Author

If you prefer not to create a third output (.bigint.mjs), then what about just applying this to the ESM output? Anyone who is worried about older platforms like that is going to be using CJS anyway.

12wrigja

12wrigja commented on May 12, 2022

@12wrigja
Contributor

I'd probably lean towards making more outputs that are listed as conditional exports (https://nodejs.org/api/packages.html#conditional-exports) and could be imported like so:

import {Temporal} from '@js-temporal/polyfill/bigint';

Or some such.

I don't want to tie this to the module system used as it can be quite surprising which tools chose to use what thing we specify in package.json (see #29 for example).

12wrigja

12wrigja commented on May 12, 2022

@12wrigja
Contributor

Though I think this strategy will lead to weird bifurcation issues within the ecosystem and likely weird issues if both versions are in use at once (besides the expected doubled code-size).

12wrigja

12wrigja commented on May 12, 2022

@12wrigja
Contributor

trying to keep download sizes down as well, preferably without introducing an additional transpile step.

To be clear: have you tried the Babel plugin and does it meet your needs besides having another build step?

taralx

taralx commented on May 12, 2022

@taralx
Author

I haven't tried it but it almost certainly works. It's just that right now we don't have a transpile requirement, and I was hoping to keep it that way. 🙂

12wrigja

12wrigja commented on May 12, 2022

@12wrigja
Contributor

Would you mind describing your current dev & prod build setups in more detail? I'd like to understand why adding a transpilation step here is something you want to avoid. I can generally understand the desire to have fewer tools/processes in place, but any general solution to the bifurcation problem I presented above likely requires ecosystem-wide tooling support. If your goal is to reduce download code-size then I'd have thought you would already have transpilation / minification in place for prod builds.

taralx

taralx commented on May 13, 2022

@taralx
Author

Right now it's all just direct <script> tags from unpkg. No build steps at all.

taralx

taralx commented on May 13, 2022

@taralx
Author

You're right, we're probably going to need to set up a build at some point. I was just thinking maybe others might want the same thing here. But I also understand the fragmentation / too many artifacts argument.

12wrigja

12wrigja commented on May 13, 2022

@12wrigja
Contributor

Thanks for your understanding. It's less about the number of artifacts and more about fragmentation / confusing problems stemming from using two copies of the Temporal source simultaneously.

That being said, this discussion is making me reconsider attempting upstream adjustments for JSBI to use native BigInt where available so that whilst code-size might suffer more the runtime performance should improve for most users.

jimmywarting

jimmywarting commented on Jun 2, 2022

@jimmywarting

👍 would also want a scaled down version. don't care about IE anymore. all the new browser have auto updates and have had BigInt for a while now.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt#browser_compatibility

12wrigja

12wrigja commented on Jun 2, 2022

@12wrigja
Contributor

webpack/webpack#15903

I've filed this issue against Webpack to consider what it would take to have support in bundler tools for the sorts of conditions we would need to make this "automatic".

If we generated a build that only ever uses native bigint and referenced it in package.json using a custom condition, would that be enough? I'm concerned that won't be compatible with the various build tools that people use, and that configuring it would be just as difficult as installing and using the JSBI Babel plugin).

If something like this ends up working, perhaps we can flip the defaults (so by default users use a build that uses native bigints, and you have to opt in to using JSBI if your build needs it).

taralx

taralx commented on Jun 3, 2022

@taralx
Author

That's a great idea, but probably needs to be up a level at the package manager, i.e. npm/yarn/etc. rather than at the bundler level.

13 remaining items

jimmywarting

jimmywarting commented on Nov 22, 2023

@jimmywarting

I have always been a bit against the way package.json can magically change the import behaviour. i think package.json was a misstake from begin with. conditional import (in javascript) and only polyfill stuff when necessary is the way to go imo.

globalThis.DOMException || await import('https://jscdn.xyz/DOMException/polyfill.js')

I always try to create solution that works in a way such that if you had no information about a package.json, what runtime you are using or how any of the new tomorrow bundler will work and behave (cuz they might not take any consideration into any overrides) or knowing what target you are building for

Try to think of it like if deno wanted to do a http-import and did not have any support for bigint or any package.json information.

rjgotten

rjgotten commented on Nov 22, 2023

@rjgotten

@jimmywarting
BigInt can't be polyfilled because it is in part a language feature, and not an API.
It has problems with fallbacks being transpiled in as well, because essentially any piece of math no matter how trivial might at one point need to operate on a BigInt.

This is why solutions like JSBI took the approach that you have to author your code itself with the bespoke syntax of the fallback library; and then you have a transpiler plugin to recognize that library-specific syntax and pull it back out.

The discussion here is about the fact that not everyone has access to a transpiler in their specific setup. (Or has access to configure the transpiler. See for instance the situation with create-react-app and the need to 'eject' the configuration.)

It's about recognizing that there is value in supplying a ready-to-go distribution with JSBI already removed.
And about finding a way to do that.

jimmywarting

jimmywarting commented on Nov 22, 2023

@jimmywarting

i didn't try to make my comment specific to just JSBI and bigints.
i only wanted touch the thing with package.json

if it's the case that BigInt can't be polyfilled then it should do:

temporal = globalThis.temporal || await import(typeof BigInt === 'undefined' ? './temporal-jsbi.js' : './temporal-bigint.js')

rather than relying on package.json overrides. Some day react-native might have support for bigint. and it is beter to do feature detection instead.

rjgotten

rjgotten commented on Nov 22, 2023

@rjgotten

That will not work, for the very simple reason that import expressions are asynchronous and a poison pill.
It means any code using Temporal suddenly can only access Temporal from an async context.
Total no-go.

lionel-rowe

lionel-rowe commented on Dec 11, 2023

@lionel-rowe

That will not work, for the very simple reason that import expressions are asynchronous and a poison pill. It means any code using Temporal suddenly can only access Temporal from an async context. Total no-go.

Not in ESM contexts. As long as the await is at the top level and that module is imported at the app's entrypoint before any other imports, it won't cause problems.

// sync-export.mjs
export const resolved = 1
export const globalVar = 2

// async-export.mjs
export const { resolved, globalVar } = await import('./sync-export.mjs')
globalThis.globalVar = globalVar

// sync-import.mjs
import { resolved } from './async-export.mjs'
console.log(resolved) // 1
console.log(globalThis.globalVar) // 2

v8.dev's Top-level await article explicitly lists dependency fallbacks as a use case:

let jQuery;
try {
  jQuery = await import('https://cdn-a.example.com/jQuery');
} catch {
  jQuery = await import('https://cdn-b.example.com/jQuery');
}
rjgotten

rjgotten commented on Dec 11, 2023

@rjgotten

Not in ESM contexts.

Which means the requirement placed on developers shifts from "you have to use a toolchain that involves Babel and can be configured to transpile JSBI out" to "you have to use a toolchain that understands top-level awaited modules".

In practice that means you're shifting from "you need to use Webpack" to "you need to use a very recent version of Webpack" which, to say, does not improve matters. It's rather a case of 1 step forward, 2 steps back wrt ease-of-use.

The best way is still the package.json override, because that one is centered on features integral to Yarn and NPM; either of which you HAVE to be using anyway if you're installing the polyfill offered in its packaged format.

lionel-rowe

lionel-rowe commented on Dec 11, 2023

@lionel-rowe

The best way is still the package.json override, because that one is centered on features integral to Yarn and NPM; either of which you HAVE to be using anyway if you're installing the polyfill offered in its packaged format.

I'm using Deno, importing via an esm.sh URL (same approach also works natively in all modern browsers). No build tools, no package managers, no package.json.

LinusU

LinusU commented on Feb 12, 2024

@LinusU

It makes sense to me that the default published build for this project does not use JSBI.

Nice! I think that this is a very welcomed change, since basically every environment supports BigInt natively.

According to caniuse:

Since September 2020, this feature works across the latest devices and major browser versions (Learn more about Baseline)

I believe that it's only Internet Explorer 11 that doesn't support it, which is end-of-life as of 14 Jun 2022.

However, the project source should continue to.

Im curious about the reasoning here, sorry if it's already specified elsewhere in the project, I had a search but couldn't find anything. Is this only to support Internet Explorer, or is there something else that I'm missing?

12wrigja

12wrigja commented on Feb 12, 2024

@12wrigja
Contributor

Is this only to support Internet Explorer

Correct - we want to provide back-compat support for projects that need it, even if it requires more complicated project setup on their end. If we swapped to using native bigint in source directly it would be very difficult to "un-do" that locally in a project.

That being said, we don't currently have CI testing on IE11 so I can't confidently say the current implementation even works in IE11 even with transpilation to ES5.

While this is something I want to see done, I'm not sure I have the bandwidth to work on it (my day job has shifted priorities, and helping to maintain this project isn't as high on the to-do list as it was previously). If anyone here is interested in contributing a PR to see it happen I would be happy to review it.

espretto

espretto commented on May 7, 2024

@espretto

Hello 👋
it seems to me the browser build should rely on native BigInt and for back-compat support a separate build should be introduced. Projects that need it can always override their bundler's dependency resolution for specific packages (commonly using "aliases"):

rjgotten

rjgotten commented on May 7, 2024

@rjgotten

The best way is still the package.json override, because that one is centered on features integral to Yarn and NPM; either of which you HAVE to be using anyway if you're installing the polyfill offered in its packaged format.

I'm using Deno, importing via an esm.sh URL (same approach also works natively in all modern browsers). No build tools, no package managers, no package.json.

esm.sh processes NPM packages and uses ESBuild under the hood for transpilation. So you actually ARE using a build tool, a package manager and a package.json file. Albeit at a distance.

That said; problem is where? If you're using esm.sh to serve out modules - then you'll have native BigInt support, which would be the default configuration for the package. Which wouldn't need any overrides...

lionel-rowe

lionel-rowe commented on May 7, 2024

@lionel-rowe

That said; problem is where? If you're using esm.sh to serve out modules - then you'll have native BigInt support, which would be the default configuration for the package. Which wouldn't need any overrides...

I'm no longer using this polyfill, I switched to fullcalendar/temporal-polyfill. But the esm.sh build definitely includes jsbi:

/* esm.sh - @js-temporal/polyfill@0.4.4 */
import "/v135/jsbi@4.3.0/es2022/jsbi.mjs";
export * from "/v135/@js-temporal/polyfill@0.4.4/es2022/polyfill.mjs";
rjgotten

rjgotten commented on May 7, 2024

@rjgotten

That said; problem is where? If you're using esm.sh to serve out modules - then you'll have native BigInt support, which would be the default configuration for the package. Which wouldn't need any overrides...

I'm no longer using this polyfill, I switched to fullcalendar/temporal-polyfill. But the esm.sh build definitely includes jsbi:

/* esm.sh - @js-temporal/polyfill@0.4.4 */
import "/v135/jsbi@4.3.0/es2022/jsbi.mjs";
export * from "/v135/@js-temporal/polyfill@0.4.4/es2022/polyfill.mjs";

Afaict the idea proposed evolved to a point that there was some kind of consensus that the default configuration for the package should be to no longer use JSBI, and then require users that need the JSBI support to somehow override that and have the JSBI-version be served.

In other words- for your particular use case, that idea would work without issue. 😉

rinarakaki

rinarakaki commented on Jun 13, 2024

@rinarakaki

Any update?

mikemccaughan

mikemccaughan commented on Jul 16, 2025

@mikemccaughan

So, I've read this whole page, and the consensus appears to be to provide a build without JSBI. And yet, the build currently provided starts with import e from"jsbi"; which fails via dynamic import() in Edge/Chrome with Uncaught (in promise) TypeError: Failed to resolve module specifier "jsbi". Relative references must start with either "/", "./", or "../". It's a shame to hear that it's due to a requirement for working around bigint integration, something Chromium has had for a long time.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @LinusU@alippai@rjgotten@Pyrolistical@adidahiya

        Issue actions

          FR: provide a "modern" ESM build without jsbi · Issue #155 · js-temporal/temporal-polyfill