Auto Components
Automatically load and run your component modules without manual require statements. Part of SuperbulletFrameworkV1-Knit (2025).
What Does This Do?
Instead of manually requiring and initializing each module, you add Instance = script to your service/controller and Knit handles the rest:
When you pass Instance = script to CreateService() or CreateController(), Knit will automatically:
- Look for a
Componentsfolder inside your service/controller - Load all component modules and call their
Init()functions - Set up
Accessor,Mutator, andComponentsutilities on the service/controller - Call
Start()on all components after the service/controller starts
Enabling Component Initialization
Pass Instance = script when creating your service or controller:
Server (Service):
local MyService = Knit.CreateService({
Name = "MyService",
Client = {},
Instance = script, -- Enables automatic component initialization
})Client (Controller):
local MyController = Knit.CreateController({
Name = "MyController",
Instance = script, -- Enables automatic component initialization
})Folder Structure
The Component Initializer expects this folder structure:
MyService/
βββ init.lua -- Main service file
βββ Components/
βββ Accessor.lua -- (Optional) Get component for reading data
βββ Mutator.lua -- (Optional) Set component for writing data
βββ Others/
βββ FeatureA.lua
βββ FeatureB.lua
βββ Utilities.luaLegacy Support
For backward compatibility, the system also supports:
Get().luainstead ofAccessor.luaSet().luainstead ofMutator.lua
Component Lifecycle
Components follow a two-phase lifecycle that mirrors Knit's service/controller lifecycle:
Lifecycle Order:
1. Knit.Start() begins
2. Service/Controller KnitInit() runs
3. ComponentInitializer.Initialize() runs:
- Loads all modules in Components/Others/
- Sets up Accessor and Mutator
- Calls Init() on all component modules
4. Service/Controller KnitStart() runs
5. ComponentInitializer.Start() runs:
- Calls Start() on all component modulesInit() Phase
The Init() function runs before KnitStart(). Use it for:
- Setting up initial state
- Registering client extensions (signals, methods, properties)
- Getting service/controller references
-- Components/Others/QuestHandler.lua
local QuestHandler = {}
function QuestHandler.Init()
-- Runs during component initialization phase
local QuestService = Knit.GetService("QuestService")
-- Register dynamic client items here
Knit.RegisterClientSignal(QuestService, "OnQuestUpdate")
end
return QuestHandlerStart() Phase
The Start() function runs after KnitStart(). Use it for:
- Runtime logic
- Connecting events
- Starting gameplay systems
-- Components/Others/QuestHandler.lua
local QuestHandler = {}
function QuestHandler.Init()
-- Setup code
end
function QuestHandler.Start()
-- Runs after service starts
-- Safe to run gameplay logic here
QuestHandler:LoadActiveQuests()
end
function QuestHandler:LoadActiveQuests()
-- Implementation
end
return QuestHandlerAccessing Components
After initialization, the service/controller has access to:
Components Table
All modules in the Others/ folder are available via self.Components:
function MyService:KnitStart()
-- Access a component module
local QuestHandler = self.Components.QuestHandler
QuestHandler:DoSomething()
endAccessor (Get Component)
If you have an Accessor.lua (or Get().lua), it's available via self.Accessor:
-- Components/Accessor.lua
local Accessor = {}
function Accessor:GetPlayerData(player)
return DataStore:GetData(player)
end
return Accessor
-- In your service:
function MyService:KnitStart()
local data = self.Accessor:GetPlayerData(somePlayer)
-- or use the alias:
local data = self.GetComponent:GetPlayerData(somePlayer)
endMutator (Set Component)
If you have a Mutator.lua (or Set().lua), it's available via self.Mutator:
-- Components/Mutator.lua
local Mutator = {}
function Mutator:SetPlayerData(player, data)
DataStore:SetData(player, data)
end
return Mutator
-- In your service:
function MyService:KnitStart()
self.Mutator:SetPlayerData(somePlayer, newData)
-- or use the alias:
self.SetComponent:SetPlayerData(somePlayer, newData)
endComplete Example
MyService/init.lua:
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Knit = require(ReplicatedStorage.Packages.Knit)
local MyService = Knit.CreateService({
Name = "MyService",
Client = {},
Instance = script,
})
function MyService:KnitStart()
-- Components are now available
print("Components loaded:", self.Components)
-- Use the Accessor
if self.Accessor then
local data = self.Accessor:GetSomeData()
end
end
function MyService:KnitInit()
-- Get other services
end
return MyServiceMyService/Components/Accessor.lua:
local Accessor = {}
function Accessor:GetSomeData()
return { key = "value" }
end
return AccessorMyService/Components/Others/FeatureHandler.lua:
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Knit = require(ReplicatedStorage.Packages.Knit)
local FeatureHandler = {}
function FeatureHandler.Init()
print("FeatureHandler initializing")
-- Can register client items here
local MyService = Knit.GetService("MyService")
Knit.RegisterClientSignal(MyService, "FeatureEvent")
end
function FeatureHandler.Start()
print("FeatureHandler started")
-- Runtime logic
end
return FeatureHandlerDuplicate Prevention
The Component Initializer tracks which modules have been initialized using attributes:
Initializedattribute prevents callingInit()twiceStartedattribute prevents callingStart()twice
This ensures components only run their lifecycle methods once, even if the module is required multiple times.
Error Handling
If a component's Init() or Start() function throws an error, the system:
- Logs a warning with the full path to the component
- Continues initializing other components
- Does not halt the entire Knit startup process
Example warning:
Error initializing component ServerScriptService.MyService.Components.Others.BrokenComponent: attempt to index nilBest Practices
- Keep components focused - Each component should handle one specific feature
- Use Init() for setup - Register remotes, set up state
- Use Start() for runtime - Connect events, start systems
- Don't yield in Init() - This blocks other services from initializing
- Access other services in Init() - They're available via
Knit.GetService()