### Good Module Structure Example Source: https://github.com/ldgerrits/bootstrapper/blob/main/_autodocs/quick-reference.md This is an example of a well-structured module for Bootstrapper, including common lifecycle methods like init, start, update, tick, and shutdown. ```lua -- Good module for Bootstrapper local MyService = {} function MyService:init() self.initialized = true end function MyService:start() self:loadData() end function MyService:update(deltaTime) -- Per-frame logic end function MyService:tick(deltaTime) -- Periodic logic end function MyService:shutdown() self.initialized = false end return MyService ``` -------------------------------- ### Setup Multiple Stages with runAsync() Source: https://github.com/ldgerrits/bootstrapper/blob/main/_autodocs/execution-modes.md Demonstrates a multi-stage setup using run(), runAsync(), and runConcurrent(). Stage 2 uses runAsync() for non-blocking background loading while other stages proceed. ```lua local Bootstrapper = require(packages.Bootstrapper) local services = Bootstrapper.loadChildren(parent) -- Stage 1: Initialize (sequential, blocking) print("Stage 1: Initializing...") Bootstrapper.run(services, ':init') -- Stage 2: Load assets (sequential, non-blocking background) print("Stage 2: Loading assets in background...") Bootstrapper.runAsync(services, ':loadAssets') -- Stage 3: Start (concurrent, non-blocking) print("Stage 3: Starting services...") Bootstrapper.runConcurrent(services, '.start') -- All three can overlap: stage 2 runs in background while stage 3 proceeds ``` -------------------------------- ### Quick Start: Bootstrapper Initialization Source: https://github.com/ldgerrits/bootstrapper/blob/main/README.md Demonstrates how to initialize core systems using strict boot sequences or automatic discovery. Use ':init' for manual order and ':start' for async initialization. Automatic discovery sorts modules by name. ```lua local Bootstrapper = require(packages.Bootstrapper) -- Strict boot sequence (manual order for core systems) local bootSequence = { path.to.DataService, path.to.PlayerService, path.to.ZoneService } Bootstrapper.run(bootSequence, ':init') -- injects self Bootstrapper.runAsync(bootSequence, ':start') -- injects self -- Automatic discovery (A-Z sorted) local systems = Bootstrapper.loadChildren(path.to.Systems, Bootstrapper.byName('System$')) -- Use '.run' for a strict A-Z sequence, or '.runConcurrent()' if not Bootstrapper.run(systems, '.init') -- does NOT inject self Bootstrapper.runConcurrent(systems, '.start') -- does NOT inject self -- Maintains alphabetical execution every frame with auto-memory profiling. Bootstrapper.bindToHeartbeat(systems, '.onUpdate') -- does NOT inject self -- Run every second without drift. Bootstrapper.bindToInterval(systems, '.onTick', 1.0) -- does NOT inject self ``` -------------------------------- ### Background Initialization with runAsync() Source: https://github.com/ldgerrits/bootstrapper/blob/main/_autodocs/execution-modes.md Starts module initialization in a background thread using runAsync(), allowing the main thread to continue immediately with UI setup. Errors are logged but not returned. ```lua local Bootstrapper = require(packages.Bootstrapper) local services = Bootstrapper.loadSequence({ DatabaseService, CacheService, NetworkService, }) -- Start initialization in background Bootstrapper.runAsync(services, ':preload') -- Continue immediately with UI setup print("Initializing...") showLoadingScreen() -- Later, services are ready game:WaitForChild("Initialized") hideLoadingScreen() ``` -------------------------------- ### Bootstrapper Long Setup with runAsync() Source: https://github.com/ldgerrits/bootstrapper/blob/main/_autodocs/execution-modes.md Employ `runAsync()` for long-running setup tasks to prevent blocking the main thread, such as during loading screens. Using `run()` for such tasks will block all operations. ```lua -- GOOD: Don't block loading screen Bootstrapper.runAsync(services, ':preload') showLoadingBar() ``` ```lua -- BAD: Blocks everything Bootstrapper.run(services, ':preload') ``` -------------------------------- ### Example: DataProcessor Functional Methods Source: https://github.com/ldgerrits/bootstrapper/blob/main/_autodocs/method-invocation.md Demonstrates module methods designed for functional processing, suitable for static invocation. ```lua -- DataProcessor.lua local DataProcessor = {} function DataProcessor.process(data) local processed = {} for _, item in pairs(data) do table.insert(processed, item.value * 2) end return processed end function DataProcessor.validate(data) return data and type(data) == 'table' end return DataProcessor ``` -------------------------------- ### Valid Task Examples Source: https://github.com/ldgerrits/bootstrapper/blob/main/_autodocs/types.md Provides examples of various types that are considered valid Tasks, which Bootstrapper can internally manage for cleanup. ```lua -- All of these are valid Tasks returned from subscription functions local connection = signal:Connect(callback) -- RBXScriptConnection local object = Instance.new("Part") -- Instance (has :Destroy()) local custom = { destroy = function(self) end } -- Table with destroy method local cleanup = function() end -- Function -- Bootstrapper internally handles cleanup for any of these ``` -------------------------------- ### Example: Bootstrapper Run for Functional Processing Source: https://github.com/ldgerrits/bootstrapper/blob/main/_autodocs/method-invocation.md Use Bootstrapper.run with dot notation to call functional methods like 'validate' and 'process'. ```lua local Bootstrapper = require(packages.Bootstrapper) local processors = Bootstrapper.loadSequence({ DataProcessor }) -- Both methods work without self Bootstrapper.run(processors, '.validate', { a = 1 }) Bootstrapper.run(processors, '.process', someData) ``` -------------------------------- ### Synchronous Setup with Step-by-Step Dependencies Source: https://github.com/ldgerrits/bootstrapper/blob/main/_autodocs/execution-modes.md When modules have complex interdependencies, `Bootstrapper.run()` can be called multiple times with smaller groups of modules to manage initialization step-by-step and handle errors at each stage. ```lua local modules = { ConfigService, -- Load config DatabaseService, -- Connect to DB (needs config) APIService, -- Setup API (needs config and DB)} -- Initialize in order, checking at each stage local step1, err1 = Bootstrapper.run({modules[1]}, ':init') if err1 then error("Config failed") end local step2, err2 = Bootstrapper.run({modules[2]}, ':init') if err2 then error("Database failed") end local step3, err3 = Bootstrapper.run({modules[3]}, ':init') if err3 then error("API failed") end ``` -------------------------------- ### Bootstrapper Initialization with run() Source: https://github.com/ldgerrits/bootstrapper/blob/main/_autodocs/execution-modes.md Use `run()` for blocking initialization to ensure critical setup completes before proceeding. Avoid `runConcurrent()` for initialization as it may lead to missing dependencies. ```lua -- GOOD: Block until critical setup completes Bootstrapper.run(services, ':init') ``` ```lua -- BAD: Non-blocking initialization might miss dependencies Bootstrapper.runConcurrent(services, ':init') ``` -------------------------------- ### Stateful Service Example Source: https://github.com/ldgerrits/bootstrapper/blob/main/_autodocs/method-invocation.md Illustrates how to define and use a stateful service module with colon notation. The ':init' and ':addPlayer' methods access and modify module state via 'self'. ```lua -- PlayerService.lua local PlayerService = {} function PlayerService:init() self.players = {} self.maxPlayers = 100 end function PlayerService:addPlayer(playerId, playerData) self.players[playerId] = playerData end function PlayerService:getPlayerCount() return table.getn(self.players) end return PlayerService ``` ```lua local Bootstrapper = require(packages.Bootstrapper) local service = Bootstrapper.loadSequence({ PlayerService }) -- Invoke with colon (self is passed) Bootstrapper.run(service, ':init') Bootstrapper.run(service, ':addPlayer', player1, { name = 'Alice' }) -- Inside :addPlayer, self.players is accessible ``` -------------------------------- ### Example: Creating and Using Predicate Functions Source: https://github.com/ldgerrits/bootstrapper/blob/main/_autodocs/types.md Shows how to create a PredicateFn using the byName helper or by defining a custom function. The predicate is then used to filter ModuleScripts during loading. ```lua -- Create a predicate using byName helper local predicate = Bootstrapper.byName('Service$') -- Or create a custom predicate local customPredicate = function(moduleScript: ModuleScript): boolean return moduleScript.Name:match('Service') ~= nil and not moduleScript.Name:match('Abstract') end local modules = Bootstrapper.loadChildren(parent, customPredicate) ``` -------------------------------- ### Lazy Module Loading Examples Source: https://github.com/ldgerrits/bootstrapper/blob/main/_autodocs/configuration.md Demonstrates Bootstrapper's ability to automatically require modules when they are loaded into the sequence. ```lua -- These all work identically local m1 = Bootstrapper.loadSequence({ ModuleScriptInstance }) local m2 = Bootstrapper.loadSequence({ 'path.to.Module' }) local m3 = Bootstrapper.loadSequence({ alreadyRequiredModule }) ``` -------------------------------- ### Bootstrapper Ordered Initialization Pattern Source: https://github.com/ldgerrits/bootstrapper/blob/main/_autodocs/quick-reference.md Initializes services in a specific sequence by loading them using `loadSequence`, then running ':init' and ':start' methods, and binding ':update' to the heartbeat. ```lua local Bootstrapper = require(packages.Bootstrapper) local services = Bootstrapper.loadSequence({ DatabaseService, PlayerService, GameService, }) Bootstrapper.run(services, ':init') Bootstrapper.runAsync(services, ':start') Bootstrapper.bindToHeartbeat(services, ':update') ``` -------------------------------- ### Example: Bootstrapper Run for Static Update Source: https://github.com/ldgerrits/bootstrapper/blob/main/_autodocs/method-invocation.md Invoke a static method using dot notation. This calls the method without passing 'self'. ```lua -- Boot script local Bootstrapper = require(packages.Bootstrapper) local modules = Bootstrapper.loadSequence({ MyModule }) -- Call without self Bootstrapper.run(modules, '.update', 0.016) -- Invokes: MyModule.update(0.016) ``` -------------------------------- ### Luau Debugging Checklist Example Source: https://github.com/ldgerrits/bootstrapper/blob/main/_autodocs/MANIFEST.txt Provides a snippet representing a debugging checklist. This is a conceptual example; the actual checklist would be more detailed and likely text-based. ```luau -- Conceptual debugging step if bootstrapper.isDebugMode() then bootstrapper.log("Debugging enabled. Checking assertions...") assert(bootstrapper.checkState(), "State assertion failed") end ``` -------------------------------- ### API Reference - Functions Source: https://github.com/ldgerrits/bootstrapper/blob/main/_autodocs/README.md Exhaustive function-by-function reference with signatures, parameters, returns, and examples for Bootstrapper. ```APIDOC ## `byName()` ### Description Predicate for filtering modules. ### Signature ```lua function byName(name: string): PredicateFn ``` ### Parameters - **name** (string) - Required - The name of the module to filter by. ### Returns - `PredicateFn` - A function that returns true if a module's name matches the provided name. ``` ```APIDOC ## `loadChildren()` ### Description Loads direct children of a module. ### Signature ```lua function loadChildren(module: ModulePath, options?: LoadOptions): LoadedModules ``` ### Parameters - **module** (ModulePath) - Required - The path to the module whose children should be loaded. - **options** (LoadOptions) - Optional - Configuration options for loading. ### Returns - `LoadedModules` - A table containing the loaded child modules. ``` ```APIDOC ## `loadDescendants()` ### Description Loads all descendants of a module recursively. ### Signature ```lua function loadDescendants(module: ModulePath, options?: LoadOptions): LoadedModules ``` ### Parameters - **module** (ModulePath) - Required - The path to the module whose descendants should be loaded. - **options** (LoadOptions) - Optional - Configuration options for loading. ### Returns - `LoadedModules` - A table containing all loaded descendant modules. ``` ```APIDOC ## `loadSequence()` ### Description Loads modules in a specified sequence. ### Signature ```lua function loadSequence(modules: ModulePath[], options?: LoadOptions): LoadedModules ``` ### Parameters - **modules** (ModulePath[]) - Required - An array of module paths to load in order. - **options** (LoadOptions) - Optional - Configuration options for loading. ### Returns - `LoadedModules` - A table containing the loaded modules in the order they were specified. ``` ```APIDOC ## `run()` ### Description Executes a module synchronously. ### Signature ```lua function run(module: ModulePath, options?: RunOptions): any ``` ### Parameters - **module** (ModulePath) - Required - The path to the module to execute. - **options** (RunOptions) - Optional - Configuration options for execution. ### Returns - `any` - The result of the module execution. ``` ```APIDOC ## `runAsync()` ### Description Executes a module asynchronously in the background sequentially. ### Signature ```lua function runAsync(module: ModulePath, options?: RunOptions): void ``` ### Parameters - **module** (ModulePath) - Required - The path to the module to execute. - **options** (RunOptions) - Optional - Configuration options for execution. ### Returns - `void` ``` ```APIDOC ## `runConcurrent()` ### Description Executes modules in parallel. ### Signature ```lua function runConcurrent(modules: ModulePath[], options?: RunOptions): void ``` ### Parameters - **modules** (ModulePath[]) - Required - An array of module paths to execute concurrently. - **options** (RunOptions) - Optional - Configuration options for execution. ### Returns - `void` ``` ```APIDOC ## `bindTo()` ### Description Binds a module's execution to a custom signal. ### Signature ```lua function bindTo(signal: Signal, module: ModulePath, options?: BindOptions): Cleanup ``` ### Parameters - **signal** (Signal) - Required - The custom signal to bind to. - **module** (ModulePath) - Required - The path to the module to execute when the signal is fired. - **options** (BindOptions) - Optional - Configuration options for binding. ### Returns - `Cleanup` - A function to disconnect the binding. ``` ```APIDOC ## `bindToInterval()` ### Description Binds a module's execution to a specified interval. ### Signature ```lua function bindToInterval(interval: number, module: ModulePath, options?: BindOptions): Cleanup ``` ### Parameters - **interval** (number) - Required - The interval in seconds. - **module** (ModulePath) - Required - The path to the module to execute. - **options** (BindOptions) - Optional - Configuration options for binding. ### Returns - `Cleanup` - A function to disconnect the binding. ``` ```APIDOC ## `bindToHeartbeat()` ### Description Binds a module's execution to the Heartbeat event. ### Signature ```lua function bindToHeartbeat(module: ModulePath, options?: BindOptions): Cleanup ``` ### Parameters - **module** (ModulePath) - Required - The path to the module to execute. - **options** (BindOptions) - Optional - Configuration options for binding. ### Returns - `Cleanup` - A function to disconnect the binding. ``` ```APIDOC ## `bindToRenderStep()` ### Description Binds a module's execution to a client-side render step. ### Signature ```lua function bindToRenderStep(step: RenderStep, module: ModulePath, options?: BindOptions): Cleanup ``` ### Parameters - **step** (RenderStep) - Required - The render step to bind to. - **module** (ModulePath) - Required - The path to the module to execute. - **options** (BindOptions) - Optional - Configuration options for binding. ### Returns - `Cleanup` - A function to disconnect the binding. ``` ```APIDOC ## `bindToPreSimulation()` ### Description Binds a module's execution to the pre-simulation step. ### Signature ```lua function bindToPreSimulation(module: ModulePath, options?: BindOptions): Cleanup ``` ### Parameters - **module** (ModulePath) - Required - The path to the module to execute. - **options** (BindOptions) - Optional - Configuration options for binding. ### Returns - `Cleanup` - A function to disconnect the binding. ``` ```APIDOC ## `bindToPostSimulation()` ### Description Binds a module's execution to the post-simulation step. ### Signature ```lua function bindToPostSimulation(module: ModulePath, options?: BindOptions): Cleanup ``` ### Parameters - **module** (ModulePath) - Required - The path to the module to execute. - **options** (BindOptions) - Optional - Configuration options for binding. ### Returns - `Cleanup` - A function to disconnect the binding. ``` ```APIDOC ## `bindToPreAnimation()` ### Description Binds a module's execution to the pre-animation step. ### Signature ```lua function bindToPreAnimation(module: ModulePath, options?: BindOptions): Cleanup ``` ### Parameters - **module** (ModulePath) - Required - The path to the module to execute. - **options** (BindOptions) - Optional - Configuration options for binding. ### Returns - `Cleanup` - A function to disconnect the binding. ``` ```APIDOC ## `bindToPreRender()` ### Description Binds a module's execution to a client-side pre-render step. ### Signature ```lua function bindToPreRender(module: ModulePath, options?: BindOptions): Cleanup ``` ### Parameters - **module** (ModulePath) - Required - The path to the module to execute. - **options** (BindOptions) - Optional - Configuration options for binding. ### Returns - `Cleanup` - A function to disconnect the binding. ``` -------------------------------- ### Progressive Initialization with Multiple Phases Source: https://github.com/ldgerrits/bootstrapper/blob/main/_autodocs/execution-modes.md This pattern implements a multi-phase initialization process. It includes sequential core setup, concurrent asset loading, sequential asynchronous startup, and continuous updates bound to heartbeat and interval timers. ```lua local Bootstrapper = require(packages.Bootstrapper) local systems = Bootstrapper.loadChildren(parent) -- Phase 1: Core setup (sequential, blocking) local _, err1 = Bootstrapper.run(systems, ':setupCore') if err1 then error("Core setup failed") end -- Phase 2: Asset loading (concurrent, non-blocking) Bootstrapper.runConcurrent(systems, '.loadAssets') -- Phase 3: Startup (sequential, non-blocking) Bootstrapper.runAsync(systems, ':startup') -- Phase 4: Continuous updates Bootstrapper.bindToHeartbeat(systems, ':update') Bootstrapper.bindToInterval(systems, ':tick', 1.0) ``` -------------------------------- ### Example: Handling Errors from loadChildren Source: https://github.com/ldgerrits/bootstrapper/blob/main/_autodocs/types.md Demonstrates how to check for and iterate through errors returned by Bootstrapper.loadChildren. It warns about any modules that failed to load. ```lua local modules, errors = Bootstrapper.loadChildren(game.ServerScriptService.Services) if errors then for moduleName, errorMsg in pairs(errors) do warn(`Module {moduleName} failed to load: {errorMsg}`) end end ``` -------------------------------- ### Standard Bootstrapper Imports Source: https://github.com/ldgerrits/bootstrapper/blob/main/_autodocs/quick-reference.md Demonstrates how to import the Bootstrapper module using the standard 'require' function. This is the most common way to get access to Bootstrapper's functionality. ```lua -- Standard import local Bootstrapper = require(packages.Bootstrapper) ``` ```lua -- From path local Bootstrapper = require(game.ReplicatedStorage.Packages.Bootstrapper) ``` ```lua -- Can be aliased local BS = require(packages.Bootstrapper) BS.run(modules, ':init') ``` ```lua -- Multiple uses in a file local Bootstrapper = require(packages.Bootstrapper) local modules = Bootstrapper.loadChildren(parent) Bootstrapper.run(modules, ':init') ``` -------------------------------- ### Recursive System Loading Example Source: https://github.com/ldgerrits/bootstrapper/blob/main/_autodocs/module-loading.md Loads all ModuleScript descendants from a parent instance, sorted alphabetically by name and then by full path. Assumes a nested folder structure for modules. ```lua local Bootstrapper = require(packages.Bootstrapper) -- Assume folder structure: -- Systems/ -- Combat/ -- DamageSystem -- EffectSystem -- Movement/ -- AnimationSystem -- LocomotionSystem -- Inventory/ -- ItemSystem -- EquipmentSystem local systems = Bootstrapper.loadDescendants( game.ServerScriptService.Systems ) -- Result: All modules, sorted alphabetically -- [1] AnimationSystem (Movement/) -- [2] DamageSystem (Combat/) -- [3] EffectSystem (Combat/) -- [4] EquipmentSystem (Inventory/) -- [5] ItemSystem (Inventory/) -- [6] LocomotionSystem (Movement/) -- Note: Sorting is by Name first, then by full path -- So all "A" modules before "D" modules, etc. ``` -------------------------------- ### Handle Module Load Exceptions with Bootstrapper Source: https://github.com/ldgerrits/bootstrapper/blob/main/_autodocs/errors-and-troubleshooting.md Log detailed error messages when a module fails to initialize after being required. This example prints the error and can halt execution for critical modules. ```lua local Bootstrapper = require(packages.Bootstrapper) local modules, errors = Bootstrapper.loadChildren(parent) if errors then for moduleName, errorMsg in pairs(errors) do print(`Loading {moduleName} failed:`) print(` {errorMsg}`) -- Don't continue if critical module failed if moduleName == 'CriticalService' then error(`Critical module failed: {moduleName}`) end end end ``` -------------------------------- ### Example Module Definition Source: https://github.com/ldgerrits/bootstrapper/blob/main/_autodocs/configuration.md Defines a Lua module with both a method accepting 'self' and a static function. ```lua -- MyModule.lua local MyModule = {} function MyModule:init() print(self.name) end function MyModule.start() print("Starting") end MyModule.name = "MyModule" return MyModule ``` -------------------------------- ### Luau Function Usage Example Source: https://github.com/ldgerrits/bootstrapper/blob/main/_autodocs/MANIFEST.txt Demonstrates how to use an exported function from the Bootstrapper library. Ensure the library is correctly loaded before calling functions. ```luau local bootstrapper = require(path.to.bootstrapper) -- Example function call local result = bootstrapper.someFunction(arg1, arg2) print(result) ``` -------------------------------- ### Example: MyModule Static Update Function Source: https://github.com/ldgerrits/bootstrapper/blob/main/_autodocs/method-invocation.md Define a module with a static function that does not rely on module state. ```lua -- MyModule.lua local MyModule = {} -- Static function (doesn't use self) function MyModule.update(deltaTime) print(`Updating: {deltaTime}s`) end return MyModule ``` -------------------------------- ### Event Binding with Bootstrapper Source: https://github.com/ldgerrits/bootstrapper/blob/main/README.md Demonstrates how to bind RunService events or signals directly to module methods. Includes examples for render steps, intervals, and custom game state changes, along with cleanup functions. ```lua local cleanupRenderStep = Bootstrapper.bindToRenderStep(services, '.onRender', Enum.RenderPriority.Last.Value) local cleanupInterval = Bootstrapper.bindToInterval(systems, '.onTick', 1.0) local cleanupGameState = Bootstrapper.bindTo(services, '.onGameState', GameState.Changed) -- Disconnect everything when they are no longer needed cleanupRenderStep() cleanupInterval() cleanupGameState() ``` -------------------------------- ### Bootstrapper.run Source: https://github.com/ldgerrits/bootstrapper/blob/main/_autodocs/api-reference.md Calls a method on each module sequentially, yielding until all complete. Ensures that module A finishes before module B starts. The module itself is passed as `self` by default, or can be called as a static function using '.' prefix. ```APIDOC ## Bootstrapper.run(modules: { Instance | ModulePath | LoadedModule }, methodName: string, ...: any): (LoadedModules, Errors?) ### Description Calls a method on each module sequentially, yielding until all complete. Ensures that module A finishes before module B starts. The module itself is passed as `self` by default, or can be called as a static function using '.' prefix. Additional arguments can be passed to the method. ### Parameters #### Path Parameters - **modules** (Instance | ModulePath | LoadedModule) - Required - Array of modules to execute - **methodName** (string) - Required - Method name, prefixed with '.' to call without self, or ':' (default) to inject self - **...** (any) - Required - Additional arguments passed to each method ### Returns - **LoadedModules** - Tuple of successfully executed modules - **Errors?** - Optional error map (nil if no errors) ### Request Example ```lua local Bootstrapper = require(packages.Bootstrapper) local services, errors = Bootstrapper.loadSequence({ DataService, PlayerService, ZoneService, }) -- Run with self injection (module:init()) local loaded, runErrors = Bootstrapper.run(services, ':init') -- Run without self injection (module.init()) Bootstrapper.run(services, '.init') -- Pass additional arguments Bootstrapper.run(services, ':initialize', gameConfig, playerData) -- Check for runtime errors if runErrors then for moduleName, errorMsg in pairs(runErrors) do warn(`Module {moduleName} failed: {errorMsg}`) end end ``` ``` -------------------------------- ### Module Return Type Examples Source: https://github.com/ldgerrits/bootstrapper/blob/main/_autodocs/errors-and-troubleshooting.md Illustrates correct and incorrect return types for modules loaded by Bootstrapper. Modules must return a table, not strings, numbers, nil, or functions. ```lua -- BAD: Module returns wrong type return "string" return 123 return nil return function() end -- GOOD: Module returns table return {} return { init = function() end } ``` -------------------------------- ### Independent Service Setup with runConcurrent Source: https://github.com/ldgerrits/bootstrapper/blob/main/_autodocs/execution-modes.md Set up multiple independent services concurrently using runConcurrent. This ensures that services like audio, particles, and animations are initialized in parallel without blocking the main thread. ```lua local Bootstrapper = require(packages.Bootstrapper) local services = { AudioService, -- Sets up audio (no dependencies) ParticleService, -- Loads particles (no dependencies) AnimService, -- Caches animations (no dependencies) VFXService, -- Sets up effects (no dependencies) } -- All services setup in parallel Bootstrapper.runConcurrent(services, ':setup') -- Continue immediately; services set up concurrently print("All services starting up...") ``` -------------------------------- ### Object-Oriented Module Example Source: https://github.com/ldgerrits/bootstrapper/blob/main/_autodocs/method-invocation.md Shows an object-oriented module pattern using colon notation for methods like ':new', ':addScore', and ':advance'. Each method operates on the module's state through 'self'. ```lua -- GameState.lua local GameState = {} function GameState:new() local self = setmetatable({}, { __index = GameState }) self.score = 0 self.level = 1 self.items = {} return self end function GameState:addScore(points) self.score = self.score + points end function GameState:advance() self.level = self.level + 1 end function GameState:getStatus() return `Level {self.level}, Score {self.score}` end return GameState ``` ```lua local Bootstrapper = require(packages.Bootstrapper) local gameState = Bootstrapper.loadSequence({ GameState }) -- Each call has access to self.score, self.level, etc. Bootstrapper.run(gameState, ':addScore', 100) Bootstrapper.run(gameState, ':advance') ``` -------------------------------- ### Filtered Recursive Loading Examples Source: https://github.com/ldgerrits/bootstrapper/blob/main/_autodocs/module-loading.md Demonstrates filtering ModuleScript descendants during recursive loading. One example loads modules ending with 'System', and another loads modules only within a 'Combat' folder. ```lua local Bootstrapper = require(packages.Bootstrapper) -- Load only modules ending with "System" local systems = Bootstrapper.loadDescendants( parent, Bootstrapper.byName('System$') ) -- Load only modules in Combat folder local combatFilter = function(moduleScript: ModuleScript): boolean return moduleScript:FindFirstAncestorOfClass('Folder').Name == 'Combat' end local combatSystems = Bootstrapper.loadDescendants(parent, combatFilter) ``` -------------------------------- ### Synchronous Module Initialization Sequence Source: https://github.com/ldgerrits/bootstrapper/blob/main/_autodocs/execution-modes.md Use `Bootstrapper.run()` to initialize modules in a strict, sequential order, ensuring dependencies are met before proceeding. This is ideal for setting up game state or services that rely on each other. ```lua local Bootstrapper = require(packages.Bootstrapper) -- Define initialization order local bootSequence = Bootstrapper.loadSequence({ DatabaseService, -- Initialize database first PlayerService, -- Then load players (needs database) InventoryService, -- Then load inventories (needs players) GameStateService, -- Finally setup game state (needs inventory) }) -- Run in sequence, yielding until complete local loaded, errors = Bootstrapper.run(bootSequence, ':init') if errors then error("Initialization failed!") end -- Continue with other startup code print("All services initialized") Game:LoadCustomPlace() ``` -------------------------------- ### Initialize, Load, Run Services Sequentially Source: https://github.com/ldgerrits/bootstrapper/blob/main/_autodocs/execution-modes.md This pattern demonstrates a sequential initialization process for services. It first loads a sequence of services, then runs their initialization blocking, followed by concurrent asset loading, and finally asynchronous startup and heartbeat binding. ```lua local Bootstrapper = require(packages.Bootstrapper) local services = Bootstrapper.loadSequence({ DataService, PlayerService, GameService, }) -- 1. Sequential initialization (blocking) Bootstrapper.run(services, ':init') -- 2. Parallel asset loading (non-blocking) Bootstrapper.runConcurrent(services, '.loadAssets') -- 3. Sequential startup (non-blocking) Bootstrapper.runAsync(services, ':start') -- 4. Hook to update loop Bootstrapper.bindToHeartbeat(services, ':update') ``` -------------------------------- ### Coroutine/Async Pattern Concurrent Loading Source: https://github.com/ldgerrits/bootstrapper/blob/main/_autodocs/method-invocation.md Start concurrent asynchronous operations using Bootstrapper.runConcurrent with a method like ':startLoad'. ```lua Bootstrapper.runConcurrent(loaders, ':startLoad') ``` -------------------------------- ### Service Pattern (OOP) Initialization Source: https://github.com/ldgerrits/bootstrapper/blob/main/_autodocs/method-invocation.md Use this pattern for object-oriented services that manage state. Initialize services using Bootstrapper.run with the ':init' method. ```lua local DataService = {} function DataService:init() self.data = {} end function DataService:loadData(source) self.data = source.getData() end function DataService:getData(key) return self.data[key] end return DataService ``` ```lua Bootstrapper.run(services, ':init') ``` -------------------------------- ### Pass Arguments to Bootstrapper.run Source: https://github.com/ldgerrits/bootstrapper/blob/main/_autodocs/quick-reference.md Demonstrates how to pass zero, one, or multiple arguments to the Bootstrapper.run function. Arguments are received by the module's init function. ```lua -- No arguments Bootstrapper.run(modules, ':init') -- Single argument Bootstrapper.run(modules, ':init', config) -- Multiple arguments Bootstrapper.run(modules, ':init', config, debug) -- In module: function Module:init(config, debug) self.config = config self.debug = debug end ``` -------------------------------- ### Using Events with Bootstrapper Source: https://github.com/ldgerrits/bootstrapper/blob/main/_autodocs/types.md Shows how to use Bootstrapper.bindTo with both Signal objects and subscription functions. ```lua -- Using as a Signal local cleanup1 = Bootstrapper.bindTo(systems, '.onUpdate', instance.Changed) -- Using as a subscription function local cleanup2 = Bootstrapper.bindTo(systems, '.onTick', function(callback) local connection = RunService.Heartbeat:Connect(callback) return connection -- Task to clean up end) ``` -------------------------------- ### Mixed Module Usage Source: https://github.com/ldgerrits/bootstrapper/blob/main/_autodocs/method-invocation.md Demonstrates how to bootstrap modules that contain both instance methods (colon notation) and static functions (dot notation). ```lua local System = {} -- Configuration (static access) System.name = "MySystem" System.priority = 1 -- Initialization (uses self) function System:init() self.isRunning = false self.updateCount = 0 end -- Setup (uses self) function System:setup(config) self.config = config end -- Update loop (uses self) function System:update(deltaTime) if self.isRunning then self.updateCount = self.updateCount + 1 end end -- Utility function (static, no self) function System.getSystemInfo() return System.name end return System ``` ```lua -- Mixed usage Bootstrapper.run(systems, ':init') -- Method call Bootstrapper.run(systems, ':setup', config) -- Method call with args Bootstrapper.bindToHeartbeat(systems, ':update') -- Method binding Bootstrapper.run(systems, '.getSystemInfo') -- Static call ``` -------------------------------- ### Bootstrapper Assertions and Constraints Source: https://github.com/ldgerrits/bootstrapper/blob/main/_autodocs/quick-reference.md Illustrates how Bootstrapper enforces constraints on function arguments and usage. For example, intervals must be positive, and certain functions are client-only. ```lua -- Interval must be > 0 Bootstrapper.bindToInterval(modules, ':tick', 1.0) -- OK -- Bootstrapper.bindToInterval(modules, ':tick', 0) -- ERROR -- Cannot use Stepped with interval -- Bootstrapper.bindToInterval(modules, ':tick', 1.0, RunService.Stepped) -- ERROR -- Client-only functions if not RunService:IsClient() then -- Don't call bindToRenderStep or bindToPreRender on server end ``` -------------------------------- ### Bootstrapper Execution Modes Source: https://github.com/ldgerrits/bootstrapper/blob/main/_autodocs/quick-reference.md Compares the three main execution modes: run(), runAsync(), and runConcurrent(). Use run() for sequential initialization with dependencies, runAsync() for non-blocking long tasks, and runConcurrent() for independent parallel tasks. ```plaintext run(): - Sequential execution - Yields until complete - Returns results and errors - Best for: Initialization with dependencies runAsync(): - Sequential execution - Non-blocking background - No return value - Best for: Long initialization, non-blocking runConcurrent(): - Parallel execution - Non-blocking - No return value - Best for: Independent tasks ``` -------------------------------- ### Best Practice: Document Calling Convention Source: https://github.com/ldgerrits/bootstrapper/blob/main/_autodocs/method-invocation.md Clearly document the expected calling convention (colon for stateful, dot for functional) in comments to guide users. ```lua -- GOOD: Document in comments local Service = {} -- Stateful service methods (call with colon) function Service:init() ... end function Service:update(dt) ... end -- Utility functions (call with dot) function Service.validate(data) ... end return Service ``` -------------------------------- ### Luau Configuration and Defaults Source: https://github.com/ldgerrits/bootstrapper/blob/main/_autodocs/MANIFEST.txt Shows how to configure the Bootstrapper library and set default values. Proper configuration ensures the library behaves as expected. ```luau -- Setting configuration options bootstrapper.configure({ timeout = 5000, retries = 3 }) -- Using default values local defaultConfig = bootstrapper.getDefaults() ``` -------------------------------- ### Lifecycle Methods for Object-Oriented Services Source: https://github.com/ldgerrits/bootstrapper/blob/main/_autodocs/method-invocation.md Defines common lifecycle methods like 'new', 'init', 'start', 'update', and 'shutdown' for services using colon notation. ```lua local Service = {} function Service:new() local self = setmetatable({}, { __index = Service }) self.initialized = false return self end function Service:init() self.initialized = true end function Service:start() self:loadData() end function Service:update(deltaTime) -- Update logic end function Service:shutdown() self.initialized = false end return Service ``` ```lua -- Bootstrap with colon notation Bootstrapper.run(services, ':init') Bootstrapper.runAsync(services, ':start') Bootstrapper.bindToHeartbeat(services, ':update') ``` -------------------------------- ### Bootstrapper Simple Initialization Pattern Source: https://github.com/ldgerrits/bootstrapper/blob/main/_autodocs/quick-reference.md A basic pattern for initializing services by loading all children of a parent, running an ':init' method on them, and binding a ':update' method to the heartbeat. ```lua local Bootstrapper = require(packages.Bootstrapper) local services = Bootstrapper.loadChildren(parent) Bootstrapper.run(services, ':init') Bootstrapper.bindToHeartbeat(services, ':update') ``` -------------------------------- ### Custom Execution Chains with Bootstrapper Source: https://github.com/ldgerrits/bootstrapper/blob/main/_autodocs/configuration.md Manages module initialization and execution using sequential, asynchronous, or concurrent patterns. ```lua local Bootstrapper = require(packages.Bootstrapper) local services = Bootstrapper.loadSequence(bootOrder) -- Sequential, blocking initialization Bootstrapper.run(services, ':init') -- Sequential, non-blocking startup Bootstrapper.runAsync(services, ':start') -- Concurrent independent tasks Bootstrapper.runConcurrent(services, ':loadAssets') -- Bind to lifecycle Bootstrapper.bindToHeartbeat(services, ':update') Bootstrapper.bindToPostSimulation(services, ':postStep') ``` -------------------------------- ### Choose Appropriate Execution Mode for Tasks Source: https://github.com/ldgerrits/bootstrapper/blob/main/_autodocs/configuration.md Select the correct `Bootstrapper.run` mode based on task requirements. Use `run` for sequential, yielding execution, `runConcurrent` for independent tasks that run in parallel, and `runAsync` for background initialization that maintains order. ```lua -- GOOD: Sequential for dependent tasks Bootstrapper.run(services, ':init') -- yields until done -- GOOD: Concurrent for independent tasks Bootstrapper.runConcurrent(systems, '.loadAssets') -- concurrent, doesn't yield -- GOOD: Async for long-running initialization Bootstrapper.runAsync(services, ':preload') -- background, maintains order ``` -------------------------------- ### Sorting with Nested Paths Example Source: https://github.com/ldgerrits/bootstrapper/blob/main/_autodocs/module-loading.md Illustrates how `loadDescendants` sorts modules with identical names by their full path. Modules in the 'Combat' folder are loaded before those in 'Movement' when both have a module named 'Damage'. ```lua -- Folder structure: -- Systems/ -- Combat/ -- Damage -- Movement/ -- Damage -- loadDescendants results (both named "Damage", sorted by path): -- [1] Damage (from Combat/ — Combat < Movement alphabetically) -- [2] Damage (from Movement/) ``` -------------------------------- ### Bootstrapper Run Syntax with Dot Notation Source: https://github.com/ldgerrits/bootstrapper/blob/main/_autodocs/method-invocation.md Use this syntax to call a method as a static function. Arguments can be passed after the method name. ```lua Bootstrapper.run(modules, '.methodName') Bootstrapper.run(modules, '.methodName', arg1, arg2) ``` -------------------------------- ### Best Practice: Handle Missing Methods Gracefully Source: https://github.com/ldgerrits/bootstrapper/blob/main/_autodocs/method-invocation.md Bootstrapper silently skips non-existent methods, which is often acceptable. Document optional methods for clarity. ```lua -- In Bootstrapper, if a method doesn't exist, it's silently skipped -- This is fine: function Module:init() ... end -- This also works (no error if 'update' doesn't exist): Bootstrapper.bindToHeartbeat(modules, ':update') -- But for clarity, document which methods are optional ``` -------------------------------- ### Reuse Loaded Module Arrays Source: https://github.com/ldgerrits/bootstrapper/blob/main/_autodocs/module-loading.md Load module arrays once and reuse them for multiple operations like initialization, starting, and updating. This is more efficient than repeatedly calling `loadSequence` for the same set of modules. ```lua -- GOOD: Load once, use multiple times local services = Bootstrapper.loadSequence(sequence) Bootstrapper.run(services, ':init') Bootstrapper.runAsync(services, ':start') Bootstrapper.bindToHeartbeat(services, ':update') -- INEFFICIENT: Reload multiple times Bootstrapper.run(Bootstrapper.loadSequence(sequence), ':init') Bootstrapper.runAsync(Bootstrapper.loadSequence(sequence), ':start') ``` -------------------------------- ### Parallel Asset Loading with runConcurrent Source: https://github.com/ldgerrits/bootstrapper/blob/main/_autodocs/execution-modes.md Use runConcurrent to load multiple assets simultaneously. Each loader starts in its own thread, enabling faster overall loading times for independent assets. ```lua local Bootstrapper = require(packages.Bootstrapper) local loaders = Bootstrapper.loadChildren( game.ReplicatedStorage.AssetLoaders, Bootstrapper.byName('Loader$') ) -- All loaders start simultaneously -- Each loads a different type of asset in parallel Bootstrapper.runConcurrent(loaders, '.load') print("All assets loading in parallel...") game:WaitForChild("AssetsLoaded") -- Signal when all done ``` -------------------------------- ### Manual Module Sequences with Bootstrapper Source: https://github.com/ldgerrits/bootstrapper/blob/main/README.md Defines a manual initialization order for modules using an array of ModuleScript instances. The resulting services array can then be used for various lifecycle stages. ```lua local services, errors = Bootstrapper.loadSequence({ path.to.DataService, path.to.PlayerService, path.to.AssetService, }) -- Use the resulting services array for everything else Bootstrapper.run(services, '.init') ``` -------------------------------- ### Document Load Order for Manual Sequences Source: https://github.com/ldgerrits/bootstrapper/blob/main/_autodocs/module-loading.md Clearly document the rationale behind the load order in manual sequences, especially when services have explicit dependencies. This improves understanding of the boot-up process and dependency management. ```lua local Bootstrapper = require(packages.Bootstrapper) -- GOOD: Document WHY this order local bootSequence = Bootstrapper.loadSequence({ ConfigService, -- Load config first, other services depend on it DatabaseService, -- DB needs config, other services need DB PlayerService, -- Needs database InventoryService, -- Needs players GameStateService, -- Needs everything above }) -- This makes it clear what dependencies exist ``` -------------------------------- ### Lua Type Definition: LoadedModule Source: https://github.com/ldgerrits/bootstrapper/blob/main/_autodocs/types.md Defines a loaded Lua module as a table with string keys and any type of values. Modules should contain functions like init, start, and onUpdate. ```lua type LoadedModule = { [string]: any } ``` -------------------------------- ### Handle Module Method Throwing Exception with Bootstrapper Source: https://github.com/ldgerrits/bootstrapper/blob/main/_autodocs/errors-and-troubleshooting.md Catch and report errors thrown by module methods during execution. This example demonstrates how Bootstrapper collects errors and allows execution to continue for other modules. ```lua local Module = {} function Module:update() local part = nil part:GetChildren() -- ERROR: nil doesn't have GetChildren end return Module ``` ```lua local Bootstrapper = require(packages.Bootstrapper) local modules = Bootstrapper.loadSequence({Module}) -- Errors are collected and returned local loaded, errors = Bootstrapper.run(modules, ':update') if errors then for moduleName, errorMsg in pairs(errors) do print(`{moduleName} failed during update:`) print(` {errorMsg}`) end end -- Execution continues despite errors -- successfully loaded modules in 'loaded' array ``` -------------------------------- ### Handle Module Missing Method with Bootstrapper Source: https://github.com/ldgerrits/bootstrapper/blob/main/_autodocs/errors-and-troubleshooting.md Check if a module's method exists before calling it to prevent silent failures. This example iterates through loaded modules and warns if the 'init' method is not a function. ```lua local Bootstrapper = require(packages.Bootstrapper) local module = { name = 'MyModule' } -- No 'init' method -- This succeeds silently, but init is NOT called Bootstrapper.run({module}, ':init') -- Result: module.name is 'MyModule', no error thrown ``` ```lua -- Ensure method exists before calling local Bootstrapper = require(packages.Bootstrapper) local modules = Bootstrapper.loadChildren(parent) -- Check if method exists for _, module in ipairs(modules) do if typeof(module.init) ~= 'function' then warn(`Module missing init method`) end end Bootstrapper.run(modules, ':init') ``` -------------------------------- ### Bootstrapper Method Invocation Source: https://github.com/ldgerrits/bootstrapper/blob/main/_autodocs/quick-reference.md Demonstrates different ways to invoke methods on modules using Bootstrapper.run, including static, instance, and default methods, with and without arguments. ```lua Bootstrapper.run(modules, '.method') -- Static: module.method(...) Bootstrapper.run(modules, ':method') -- Method: module:method(...) Bootstrapper.run(modules, 'method') -- Method: module:method(...) (default) Bootstrapper.run(modules, '.method', arg1, arg2) -- With arguments ``` -------------------------------- ### Bootstrapper Module Calling Conventions Source: https://github.com/ldgerrits/bootstrapper/blob/main/_autodocs/configuration.md Demonstrates various ways to call module functions using Bootstrapper.run, controlling 'self' parameter passing. ```lua local Bootstrapper = require(packages.Bootstrapper) local module = Bootstrapper.loadSequence({ MyModule }) -- Call as method (self is passed) Bootstrapper.run(module, ':init') -- self is passed, prints "MyModule" Bootstrapper.run(module, 'init') -- equivalent to above Bootstrapper.run(module, 'MyModule:init') -- module.init(module) -- Call as static function (self is NOT passed) Bootstrapper.run(module, '.start') -- no self, prints "Starting" ``` -------------------------------- ### Progressive Loading with runAsync() Source: https://github.com/ldgerrits/bootstrapper/blob/main/_autodocs/execution-modes.md Initiates loading of optional systems in the background using runAsync() while critical systems are set up synchronously. Allows the main thread to handle events like player connections concurrently. ```lua local Bootstrapper = require(packages.Bootstrapper) local systemsFolder = game.ServerScriptService.Systems local systems = Bootstrapper.loadChildren(systemsFolder) -- Start loading critical systems Bootstrapper.run(systems, ':setupCore') -- Start optional systems in background Bootstrapper.runAsync(systems, ':setupOptional') -- Can continue to next phase immediately local players = game:GetService("Players") players.PlayerAdded:Connect(function(player) -- Handle new players while async setup continues end) ``` -------------------------------- ### Bootstrapper.runAsync Source: https://github.com/ldgerrits/bootstrapper/blob/main/_autodocs/api-reference.md Calls methods sequentially in a background thread, maintaining order without yielding the caller. Useful for initialization tasks that should complete but don't need to block gameplay. ```APIDOC ## Bootstrapper.runAsync(modules: { Instance | ModulePath | LoadedModule }, methodName: string, ...: any): () ### Description Calls methods sequentially in a background thread, maintaining order without yielding the caller. Useful for initialization tasks that should complete but don't need to block gameplay. The module itself is passed as `self` by default, or can be called as a static function using '.' prefix. Additional arguments can be passed to the method. ### Parameters #### Path Parameters - **modules** (Instance | ModulePath | LoadedModule) - Required - Array of modules to execute - **methodName** (string) - Required - Method name, prefixed with '.' to call without self, or ':' (default) to inject self - **...** (any) - Required - Additional arguments passed to each method ### Returns - **()** - Returns immediately (void) ### Request Example ```lua local Bootstrapper = require(packages.Bootstrapper) -- Start initialization in background Bootstrapper.runAsync(services, ':start') -- Continue with other startup code immediately print("Services starting in background...") game:WaitForChild("Loaded") ``` ``` -------------------------------- ### Load Modules Using String Paths Source: https://github.com/ldgerrits/bootstrapper/blob/main/_autodocs/module-loading.md Use this when you want to load modules by their string path. Bootstrapper will call `require()` with the provided string path. ```lua local Bootstrapper = require(packages.Bootstrapper) local modules = Bootstrapper.loadSequence({ 'game.ServerScriptService.Services.Service1', 'game.ServerScriptService.Services.Service2', }) ```