-
Notifications
You must be signed in to change notification settings - Fork 339
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Ensure types are bundled and correctly linked #174
Conversation
@remcohaszing I took your suggestion from #169 (comment), and used the Are the types wrong? CLI to verify the package: I'll see if I can introduce this as part of the build process in a subsequent PR, for now I wanted to keep this one lean and to the point. In the meantime, can I ask you to take a look at the changes here and let me know if this also matches your expectations? |
"type": "module", | ||
"exports": { | ||
".": { | ||
"require": "./build/cjs/jwt-decode.js", | ||
"import": "./build/esm/jwt-decode.js", | ||
"types": "./build/typings/index.d.ts" | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've moved this up next to the main
and module
definitions, so that all the paths that export stuff are in the same place.
This helps, but the CJS types are still wrong (ATTW is nice, but not yet perfect). They should not define declare function jwtDecode(/* … */) // …
declare namespace jwtDecode {
class InvalidTokenError extends Error {
// …
}
}
export = jwtDecode The simplest solution is to simply not use default exports, but named exports. Also I believe |
I thought so at first as well, but it seems that if I set the {
"files": [
"./lib/index.ts"
],
"compilerOptions": {
"target": "ES5",
"module": "CommonJS",
"strict": true,
"declaration": true,
"emitDeclarationOnly": true,
"declarationDir": "./typings",
}
} It seems like this is just how the TypeScript compiler wants to emit types for the CommonJS? Perhaps I am missing something, can you manage to get the output you expect with
Totally agree, but that would be a breaking change. And @frederikprijck has made it clear that is not an option for him.
It could, but we can't do this because:
My personal opinion aligns with you, which would be:
But again, that would be a breaking change, which I don't believe is an option. |
Hey, i want to mention that introducing a breaking change for this is perfectly fine, but i would avoid it if not necessary. But it looks like it will be neccesary and i have no objections, sorry if it may have sounded like that before. Personally, i prefer to avoid any default export myself, so i am happy to do so inhere if it aids with our setup. What i do not want is drop commonjs, for reasons mentioned before. Regarding tsup, all our JavaScript SDKs (we have alot) are using rollup, so for several reasons i believe we should stick to it, unless there is a clear reason we can not. So let's go with dropping default exports, but keep commonjs and rollup around. |
Hmm @frederikprijck why is Why not use the |
@cristobal can you elaborate on what's going wrong, probably outside of this PR? Not all tooling relies on exports, so we might need to support both. |
@frederikprijck did not mean to imply you were holding this up or anything, just that it was a concern for backwards compatibility. Sorry if it came across as such. Some maintainers can be a bit more strict about backwards compatibility 😛
Yeah that should not be an issue, still complicates things slightly, but not as much if we decide to drop the default export. What is your take on the UMD module though? I'd personally prefer to get rid of it, but I understand if you feel differently.
There is a couple of reasons I can think of, but the main one would be that it already does everything we need (except for UMD), and that pretty much makes Rollup obsolete. It also follows all the best practices and could replace the config we have with a single line script entry in the package. If you like, I can create a draft PR to show you what this could look like under ideal circumstances. Just to get an idea.
Got it, I'll make a separate PR for that so we can land this quickly and without to many files to review. |
We already do, and this has not changed in this PR. I've just moved the code around a little. And as @frederikprijck mentioned, there is tooling out there that does not yet understand the |
I opened a PR (#175 ) to avoid default exports.
How would we support people currently relying on the UMD bundle, mostly by including the script tag in their HTML file? |
This is what also rollup recommends, which is used for bundling here |
I'm not sure why you need to have an UMD bundle here, you can add it in the README that people relying on UMD can rather bundle it themselves or stick with the old version. |
Well, by supporting ESM we can support them. They can import it as they would other modules: <script type="module">
import { jwtDecode } from "/path-to-esm/jwt-decode.js";
const token = "eyJ0eXAiO.../// jwt token";
const decoded = jwtDecode(token);
</script> Or alternatively, if an import map is used, this would look the same as ESM and Node.js: <script type="module">
import { jwtDecode } from "jwt-decode";
</script> |
Again as you say by supporting esm we can support them, however there is no need for an UMD js file then? This is more of an Documentation issue rather than anything else, or am i missing something? |
@cristobal I recommend you read my comments in this thread, I am not advocating for UMD. |
@jonkoops my question about UMD was directed to @frederikprijck here. |
Ok, got confused there since you are quoting my post. |
I have a feeling you both have a strong reason to drop it, while i believe don't see the issue. If so, can you please open an issue so we can have a central place that elaborates on the issues with keeping it. Please refrain from any personal opinion about wether or not we should support it, but elaborate on the reasons we should drop it beyond personal preference. My opinion is to keep it, even if there are alternative paths for those users to migrate. I want to avoid unneccesarily breaking users beyond things that are needed, especially given this lib is used extensively. |
Yes. This is correct. This results in the following build output: exports.default = jwtDecode
Yes. TypeScript isn’t intended for dual publishing. It also can’t, because CJS and ESM are incompatible, especially default exports. To get proper output, you need both CJS and ESM source files. Named exports make it simpler though. Because now this: export function jwtDecode() {} can be compiled to: function jwtDecode() {}
exports.jwtDecode = jwtDecode The problem with Rollup and other third party TypeScript build tools is, they understand JavaScript, but not TypeScript. Aside from I doubt if people actually still use UMD. However, rollup could still be used to produce only the UMD bundle. |
I agree with @frederikprijck, let's move the UMD discussion to a separate issue. I think it's just cluttering up the discussion here. I've created #180 to continue this discussion. |
Sigh, dual packaging is like the gift bag of needles that never stops giving. Any idea how we can accomplish this without creating new source code? |
@remcohaszing I have not yet found a way to get the TypeScript compiler to emit correct types for CommonJS. Perhaps this is the best we can do for now. The types are already linked the same way for v3, and I have seen no complaints. Could be that the combination of CommonJS and TypeScript is just not that popular? Side-note: I've found a similar issue in Deno's DNT (denoland/dnt#327). |
The generated types are correct when using a named export. @frederikprijck mentioned this is ok in #174 (comment). |
I am not sure it is correct. When I rebase this PR on the work in #175, I am still getting ESM-style exports: export { InvalidTokenError, JwtDecodeOptions, JwtHeader, JwtPayload, jwtDecode }; |
This looks fine. The following CJS export style: exports.InvalidTokenError = InvalidTokenError;
exports.jwtDecode = jwtDecode; requires the following type definitions: export {
InvalidTokenError,
jwtDecode
} However, the following CJS exports style: module.exports = something; Requires the following type definitions: export = something; This is why named exports solve many ESM/CJS compatibility issues for dual publishing. |
@remcohaszing I'll take your word for it, but I was kind of expecting something like this: export = { jwtDecode }; Is there some kind of reference for this? I can't find anything in the TypeScript documentation. |
There is some documentation in https://www.typescriptlang.org/docs/handbook/modules.html and https://www.typescriptlang.org/docs/handbook/esm-node.html, but IMO the explanation isn’t great. This draft document explains a lot more in depth, but it’s a lot to read and not finished. Really the best thing you can do is fiddle with a simple project: // tsconfig.json
{
"compilerOptions": {
"declaration": true,
"module": "node16"
}
} // foo.cts
export interface Options {}
export function foo(options: Options) {} // bar.cts
declare namespace bar {
interface Options {}
}
function bar(options: bar.Options) {}
export = bar and then fiddle yourself. See what the output is when running |
@remcohaszing Yeah, I am getting the same. Let's consider this resolved then 👍 |
Just did a quick rebase so the changes from #175 are included, so I think this is good to go. @remcohaszing @frederikprijck would you take another look and let me know if things look good? |
@@ -17,8 +30,10 @@ | |||
"homepage": "https://github.com/auth0/jwt-decode#readme", | |||
"scripts": { | |||
"dev": "rollup --sourcemap --config --configPlugin typescript", | |||
"build": "rimraf build && rollup --sourcemap --config --configPlugin typescript --environment NODE_ENV:production", | |||
"postbuild": "echo '{\"type\": \"commonjs\"}'> build/cjs/package.json", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we no longer need this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now that we're using the .cjs
extension this should work without an additional package file.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the work here, this looks great.
Yes, this works great! Thanks! |
Thanks for getting this landed all! |
Ensures that emitted types are bundled into a single file, and that both ESM and CommonJS have their own type definition files linked. This is done by adding a new script to generate the types using
tsup
, which can bundle the types, unlike the TypeScript (see microsoft/TypeScript#4433).Closes #169