We took the same approach (simple hooks) in three.js and in glTF-Transform, and this has been working well. Official extensions are designed not to conflict, and if you’re creating custom extensions that would be an important design consideration.
In three.js, there are some hooks for which all extensions are given a chance to run: for example, multiple extensions might append properties to a single material. In other hooks, only the highest-priority extension runs for a particular object: for example, extensions might provide several texture formats (JPEG, Basis Universal, WebP, …) and it is up to the client to decide which is most appropriate and only download that.
I think it would also be possible to perform a “standard” import first and call extensions later, but (1) you’d need to plan standard import carefully for certain extensions, like Draco, which provide all vertex data, and (2) this is potentially less efficient at runtime — you might end up requesting textures or other resources referenced by the extensions in serial, rather than in parallel with the main process.
Here’s a simpler implementation I did recently, in case it’s helpful, also designed to support third-party extension implementations. Some extensions process at the end for now, but there are a few common hooks too: