Skip to content

Pass manager options at registration time#135

Merged
wswoodruff merged 16 commits intomasterfrom
multiple-registrations
Dec 29, 2017
Merged

Pass manager options at registration time#135
wswoodruff merged 16 commits intomasterfrom
multiple-registrations

Conversation

@wswoodruff
Copy link
Copy Markdown
Contributor

@wswoodruff wswoodruff commented Nov 19, 2017

  • Feedback welcome

  • Set multiple: true, as it's required to pass plugin options

  • Register vision via server.register({ plugin: Vision, options: { ... }); where:

    • options is a manager config, is synonymous with server.views
  • Effectively, the only thing this adds is the ability to use

      await server.register({
          plugin: Vision,
          options: {/* view manager options */}
      });
    
      // which will have the same effect as
    
      await server.register(Vision);
      server.views({/* view manager options */});
    

lib/index.js Outdated

const parent = realm.parent;

return internals.nearestState(parent);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Perhaps (?) not a practical concern here, but beware recursion in javascript. There's still no such thing as tail recursion in node, so each time you recurse the call stack gets longer (and it has a max allowed size).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

(And this can always be expressed as a while loop!)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I was having trouble getting code coverage with the while loop Eran had here, because parent would never evaluate to false, since the root server always has vision state. The root server always has vision state because of the { setup: true } introduced in the register func.

Here's what's currently in vision - the loop Eran wrote:

internals.realm = function (server) {

    if (server.realm.plugins.vision) {
        return server.realm.plugins.vision;
    }

    let parent = server.realm.parent;
    while (parent) {
        if (parent.plugins.vision) {
            return parent.plugins.vision;
        }

        parent = parent.parent;
    }

    return {};
};

As soon as the root server goes in this loop, it is returned as having a realm because setup.true will always be there. So parent = parent.parent will never run, which would cause it to evaluate to false in the while loop, and return {}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This could possibly be rewritten as nearestManager, which would fix the issue of returning just because a realm has state in vision

lib/index.js Outdated

internals.getRootRealm = (realm) => {

let rootRealm = realm;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think rootRealm is a slightly odd variable name here– it's not the root realm until it's returned (and not being used as a variable anymore).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Agree!

lib/index.js Outdated

Joi.assert(options, internals.schema.manager, 'Invalid manager options');

const realm = this.realm.parent || this.realm;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Wait, when server.views() is called inside a plugin wont this set the manager on the plugin's parent? It would be hard to see this in a test when nearestState() comes into play. But imagine server1 registers a plugin with server2, and server2 register a plugin with server3. Now server3 calls server3.views()– I think this will cause server2 and server3 to both have the same manager.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I think you're probably right, I'll definitely go back and ensure this acts correctly in tests

lib/index.js Outdated
});
internals.assignManager = function (options) {

Joi.assert(options, internals.schema.manager, 'Invalid manager options');
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Doesn't the manager make this assertion on its own?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yup! No need to export the schema I suppose

test/index.js Outdated
const views = {
engines: { 'html': Handlebars },
path: './templates/plugin'
path: __dirname + '/templates/plugin'
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Why this change?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This might've slipped through when trying to write tests based off of others. I can remove it!

Copy link
Copy Markdown

@jedireza jedireza left a comment

Choose a reason for hiding this comment

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

I haven't taken a test drive yet but I did leave a couple small questions.

test/index.js Outdated
register: function (server, options) {

return server.register(Vision);
server.register({
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Should we be using awaiting the return of this? (seen later in other call sites as well)

await server.register(...

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I've asked around about this, "what's the difference between return await [Promise] and return [Promise]? And ljharb in the Node.js Slack community said they're identical in what they do, only returning an await causes an unnecessary wrapper. Do you know if there's a difference?

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

I see. That's good to know.

Do you know if there's a difference?

Nope. I'm new to async/await in general.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I find it's generally easier to remove cognitive load by simply awaiting anything async– only think about the underlying promises when really necessary. For what it's worth, in a lot of hapi code you'll find return await somePromise. Unless perf is terribly important, that seems most consistent.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Good to know!!

test/index.js Outdated
}
});

return server.route({
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

I'm curious why you're using return here. I don't see a reference in the docs about needing to return anything from a plugin's register function. (seen later in other call sites as well)

@wswoodruff
Copy link
Copy Markdown
Contributor Author

Thanks so much for the review guys!

@thebinarypenguin
Copy link
Copy Markdown

I'm excited about the ability to pass view manager options at registration time, but I'm curious what does that have to do with multiple registrations?

@wswoodruff
Copy link
Copy Markdown
Contributor Author

wswoodruff commented Dec 16, 2017

https://github.com/hapijs/hapi/blob/master/API.md#-await-serverregisterplugins-options
mentions that once: true ... 'Cannot be used with plugin options.'

So just to allow plugin options loL ¯\(ツ)

@thebinarypenguin
Copy link
Copy Markdown

@wswoodruff Gotcha. Thanks for the plugin, and preemptive thanks for this new feature. 🎉

@wswoodruff wswoodruff changed the title Multiple registrations Pass manager options at registration time Dec 24, 2017
lib/index.js Outdated
return parent.plugins.vision;
}
// This fingerprint is set when using the 'onRequest' server ext
if (this.request.route.fingerprint === '/#') {
Copy link
Copy Markdown
Contributor Author

@wswoodruff wswoodruff Dec 24, 2017

Choose a reason for hiding this comment

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

I'm curious what others think of using the fingerprint /# for detecting when using the 'onRequest' server extension.

When using the toolkit view decorator inside the onRequest server extension, it seems like this.request.route.realm is set to the root server every time.

lib/index.js Outdated
if (this.request.route.fingerprint === '/#') {

parent = parent.parent;
// 'this' is the plugin/server that registered the extension
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

this should be the toolkit itself. If h.view() is called in an extension then h.realm will be the realm in which the extension was created.

I'm pretty sure you want to always use h.realm and not h.request.route.realm here. Imagine writing a plugin that has its own manager and registers some extensions (but no routes). When calling h.view() in one of those extensions I think you would expect to know only about your manager/templates, and not about other managers/templates registered in a different plugin (i.e. a separate plugin that registers routes).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Hm, now I can't remember why I wrote it grabbing the realm from the route.

@wswoodruff
Copy link
Copy Markdown
Contributor Author

Thanks for the reviews guys! I'm hoping to merge this to master soon after the holidays, gonna let it marinate again for a little bit, not a whole month this time tho loL

@wswoodruff wswoodruff added this to the 5.3.0 milestone Dec 28, 2017
@wswoodruff
Copy link
Copy Markdown
Contributor Author

It's time! =P

@wswoodruff wswoodruff merged commit 6f1db29 into master Dec 29, 2017
@wswoodruff wswoodruff deleted the multiple-registrations branch December 31, 2017 20:43
@lock
Copy link
Copy Markdown

lock bot commented Jan 9, 2020

This thread has been automatically locked due to inactivity. Please open a new issue for related bugs or questions following the new issue template instructions.

@lock lock bot locked as resolved and limited conversation to collaborators Jan 9, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants