Depending on which addon is bringing in {{did-update}}, it looks like it only defines a modifier.
When using the globals resolver (where you don't need to import anything), the syntax matters more than the name of the thing you're typing.
So,
{{did-update}} in a template is a helper. This will be looked up in app / addon's helpers directories.
<div {{did-update}}> is a modifier. This will be looked up in app / addon's modifiers directories.
I made this little explainer for how to read the syntax:
<div {{this.modifierName a b=(this.helperName c)}}>
{{!-- │ │ │ │ └─── positional argument
│ │ │ └─── helper
│ │ └─── named argument key
│ └─── positional argument
└─── modifier --}}
{{yield to="default"}}
{{!-- │ │ └─── value
│ └─── named argument key
└─── helper --}}
</div>
<div {{@modifierName a b=(@helperName c)}}>
{{!-- │ │ │ │ └─── positional argument
│ │ │ └─── helper
│ │ └─── named argument key
│ └─── positional argument
└─── modifier --}}
{{yield to="default"}}
{{!-- │ │ └─── value
│ └─── named argument key
└─── helper --}}
</div>
From: https://cheatsheet.glimmer.nullvoxpopuli.com/docs/templates
There is a slight difference when you a local value. For example:
class Demo extends Component {
foo = () => {};
}
using this function, foo, we can use it the following ways
{{this.foo}} renders, but is a function, so it doesn't render nicely
{{ (this.foo) }} invokes the function and renders the output, or nothing if undefined
<div {{this.foo}}></div> errors, because the function, foo, is not a modifier
<div {{ (this.foo) }}></div> invokes foo, because it is a function / helper, returns undefined, which is now in "modifier space", undefined modifiers are no-ops, and does nothing. This is useful for when you want to do conditional modifiers
<div {{ (if this.someCondition this.myModifier}}) }}></div> this will collapse down to (if some condition is true):
<div {{this.myModifier}}></div>
<this.foo /> errors, because the function, foo, does not have an associated component manager / foo is not a component.