Skip to content
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

Remove joi to shrink module size #348

Merged
merged 3 commits into from
Sep 6, 2017
Merged

Conversation

chrisprice
Copy link
Contributor

As noted in #343 & #292 the specific version of joi is bloating the package size. However upgrading to the latest version would break ES5 compatibility.

This PR shrinks the module size from 3.12M to 0.25M by replacing joi with bespoke implementation using lodash helpers.

N.B. To keep the implementation as simple as possible, these changes mean that the validation error messages are marginally less helpful e.g. -

"expiresIn" must be a number versus "expiresIn" is not the correct type

This should also solve #334.

Copy link
Contributor

@ziluvatar ziluvatar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome work!! 👏 lot of people will like this 🎉

Some feedback:
a) Since the validation code is in our plate now, can you add tests to it?

b) We'll probably upgrade major version with this, because we are modifying joi ValidationError by Error (and messages even if no one should depend on them), it'd be nice to have proper error messages so we don't need to improve the impl later. I was thinking, maybe each schema item could have the validation function + validation error message, ie: iat: { validate: isNumber, errorMessage: '"iat" must be a number'}, that way you don't need to do smarter stuff but messages are meaningful.
About Expected object error, you could have a main object schemas: { payload, signOptions } and use the name of it when you call validate ie: validate('payload', ...) so you can raise a better message. These are just ideas to keep it simple but nicer for consumer, be free to implement it in different way.

Also, good idea adding the cost of modules, that could be part of a different PR, but it is fine for me to have it together.

sign.js Outdated
}
Object.keys(object)
.forEach(function(key) {
if (schema[key] == null) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

!schema[key] ?

@ziluvatar ziluvatar mentioned this pull request May 16, 2017
@chrisprice
Copy link
Contributor Author

Changes sound good, as soon as I get a chance I'll update the PR.

sign({algorithm: 'RS256'});
sign({algorithm: 'RS384'});
sign({algorithm: 'RS512'});
// not sure how to fix error - 'Could not find expected "seq"'
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wasn't sure how to get these tests to pass, I assume I'm missing some required configuration for the ES* algorithms.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You need to use different certificates for RS and ES. Probably it's that.
Take a look to: https://github.com/auth0/node-jsonwebtoken/blob/master/test/jwt.asymmetric_signing.tests.js#L13

@chrisprice
Copy link
Contributor Author

So it took a little longer than I expect to get back around to doing this but I think I've made all of the suggested changes.

sign({algorithm: 'RS256'});
sign({algorithm: 'RS384'});
sign({algorithm: 'RS512'});
// not sure how to fix error - 'Could not find expected "seq"'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You need to use different certificates for RS and ES. Probably it's that.
Take a look to: https://github.com/auth0/node-jsonwebtoken/blob/master/test/jwt.asymmetric_signing.tests.js#L13

@@ -12,11 +12,4 @@ describe('iat', function () {
expect(result.exp).to.be.closeTo(iat + expiresIn, 0.2);
});


it('should throw if iat is not a number', function () {
Copy link
Contributor

@ziluvatar ziluvatar Aug 24, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do you remove it? is it because with this PR it is tested in the schema test? (if so, I'm ok with that)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, that's correct.

Results before any changes

┌─────────────┬────────────┬───────┐
│ name        │ children   │ size  │
├─────────────┼────────────┼───────┤
│ joi         │ 4          │ 3.12M │ <--!!!
├─────────────┼────────────┼───────┤
│ jws         │ 5          │ 0.18M │
├─────────────┼────────────┼───────┤
│ lodash.once │ 0          │ 0.01M │
├─────────────┼────────────┼───────┤
│ ms          │ 0          │ 0.01M │
├─────────────┼────────────┼───────┤
│ xtend       │ 0          │ 0.00M │
├─────────────┼────────────┼───────┤
│ 5 modules   │ 9 children │ 3.32M │
└─────────────┴────────────┴───────┘
Dramatically reduces the module size without breaking ES5 compatability -

┌──────────────────────┬────────────┬───────┐
│ name                 │ children   │ size  │
├──────────────────────┼────────────┼───────┤
│ jws                  │ 5          │ 0.18M │
├──────────────────────┼────────────┼───────┤
│ lodash.includes      │ 0          │ 0.02M │
├──────────────────────┼────────────┼───────┤
│ lodash.once          │ 0          │ 0.01M │
├──────────────────────┼────────────┼───────┤
│ lodash.isinteger     │ 0          │ 0.01M │
├──────────────────────┼────────────┼───────┤
│ ms                   │ 0          │ 0.01M │
├──────────────────────┼────────────┼───────┤
│ lodash.isplainobject │ 0          │ 0.01M │
├──────────────────────┼────────────┼───────┤
│ xtend                │ 0          │ 0.00M │
├──────────────────────┼────────────┼───────┤
│ lodash.isstring      │ 0          │ 0.00M │
├──────────────────────┼────────────┼───────┤
│ lodash.isboolean     │ 0          │ 0.00M │
├──────────────────────┼────────────┼───────┤
│ lodash.isnumber      │ 0          │ 0.00M │
├──────────────────────┼────────────┼───────┤
│ lodash.isarray       │ 0          │ 0.00M │
├──────────────────────┼────────────┼───────┤
│ 11 modules           │ 5 children │ 0.25M │
└──────────────────────┴────────────┴───────┘
@chrisprice
Copy link
Contributor Author

Thanks for the pointer on ECDSA signing, I've updated the tests to use the other key where appropriate.

Copy link
Contributor

@ziluvatar ziluvatar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome, we have our gold PR for the major update. I'll try to find time this week or next week to merge all wanted PRs for next major, v8 without JOI is coming... 👏

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

Successfully merging this pull request may close these issues.

2 participants