good morning! i'm curious about some of the inner ...
# typescript
s
good morning! i'm curious about some of the inner workings of ComponentResource. does anybody know if there's a difference between setting a component property vs using registerOutput . for instance in this example, why use
registerOutputs({bucketName: ....})
instead of just declaring and setting
this.bucketName
like does it change the way the dependency graph/resolution order/change detection work?
the one thing i could think of would be for cross-language support. i can imagine it being much easier to only expose things done via
registerOutput
as opposed to all of the various ways different languages can expose properties/getters/etc
f
RegisterOutputs
signals that the
ComponentResource
is done creating child resources and is mainly for quicker UI updates. It will not affect the dep graph. Specifically for TS, see: https://github.com/pulumi/pulumi/blob/510111fe67666834b7e7ed43242ac60a3eaa524e/sdk/nodejs/resource.ts#L1280 and https://github.com/pulumi/pulumi/blob/510111fe67666834b7e7ed43242ac60a3eaa524e/sdk/nodejs/runtime/resource.ts#L1131
s
@future-hairdresser-70637 ah, interesting. it seems weird to signal that it's done creating when that always fires before the child constructor is finished
maybe a related question would be, is there any reason to use
initialize
over putting all of the logic in the constructor?
like even in the example i linked,
registerOutputs
is a noop
super
calls
initializeAndRegisterOutputs
before it returns to the child constructor. and those don't do anything useful unless you have a custom
initialize
method (which i don't really see any good examples of/reason to use)
f
is there any reason to use
initialize
over putting all of the logic in the constructor?
I would say no, as
ComponentResource
is "just" a container for other resources; more of an organizational/reuse thing than an actual Resource. I want to say I've seen an example or two that overrode
initialize
but I can't think of where/why
s
@future-hairdresser-70637 that makes total sense. it feels like maybe those are vestiges of maintaining parity with
Resource
wonders how many thousands of LOC are uselessly calling
registerOutputs
f
i would still recommend following the best practices of the docs and call it
The call to
registerOutputs
also tells Pulumi that the resource is done registering children and should be considered fully constructed, so—although it’s not enforced—the best practice is to call it in all components even if no outputs need to be registered.
there's no absolute guarantee that this will stay unenforced
(or possibly do something else in the future)
s
that's the part that's misleading though
Copy code
class Foo extends ComponentResource {
  constructor(......) {
    super(....)
    // registerOutputs was called by super
    new FooResource(....)
    // but we're not done creating resources
  }
}
@future-hairdresser-70637 i just did some testing. another thing
registerOutputs
does that's somewhat useful is showing resource outputs on the resource page on pulumi cloud
but the UX is definitely clunky
Copy code
interface ExampleOutputs {
  hostname: Output<string>
}

export class ExampleResource extends ComponentResource<ExampleOutputs> {
  protected initialize(args: ExampleArgs): Promise<ExampleOutputs> {
    const hostname = args.wildcard ? '*' : args.hostname
    const retval = {
      hostname,
    }
    this.registerOutputs(retval)
    return Promise.resolve(output(retval))
  }
  ...
}
f
@steep-secretary-65224 🤔 it doesn't show up without the call to
registerOutputs
?
s
nope. and if you try to call it in the constructor, it short circuits because it was already called at the end of the
super
call
f
I would very lightly argue that's a somewhat contrived example there because of the input
args
-> output
retval
? that is, it's expected the
ComponentResource
will do "stuff" such as have resources with their
parent
==
this
this is the issue I tend to send out to folks wondering about
registerOutputs
https://github.com/pulumi/pulumi/issues/2653
s
hmm, that's a good point
f
i agree this is still documented... oddly, at best, and not with sufficient "but why do we do this?" aside from "because we say to (and it updates the UI)" :)
it varies a bit across languages as well, if I recall. e.g. C# has the
[Output]
property attribute which
registerOutputs
looks for
s
agreed. given that you can't really create resources, i think the only real use would be like my example, where you might be calculating values, fetching resources (eg,
aws.route53.getZone
), etc
but it's still flimsy
it almost feels like https://github.com/pulumi/pulumi/blob/510111fe67666834b7e7ed43242ac60a3eaa524e/sdk/nodejs/resource.ts#L1246-L1250 should be more like
this.registerOutputs(await this.initialize(args)
f
🙂
which does have some interesting historical comments
s
heh, it's nice to see i had the same gut reaction as @white-balloon-205