MasterKale / SimpleWebAuthn

WebAuthn, Simplified. A collection of TypeScript-first libraries for simpler WebAuthn integration. Supports modern browsers, Node, Deno, and more.
https://simplewebauthn.dev
MIT License
1.63k stars 137 forks source link

Fixed invalid format of ES modules that caused compiling issues for Vite #128

Closed skoshx closed 3 years ago

skoshx commented 3 years ago

This pull request fixes an issue where @simplewebauthn/browser cannot be imported, because it causes Vite to error because Vite doesnt look for the main:es2018, but instead looks for module, which it can't find.

akanass commented 3 years ago

Hi @skoshx thank you for your PR but this one can't work.

We can't use module entry because it will always override the main entry which is the default one for old browsers compatibility.

You have to indicate to your build system to take main:es2018 entry as it's explained in the README and all will work fine

akanass commented 3 years ago

@MasterKale we can't accept this one as already discussed together and what I have explained in my previous comment

skoshx commented 3 years ago

@akanass I'm not exactly sure what you mean… Nowadays almost every project uses some kind of bundler to bundle to JavaScript that runs on every browser that is needed, so why does the module entry change anything? Bundlers can just use that to bundle to ES modules if the developer doesn't care about older browsers, and transpile to older ES5 syntax, if old browsers need support?

Also, supporting old unused browsers shouldn't be that high on the list of priorities, yes?

akanass commented 3 years ago

@skoshx I agree with you but what you have to understand is that main entry should be normally for CJS files and module for ESM files or our bundle is both ESM modules in ES5 for the main entry and ES2018 for the main:ES2018 entry.

Bundler uses the order module then main when they take files from package.json so to support build systems which not allow the transpilation from E2018 to ES5 like Next.js by example, we can't use module else it will always be the ES2018 version taken instead of the ES5.

We already had a lot of discussion about it in this issue and we solve it like this.

To allow ES5 as main entry and allow users to use ES2018 you have to include the ES2018 version by yourself in your build system as it's explained here

akanass commented 3 years ago

@skoshx you can use this config override to solve your problem as it's explained inside vite config

skoshx commented 3 years ago

