roblox-tsr
roblox-ts5mo ago
7 replies
kv_

Create components at runtime

I have a function external to flamework which components/services/controllers can call to create components at runtime without having to set the instance up with attributes or having to call some setup method so that components can always be expected to work solely on attributes. This makes it a lot easier to create components that depend on each other or need to construct each other without implementing special handling for components created outside of those cases.
// runtime_create.ts
export const createComponent = (component: BaseComponent, attributes?: { [key: string]: AttributeValue }, instance?: Instance) => {
    const components = Dependency<Components>();
    if (!instance) {
        instance = new Instance('Part', Workspace);
    }

    if (attributes) {
        for (const [idx, v] of pairs(attributes)) {
            instance.SetAttribute(idx as string, v); // attributes keys cannot be numeric
        }
    }

    return components.addComponent<typeof component>(instance);
};

I am sure this is not a proper way of doing this but seems to be the only one I can find. Currently it is producing an error that I am not sure how to fix:
ReplicatedStorage.rbxts_include.node_modules.@flamework.components.out.components:565: Could not find component from specifier: $c:baseComponent@BaseComponent

I also have a gripe with it; creating the components dependency every time the function is called sounds like a bad idea, but I can't create it outside of the function since the script will call it before flamework is done loading:
[Flamework] Attempting to load dependency '$c:components@Components' during preloading.
This is prone to race conditions and is not guaranteed to succeed.

Any help is appreciated 🙂
Solution
Solution was to pass the component specifier to addComponent instead of the class:
/** @metadata macro */
export function makeComponent<T>(attributes?: { [key: string]: AttributeValue }, instance?: Instance, id?: Modding.Generic<T, 'id'>) {
    const components = Dependency<Components>();

    if (!instance) {
        instance = new Instance('Part', Workspace);
    }

    for (const [idx, v] of pairs(attributes || {})) {
        instance.SetAttribute(idx as string, v);
    }

    return components.addComponent(instance, id);
}
Was this page helpful?