A module that loads and executes ModuleScripts from either ServerScriptService or ReplicatedStorage and stores it into global variable "shared" with its contents depend on runtime context (Client or Server).
-
Loads modules dynamically, only when needed.
-
Loaded ModuleScripts implement lifecycle methods (hooks):
onModuleSetup(synchronous) andonModuleStart(asynchronous). -
Follows a specific design pattern when making ModuleScripts for the Client or Server but doesn't dictate the way you script.
-
Allows for both global (
shared) and local (ModuleContainer) module storage, depending on whether the module should be available globally or locally. -
Allows only loading module scripts from specific Instances' descendants.
-
Uses
xpcallandpcallfor safe module requiring to prevent the module loader from failing, with error handling that logs any failures to load modules. -
Supports loading modules from
ObjectValueinstances that point toModuleScriptinstances. -
Errors during lifecycle execution will not halt the module loader
To use the rbxmoduleloader stock, you will need to call it with no options. This module can be loaded either as a server or client-side script, and that'll dictate what module scripts it will load.
Using the ModuleLoader for the Client
- Create a
ScriptinReplicatedStorageand set itsRunContexttoClientso that it'll run inReplicatedStorage. Copy and paste, enable this script and update require path if needed.
Note
You can rewrite this below as a one-liner since the Script only exists for one purpose: Loading modules.
--!strict
local ReplicatedStorageService = game:GetService("ReplicatedStorage")
require(ReplicatedStorageService.MainModule)()Take note of its RunContext: Client. This will load the modules found in ReplicatedStorage and store them in the shared global variable, making them globally accessible on other kinds of scripts for the client.
- Make a
ModuleScriptinsideReplicatedStoragethat follows the design pattern:
return {
onModuleSetup = function()
print("onModuleSetup: " .. script.Name)
end,
onModuleStart = function()
print("onModuleStart: " .. script.Name)
end,
}Using the ModuleLoader for the Server
- Similarly, create a
ScriptinReplicatedStorageand set itsRunContexttoServerso that it'll run inReplicatedStorage. Copy and paste, enable this script and update require path if needed.
Note
You can rewrite this below as a one-liner since the Script only exists for one purpose: Loading modules.
--!strict
local ReplicatedStorageService = game:GetService("ReplicatedStorage")
require(ReplicatedStorageService.MainModule)()Take note of its RunContext: Server. This will load the modules found in ServerScriptService and store them in the shared global variable, making them globally accessible on other kinds of scripts for the server.
- Make a
ModuleScriptinsideServerScriptServicethat follows the design pattern:
return {
onModuleSetup = function()
print("onModuleSetup: " .. script.Name)
end,
onModuleStart = function()
print("onModuleStart: " .. script.Name)
end,
}- Try running the game! You should see a similar output on console:
x:x:x onModuleSetup: ModuleScript - Server - ModuleScript:3
x:x:x onModuleStart: ModuleScript - Server - ModuleScript:6
x:x:x onModuleSetup: ModuleScript - Client - ModuleScript:3
x:x:x onModuleStart: ModuleScript - Client - ModuleScript:6
For more information about the design patterns, please see lifecycle methods
The LoadModulesOptions allows you to configure the loader's behavior. This can be omitted or passed as an argument to the rbxmoduleloader function when you require it.
_shared (optional)
Type: boolean?Default: trueDescription: Determines if the loaded modules should be stored in theshareddictionary table (accessible globally) or in an isolated local dictionary table (child ofrbxmoduleloaderwhich is "ModuleContainer"). When_sharedis true, the modules are stored in the global shared table, meaning they can be accessed anywhere in the game depending on the runtime context.
Example Usage:
Note
For this example, write this as a LocalScript inside StarterPlayer -> StarterPlayerScripts
This will load all ModuleScripts inside ReplicatedStorage.
local ReplicatedStorageService = game:GetService("ReplicatedStorage")
local loadModules = require(ReplicatedStorageService.MainModule)
loadModules({ _shared = true })targetInstances (optional)
Type: { Instance }?Default: nilDescription: Specifies the list of instances whose descendants should be processed for module loading. If not provided, the loader will scan all descendants of the appropriate service based on the runtime environment (client or server):- Server
- ServerScriptService
- Client
- ReplicatedStorage
Example Usage:
Note
For this example, write this as a Server Script in ServerScriptService
This will load all ModuleScripts inside ServerScriptService and ServerStorage.
local ReplicatedStorageService = game:GetService("ReplicatedStorage")
local ServerScriptService = game:GetService("ServerScriptService")
local ServerStorageService = game:GetService("ServerStorage")
local loadModules = require(ReplicatedStorageService.MainModule)
loadModules({
targetInstances = { ServerScriptService, ServerStorageService }
})The loader supports two lifecycle methods that will be invoked in this order on the modules after they are loaded (required):
-
onModuleSetup(): () -> ()Description: This method is called synchronously for each module after it is loaded.Purpose: Use this to perform setup tasks on the module, like initializing variables or setting properties.
-
onModuleStart(): () -> ()Description: This method is called asynchronously for each module after the setup phase.Purpose: Use this to trigger the start of the module, such as initiating processes that may involve waiting or other asynchronous tasks.
With that in mind, instead of using LocalScripts or Scripts, use ModuleScripts for both the Client or Server that follows the design pattern:
-
The module script returns a table.
-
The table contains the keys
onModuleSetupandonModuleStart. -
Each key maps to an anonymous function (closure).
-
onModuleSetup()andonModuleStart()are callable functions exposed by the module.
ModuleScript Examples
Note
These are just shorthand example codes for demonstration.
1 Inline Anonymous Functions
return {
onModuleSetup = function()
print("onModuleSetup: " .. script.Name)
end,
onModuleStart = function()
print("onModuleStart: " .. script.Name)
end,
}Here are other verbose versions of writing but follows the design pattern:
2 Assigned Anonymous Functions
local module = {}
module.onModuleSetup = function()
print("onModuleSetup: " .. script.Name)
end
module.onModuleStart = function()
print("onModuleStart: " .. script.Name)
end
return module3 Syntactic Sugar: Named Table Functions
local module = {}
function module.onModuleSetup()
print("onModuleSetup: " .. script.Name)
end
function module.onModuleStart()
print("onModuleStart: " .. script.Name)
end
return module4 Local Named Functions then Assigned
local module = {}
local function ModuleOnModuleSetup()
print("onModuleSetup: " .. script.Name)
end
local function ModuleOnModuleStart()
print("onModuleStart: " .. script.Name)
end
module.onModuleSetup = ModuleOnModuleSetup
module.onModuleStart = ModuleOnModuleStart
return module5 Named Locals, Returned in Table
local function ModuleOnModuleSetup()
print("onModuleSetup: " .. script.Name)
end
local function ModuleOnModuleStart()
print("onModuleStart: " .. script.Name)
end
return {
onModuleSetup = ModuleOnModuleSetup,
onModuleStart = ModuleOnModuleStart,
}6 Local Variables with Anonymous Functions
local module = {}
local ModuleOnModuleSetup, ModuleOnModuleStart
ModuleOnModuleSetup = function()
print("onModuleSetup: " .. script.Name)
end
ModuleOnModuleStart = function()
print("onModuleStart: " .. script.Name)
end
module.onModuleSetup = ModuleOnModuleSetup
module.onModuleStart = ModuleOnModuleStart
return module7 Local Variables with Anonymous Functions but now embedded in a table.
local ModuleOnModuleSetup, ModuleOnModuleStart
ModuleOnModuleSetup = function()
print("onModuleSetup: " .. script.Name)
end
ModuleOnModuleStart = function()
print("onModuleStart: " .. script.Name)
end
return {
onModuleSetup = ModuleOnModuleSetup,
onModuleStart = ModuleOnModuleStart,
}