@akanass Build systems like Next.js, and Svelte (which doesn't transpile to ES5 by default) can all be configured to transpile to ES5, so I don't see the problem in having main and module fields the way every build system & bundler expects them to be?

akanass commented 3 years ago

@skoshx as explained in the issue linked in my previous comment, people don't want to add some plugins or configuration to do what the initial bundler does.

I give you the solution for vite in my previous comment and it's following what we decided with our package versions

module will always be taken before main so for a ES5 version it can't work and we have tested it a lot so trust us on what we did and we decided to do that.

You have a solution working well with vite config override.

MasterKale commented 3 years ago

Build systems like Next.js, and Svelte (which doesn't transpile to ES5 by default) can all be configured to transpile to ES5, so I don't see the problem in having main and module fields the way every build system & bundler expects them to be?

@skoshx The only difference between the two packages is which version of ES they're built for - "main" targets ES5 while "main:es2018" naturally targets ES2018. The bundle architecture isn't any different, though, and it feels like it'd cause confusion to simply rename the ES2018 file to .mjs and then assign it to "module" for what that implies about the package's internal structure.

akanass commented 3 years ago

@MasterKale renaming files with mjs isn't required because you don't put these files directly in a script tag with the module attribute but we use them with an import inside others files

All what we have is good and people have to use the mainFields override to take ES2018 entry as we have explained in the README and as it's explained in Vite config as well.

MasterKale commented 3 years ago

Thinking about this a bit more, @skoshx, your suggestion might make sense. Looking at the Rollup config for Browser the ES2018 bundle is in ESM format, which means it would work in a <script type="module">...

@akanass The main question for me is, why not use "module" for the ES2018 build? It's at least a recognizable "entrypoint" (not strictly defined for package.json, but seems to be becoming a de facto standard for ESM bundles), and if Create-React-App/Svelte/Vite/etc... look for "module" when importing then maybe it's not an issue?

akanass commented 3 years ago

@MasterKale first, .mjs files have to be called directly inside <script type="module"> and it's not what we are doing.

People import files in their own TS/JS files and then build their applications.

Second, as we discussed a lot of time, il we use module entry, main will NEVER be used. This will always be the ES2018 version that will be taken into account and not the ES5 version.

Applications that can not overload the entry point as we have had with Next.js, so will never take the ES5 version when they want to build it as @Moumouls wanted.

What we have is the right way to do trust me

akanass commented 3 years ago

module is only useful when the main version is in CJS and this is not our case and we have already discussed this in the previous issue.

We have two ESM version and ES5 is the main so we can't use module if we want that build system can take it

akanass commented 3 years ago

The last library I built is based on the same package format and everything works perfectly for everyone like here.

Do not want to look further than what we have already discussed and if you use the module entry then you will prevent people from using the ES5 version

skoshx commented 3 years ago

@akanass People don't care if they are usingES5 version or ESM version, they just want it to work seamlessly. Bundlers care if the code they are bundling is ES5 or ESM, and bundlers are designed to handle the module and main properties as needed, so if the program is bundled for ES5 -> Bundler will bundle the ES5 version (or use module, and transpile), and if the program is bundled to target modern Node/Browsers, bundlers will happily use the module entry.

I don't understand why not using ES5 is bad? Why can't we provide main and module, and let the bundlers decide which they use?

akanass commented 3 years ago

@skoshx bundler are always taken files in this order module -> main

So if people are targeting ES5 in their application and don't want to add plugins to transpile from ES2018 to ES5 and only use the standard configuration like it's done in Next.js so it won't work because if we put ES2018 in module entry then it will be this version used inside a ES5 application.

It's the problem we had in this issue and you can read it.

At the beginning I proposed to transpile from ES2018 to ES5 but @Moumouls didn't want to add babel plugins or whatever and we decided to make the ES5 version as the main one.

If we put ES2018 version in the module entry, the main version won't be used.

In Vite the mainFields are ['module', 'jsnext:main', 'jsnext'] by default as explained in the documentation and you can see, even if module is the first one, you can have custom entries and it's what we have in our bundle.

So, you just have to do a custom config file and declare ['main:es2018', 'module', 'jsnext:main', 'jsnext', 'main'] as mainFields and all will work for you and won't break other applications which don't want to add transpile plugins.

You can read the previous issue to understand all what I say and why we decided to do like this because as I said before I already proposed to do what you want but it can't work.

skoshx commented 3 years ago

@akanass Let me get this right, so because of one developer @Moumouls didn't want to add babel plugins to transform his code to support an OUTDATED LEGACY browser (IE11 support will be dropped in 2022 by Microsoft), you decided the best solution is to make ES5 code the default, and instead let all other developers get bundling errors when bundling using modern bundlers?

I'm sorry but this makes no sense whatsoever... Instead of @Moumouls upgrading to a more modern JS development stack, you change this repository to go back to the past, and default to using ES5 code?

akanass commented 3 years ago

@skoshx we decided to support old browsers because we still have a lot of people using IE11 unfortunately.

It's not related to a developer but to customers who are using applications and if they still are on IE11, this library should work to indicate to them that they can't use WebAuthn because of their old browsers and this library must be included in ES5 applications without breaking them.

That's why we decided to make ES5 as main version.

And you're not blocked in your build system because build system allows to override the mainFields so you can do it as explained in my previous comment.

Like this everybody is happy and we have explained in the README how to satisfy everyone.

skoshx commented 3 years ago

@akanass The global use of IE11 is 1% (according to caniuse.com), I wouldn't call that a lot of people. Also, I know that in some cases, IE11 support is needed, but bundlers take care of this problem, they create code that is usable in IE11, that doesn't mean that ES5 code should be the default.

Tell me this, what is the problem of adding a module entry to package.json? Developers (like @Moumouls ) can configure their build systems to build for ES5, while the majority of developers, who don't need to support legacy browsers, can simply npm install this library, and start using it, instead of getting build errors, and having to troubleshoot for hours (I spent this whole day troubleshooting why this library wouldn't work)

skoshx commented 3 years ago

@akanass And I know I can define resolve.mainFields in Vite, but I had to spend this whole day debugging because SimpleWebAuthn package couldn't get bundled, because of there being no module field. I don't want the same experience for other developers that start to use this project, and instantly get build errors.

I don't understand how it seems like a good solution to require all developers to change their bundler configs, when there is 2 lines that you can change (the changes i made) to make it work WITHOUT any changes in bundler configs.

MasterKale commented 3 years ago

Hey, what a passionate conversation this has become. Let's all take a breath for a few moments until I can respond to @skoshx's very valid questions.

akanass commented 3 years ago

@skoshx if you read the previous issue, you will understand why we did it like this because Next.js has a problem in its mainFields override system and it can't work.

And as I said a lot of time and if you really know how build systems are working, module always override main because he is declared first in mainFields so if we add module entry, only ES2018 version will be taken in all build system by default even if you want to build in ES5.

If you have a plugin to transpile it won't be a problem but applications which don't have this plugin will have problem.

So to fix it we did it like this.

And for your application, you just have to override mainFields as it's working for Vite because it's based on Rollup.

Several build systems thus works and several libraries proposes these customs entries.

You just have to override your config and you're done and your application will work with this library.

akanass commented 3 years ago

@MasterKale, I do not understand the problem because we have worked for several times on a solution and the one we have is quite correct.

We offer support for older as new browsers and there is no problem running its build with config overload.

We are in good standing with the standards to support all browsers and build system.

Just a small effort to overload the config and this discussion will be closed

akanass commented 3 years ago

@akanass And I know I can define resolve.mainFields in Vite, but I had to spend this whole day debugging because SimpleWebAuthn package couldn't get bundled, because of there being no module field. I don't want the same experience for other developers that start to use this project, and instantly get build errors.

@skoshx If you read the documentation you would not have been blocked because everything is explained.

I'm sorry but the problem does not come from the library as the documentation explains everything and it is the basis for the development of reading a documentation before using it.

I don't understand how it seems like a good solution to require all developers to change their bundler configs, when there is 2 lines that you can change (the changes i made) to make it work WITHOUT any changes in bundler configs.

What you say is not true because the change of mainFields is much easier and fast than adding plugin to transpile the code.

So again, whether for an ES5 version or an ES2018, the config will have to be changed so the easiest solution is the modification of the mainFields

As it works for everyone and without real complication when the documentation is read.

Moumouls commented 3 years ago

Due to the nature of this lib, it's better to have a failing compilation than a failing app on production because depending of your audience, the 1% could be 10% (if you work with some no tech companies). And 1% of 10 000 users (pretty small), is already 100 users and 100 users with a not understandable white screen failing app (since the code is auto loaded mostly on login page) is already huge and we should avoid surprises for all our friendly customer support teams. πŸ™‚

As @akanass said you seems to be really experienced on bundlers so in your case your are safe and aware of risks. (but it's not the case of many developers that simply run some NextJS or Vu/Angular.... ready to run projects).

Here my point of view, and i totally understand your point of view @skoshx πŸ™‚

MasterKale commented 3 years ago

@skoshx Have you had a chance to review the (lengthy) discussion on ES5 support in Issue #114? There's a ton of context in there that might help make some sense of @akanass' vehement support of the current solution. I'm offering this up as something that might help make sense of how this project got where it was with the ES5 bundle being the default.

tl;dr: supportsWebAuthn() didn't actually work in older browsers because it wasn't transpiled down far enough, which kinda defeated its purpose. My goal was to find a way to offer a single Browser bundle that traded a bit of size for support across even older browsers to keep things "simple".

I see that this may have backfired - in trying to address problems with one framework we've created problems with others. Of course the ideal end state is a browser package that can be bundled regardless of the framework du jour.

an OUTDATED LEGACY browser (IE11 support will be dropped in 2022 by Microsoft)

I, as much as any front end developer, eagerly await the day I no longer have to think about Internet Explorer compatibility. The truth is, though, many enterprises and governmental bodies are slow to upgrade and so IE11 will continue to persist even after Microsoft's official sunset date. Therefore I believe it's worth it to continue to allow RP developers to use such a function as supportsWebAuthn() in their code and not have to worry about the code breaking in legacy browsers like IE11 (where of course WebAuthn isn't supported).

I don't want the same experience for other developers that start to use this project, and instantly get build errors.

@skoshx I get where you're coming from, this project has "simple" in the name and I don't intentionally approve anything that I know makes use of these libraries more difficult. Can you help me understand how Vite fails to work with the "main" bundle? Is it not seeing it at all because it's only looking for "module"? Are you able to prepare a minimal reproduction of a Vite project that can't import WebAuthn so I can see your setup and factor that into browser's build process?

akanass commented 3 years ago

@MasterKale as I explained in a previous comment, Vite is only taken ['module', 'jsnext:main', 'jsnext'] fields as we can see in the documentation

But it can be overrided so it's not a problem.

And we don't introduce problem with another framework because in this one you can do your own mainFields

MasterKale commented 3 years ago

@akanass I understand that's the case, we were all there for Issue #114. What I'm trying to understand is why @skoshx had such a bad experience. Was the documentation insufficient? Not obvious? Is ES5 as default truly a bad default? Just like we considered @Moumouls' use case, I want us to consider @skoshx use case as well. Right now I haven't read anything compelling me to change the bundles yet, but I don't feel like I've fully understood the implied issue that @skoshx' experiences represent.

I'm hoping we haven't scared off skoshx because I don't think we've fully heard them out.

akanass commented 3 years ago

@MasterKale I have totally heard him and I totally agree with him because his solution it's what I've proposed at the beginning in #114

And if he had bad moment with his build I am sorry but if he read the documentation on Vite and this one as well, all should be fine in my point of view.

It's not the first time I built library and I gave to you an example of my last one which have the same build system.

So having ES5 version like this it's the only way to support old browsers without having a huge change in build config because as I already said, changing mainFields is easier to do than adding transpilation plugins and config

skoshx commented 3 years ago

@MasterKale Yes, I've read the issue, and I still don't understand why it wouldn't work the way it currently is, with one build for CJS, and one for ES modules, and then defining main & module respectively? Most web projects (SvelteKit & Next.js are big ones) already have defined build pipelines, that more or less easily compile / build to ES5.

Also, reproduction of this problem is difficult, since it arises when you have a project that depends on @simplewebauthn/browser. Let's say there is a component that would add support for logging in using Web Authentication API, that component would import from @simplewebauthn/browser, then anyone adding that component would get build errors, and finding the solution is quite hard, since the error messages are not helpful. (Something along the lines of exports is not defined in [filename])

I imagine many projects depending on this library, since this is very well written & tested, so this could actually present a lot of problems in the future.

akanass commented 3 years ago

@skoshx it won't work because all is ESM even for ES5 version.

CJS is mainly used in node and in browser application we are using ESM.

So for all what I have explained before module entry can't be used and no problem exists if the documentation is read because we explained it

skoshx commented 3 years ago

@akanass Here is a snippet of the es5 dist:

Object.defineProperty(exports, '__esModule', { value: true });

var tslib = require('tslib');

function utf8StringToBuffer(value) {
    return new TextEncoder().encode(value);
}

It has exports & require(), how is this not CommonJS? I think require() is synonymous with CommonJS, so I don't understand what you mean with that this isn't CJS?

And you keep repeating "We have explained how to fix this problem", but you don't realise, that we could just get rid of the problem all together?

Anyways, this is extremely tiring, trying to improve SimpleWebauthn and you keep saying "You don't need to improve it, since there is already a fix for the problem"... All I'm trying to do is get rid of the problem alltogether.

@MasterKale I respect and appreciate the work you have done in this repository to make Web Authentication super easy, but I simply can't require that EVERYONE that uses my project to add something to their configurations. I can make a reproduction repo, if you would be open to investigating this further. And if not, I understand perfectly, and would just convert this to ESM modules in my fork.

Furthermore, the shift towards ES modules, newer JavaScript versions & newer module bundler and developer tools is something that benefits open source and JavaScript in general greatly, I don't think the right approach is to have an "legacy browser first" approach. I think it is supposed to be easier to support modern browsers & harder to support legacy browsers (thus pushing towards newer technologies) instead of prioritising legacy browsers, and demanding that everyone make changes in their configs, to adapt to legacy browsers.

Also, I would like to see a small reproduction of a scenario, where this current pull request doesn't work (doesn't compile to ES5), iff that would be possible (although, frankly I don't think it is) then I could understand get a deeper understanding of this issue. Thanks a lot @akanass & @MasterKale for taking your time to discuss this, I really appreciate it!

akanass commented 3 years ago

@skoshx You're right it's a CJS for ES5 version.

Now if you want module entry so @MasterKale has to do it and test if it's working with Next.js as well to not break what was did before.

And I am here to help as you and I am not against you.

I totally understand you and as I always said I did that before and it was my main idea before you talk about it.

But we did some tests and it didn't work.

So now, if you can do something with your idea and make sure ES2018 is naturally taken when we want modern browser and ES5 is taken when we want old browser support so all will be perfect and I encourage you to do it.

But you have to take in consideration that it's not only your own concern which is important but all use cases.

At the end @MasterKale will take the decision.

By the way we should change CJS to ESM even for ES5 version because it's what I did for my own library and all is working.

So I am waiting for your implementation to learn new things on how to have a nice bundle supporting all use cases

skoshx commented 3 years ago

@MasterKale @akanass Here is proof that this PR works completely fine with Next.js.

To test it, navigate to nextjs-blog, run npm install, then npm run build, followed by npm run start, then open Internet Explorer in localhost:3000, open console, and it prints output "false" from supportsWebauthn().

Some takeaways:

  1. @akanass You said that it uses module over main, it doesn't. Like I said, Next.js uses the main (CJS) version, because it creates a build that supports IE11 (I didn't need to add any configurations, it works out of the box, so I don't know what @Moumouls was talking about when he said he needed to add some babel things?)
  2. Module just makes it easier to work with most modern frameworks, since all modern frameworks just take care of everything (which makes them so awesome)

I really hope this shows that there are NO negative downsides of using module entry, and that this gets merged.

MasterKale commented 3 years ago

@akanass I don't see a problem with specifying a value for "module" in package.json since modern JS framework build pipelines have standardized on it. @skoshx is right, it's silly that we're a package that requires a build config tweak to work with things like SvelteKit/etc...

@skoshx, is your actual issue just that we don't define "module"? Does it have to be the ES2018 build? What if we defined the ES5 bundle for both "main" and "module", with "main:es2018" as an optional no-legacy-browsers bundle that you can then opt into to trim a tiny bit of fat from your production build (because that bundle doesn't include 4KBs of polyfills πŸ˜„)

skoshx commented 3 years ago

@MasterKale Using the es5 bundle for module doesn't work, since it has exports keyword, which gives an error when bundling (since exports is not ES syntax, its CJS syntax). This is actually where my initial error stemmed from, the bundler was using the es5 code, since it couldn't find any module entry, and because the es5 code has exports keyword, it causes an error in bundling.

MasterKale commented 3 years ago

@MasterKale Using the es5 bundle for module doesn't work, since it has exports keyword, which gives an error when bundling (since exports is not ES syntax, its CJS syntax)

Ah yeah, that makes sense πŸ€¦β€β™‚οΈ And withformat: 'cjs' set on the ES5 build in the Rollup config it's definitely coming out as a CommonJS module.

I'm compelled by @skoshx's example - it's a Nextjs project that transpiles down to ES5 (why, though? I couldn't see an obvious reason for it compiling down so low, does Nextjs do that by default?) even after importing the ES2018 build as "module". @Moumouls is there some reason why your Nextjs project can't do this?

skoshx commented 3 years ago

@MasterKale Next.js compiles down to ES5 by default actually, I think the point of doing this is also to have out of the box support for legacy browsers (obviously you can choose to target newer browsers by changing babel options). I have to say, I'm not surprised that this PR works for Next.js out of the box, considering that frameworks & bundlers are nowadays so advanced, and know how to handle main & module entries.

akanass commented 3 years ago

@MasterKale if all application can compile ES2018 version in ES5 natively so we only need this version and delete the ES5.

We tried it in the past with @Moumouls application but it didn't work so I don't know why.

Now if we can have a running application in ES5 with the ES2018 code it's perfect.

If we are keeping the the ES5 version it should be a ESM as well and we have to change the rollup config as I did in my own library.

skoshx commented 3 years ago

@akanass If you delete the "main" entry (ES5 version), that might break Next.js out of the box compatibility (since Next.js uses the ES5 version, not the ES2018 version), so you really shouldn't do it.

akanass commented 3 years ago

@skoshx what I meant it was to put ES2018 as main version and only have this one because we just need ESM module as Next.js can transpile natively to ES5 as you said.

Maybe I am wrong.

MasterKale commented 3 years ago

I'm going to sleep on this and come to a decision tomorrow.

That said after some testing of my own I'm leaning towards accepting the PR. With @skoshx' proposed fix I was successful in getting supportsWebauthn() to execute in IE10 in a Next.js site, IE10 in a Create-React-App site, and ES2018 in a SvelteKit site (I have very little experience with Svelte despite a great interest in it; I got a built page to render in IE11 but JS failed to load and I didn't want to start down the rabbit hole of trying to get polyfills working). I'm convinced it's the way to go.

Thinking about other aspects of the codebase that will need to be updated assuming this gets accepted:

And actually that's it. The ES5 UMD build remains, the ES5 CJS build remains as "main"...anything I'm missing?

skoshx commented 3 years ago

@MasterKale

Yes, SvelteKit by default bundles to ES6, to make the bundling process easier (among other benefits), and getting SvelteKit to produce IE11 compatible output is actually kind of tricky, since the Svelte compiler accepts only ES6 code if i recall correctly. But I still strongly recommend Svelte. I have no requirements of supporting IE11, so I'm building for production with SvelteKit, and it's heaven. Everything becomes so easy and straight-forward. Defenitely one of my favorite open-source projects.

Other than that, I think that's it! Regarding the require('tslib'); line in the ES5 build, what is its purpose? It was the only thing that caused a bit of problems for me (I got errors saying 'cannot resolve module tslib' even though it was installed).

MasterKale commented 3 years ago

Other than that, I think that's it! Regarding the require('tslib'); line in the ES5 build, what is its purpose? It was the only thing that caused a bit of problems for me (I got errors saying 'cannot resolve module tslib' even though it was installed).

The tslib dependency includes some runtime helper methods that the ES5 bundle needs in order to be able to execute in those older environments. It's been long enough I'm not really sure why that doesn't end up getting compiled into the ES5 bundle - it's weird for the browser package to require that as an additional dependency. I'll take another look into that afterwards and see if I can get rid of that step too.

skoshx commented 3 years ago

@MasterKale Ok, In my reproduction repository, I commented out the require('tslib'); line, and it compiled & ran perfectly in IE11, so it might be worth checking if its actually unnecessary :)

akanass commented 3 years ago

tslib is required because some pieces of code are not compatible with ES5.

To have a lighter file, this library is externalized as recommended in order to avoid code redundancy and version conflict during an application bundle.

This is the knowledge base for creating libraries compatible with ES5

akanass commented 3 years ago

And it's not because of tslib that the project doesn't compile but because of require

The project is using ESM so CJS cannot be included without using commonjs plugin.

Or as I suggested yesterday, ES5 version should be also in ESM and all will work without additional plugin.

Again this is a basic understanding of how build systems work and the types of files that should be included in them.

skoshx commented 3 years ago

@akanass Yes, I'm just thinking if require('tslib'); is unnecessary. In my experiments, I removed tslib, and everything worked fine, even in IE11.

akanass commented 3 years ago

If you have understood my last two messages but also the usefulness and why this library is there then you will see that it is not me who added it but that it is there because it is needed seen the code used and generated

MasterKale commented 3 years ago

@skoshx Thank you for forcing me to look back at the current build options for @simplewebauthn/browser, and for sticking around to help me better understand your use case. This PR will definitely make this package work like any other without having to jump through any hoops and install extra dependencies.

@akanass Yes, I'm just thinking if require('tslib'); is unnecessary. In my experiments, I removed tslib, and everything worked fine, even in IE11.

The more I think about the role of tslib in the browser package the more I dislike it. Packages shouldn't prescribe how code is transpiled down to earlier environments, but browser effectively does this by saying, "you have to use TypeScript's ES5 runtime helpers because we pre-built to ES5 with TS and it expects it to be available." Of course it's the responsibility of the build framework (NextJS, CRA, SvelteKit, etc...) to figure out how to get dependencies transpiled down to the target environment.

@akanass If you delete the "main" entry (ES5 version), that might break Next.js out of the box compatibility (since Next.js uses the ES5 version, not the ES2018 version), so you really shouldn't do it.

@skoshx what I meant it was to put ES2018 as main version and only have this one because we just need ESM module as Next.js can transpile natively to ES5 as you said.

Maybe I am wrong.

So here's something interesting: I tested NextJS, Create-React-App, and ParcelJS (parcel@next, a.k.a. Parcel 2.0) with @skoshx's proposed fix and all three pulled in the ES2018 bundle and transpiled it down to ES5, logging the console.log("Hello from ES2018"); I injected into the .mjs file to confirm which bundle it was loading. In my mind this means it should be fine to update"main" to point to the ES2018 bundle as well and forget about offering ES5 builds in any flavor other than a UMD bundle for use via unpkg or some other non-JS web framework (as I'd like to be able to use it in future Django projects in a vanilla HTML+JS environment πŸ˜‡)

akanass commented 3 years ago

@MasterKale

The more I think about the role of tslib in the browser package the more I dislike it. Packages shouldn't prescribe how code is transpiled down to earlier environments, but browser effectively does this by saying, "you have to use TypeScript's ES5 runtime helpers because we pre-built to ES5 with TS and it expects it to be available." Of course it's the responsibility of the build framework (NextJS, CRA, SvelteKit, etc...) to figure out how to get dependencies transpiled down to the target environment.

As I said before, tslib is required to run the ES5 version and the only solution not to have it in an external library is to include it in the code.

But if you do that, we will no longer have the actual tree checking when compiling applications, which will lead to code duplication and therefore heavier files.

If tslib is in an external library as it is currently, it is precisely to let the build systems do their work and therefore include the correct version of tslib present in the application and only what is needed.

This will therefore avoid redundancy of code and we will have a lighter application in the end.

Now, to stop having require, the ES5 version should also be in ESM and not in CJS.

Can you test in your tests projects as you did before, if it takes the ES5 version even if it is in ESM ?

You just have to change this line in the rollup file and put esm instead of cjs.

If it works, it will mean that even the ES5 version will be in ESM and there will be no more problems with the import of tslib which will no longer be done in require but in import

I did this on my fork and the result is this for tslib:

import { __values, __assign, __awaiter, __generator } from 'tslib';

The ESM solution even for the ES5 version would be preferable because the code would be compatible without adding a commonjs plugin.

You just have to see in your tests if this main version is taken when you create an application in ES5 and the code is no longer in CJS.

In my mind this means it should be fine to update "main" to point to the ES2018 bundle as well and forget about offering ES5 builds in any flavor other than a UMD bundle for use via unpkg or some other non-JS web framework

In my mind it would also be good to have only one version in ES2018 and that's what we had at the beginning but for some reason the builds of @Moumouls did not work because it does not compile in ES5.

So if we put the ES2018 version in the main you would have to test if you have the compilation in ES5 which is done and therefore that everything works perfectly with your test projects.

We must not only have the compilation working but also the use of functionalities which must be compatible in ES2018 and ES5.

If this is the case then only one version will be necessary and it will be necessary to see why @Moumouls could not compile if you do it correctly and that it works.