!!! BE AWARE: THIS METHOD CAUSES FUNCTION HINTS TO BREAK DUE TO DYNAMICALLY FETCHING MODULE PATHS AT RUNTIME !!!
When you move a module to another folder, you have to change its path everywhere.
How annoying…
If your code looks like this:
local MyModule = require(ServerStorage.MyModulesFolder_1.MyModulesFolder_2.MyModule)
And you find it annoying, as I mentioned before, you can shorten all of it to this:
local MyModule = modules.MyModule
By using a simple ModuleLoader.
All you have to do is create a ModuleScript in ReplicatedStorage called “LoaderService”.
local LoaderService = {}
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local FOLDERS_ORDER = {
"DataBaseModules",
"ServicesModules",
"ControllersServerModules",
}
function LoaderService.LoadModules(ModulesFolder: Folder): { [string]: any }
local modules = {}
for _, folderName in ipairs(FOLDERS_ORDER) do
local folder = ModulesFolder:WaitForChild(folderName)
for _, module in pairs(folder:GetDescendants()) do
if module:IsA("ModuleScript") then
local success, result = pcall(require, module)
if success then
modules[module.Name] = result
print(("[MODULE_LOADER] %s loaded successfully"):format(module.Name))
else
warn("Error requiring module:", module.Name, "-", result)
end
end
end
end
return modules
end
function LoaderService.LoadRemotes(): ({ [string]: RemoteEvent }, { [string]: RemoteFunction })
local remoteEvents = {}
local remoteFunctions = {}
for _, remote in pairs(ReplicatedStorage:GetDescendants()) do
if remote:IsA("RemoteEvent") then
remoteEvents[remote.Name] = remote
elseif remote:IsA("RemoteFunction") then
remoteFunctions[remote.Name] = remote
end
end
return remoteEvents, remoteFunctions
end
return LoaderService
You need to create 3 folders in ServerStorage called:
- DataBaseModules – modules that store data for your game, no functions
- ServicesModules – modules that do the work for controllers
- ControllersServerModules – modules that control game flow
Then in ServerStorage, create a ModuleScript called “ModuleLoader”. It will store all paths for your game.
local ModuleLoader = {}
ModuleLoader.Modules = {}
ModuleLoader.RemoteEvents = {}
ModuleLoader.RemoteFunctions = {}
return ModuleLoader
In your main script in ServerScriptService, you need to initialize it:
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local ServerStorage = game:GetService("ServerStorage")
-----------------------------
-- [LOADER]
-----------------------------
local LoaderService = require(ReplicatedStorage:WaitForChild("LoaderService"))
local ModulesServer = ServerStorage.ModulesServer
local ModuleLoader = require(ServerStorage.ModuleLoader)
ModuleLoader.RemoteEvents, ModuleLoader.RemoteFunctions = LoaderService.LoadRemotes()
ModuleLoader.Modules = LoaderService.LoadModules(ModulesServer)
-----------------------------
-- [MODULES]
-----------------------------
local Modules = ModuleLoader.Modules
for moduleName, module in pairs(Modules) do
if type(module) == "table" and module.Init then
module.Init(Modules)
print(("[MODULE_INIT] %s initialized"):format(moduleName))
else
warn(("[MODULE_INIT] %s does not have an Init function"):format(moduleName))
end
end
--Here you can use all modules this way
local MyModule_1 = Modules.MyModule_1
local MyModule_2 = Modules.MyModule_2
...
local MyModule_n = Modules.MyModule_n
Now, when you need to use it in a ModuleScript, you can simply do this:
local ServerStorage = game:GetService("ServerStorage")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local MyModule_1 = {}
-----------------------------
-- [MODULES]
-----------------------------
local MyModule_2
local MyModule_3
local MyModule_4
local MyModule_5
function MyModule_1.Init(modules)
MyModule_2 = modules.MyModule_2
MyModule_3 = modules.MyModule_3
MyModule_4 = modules.MyModule_4
MyModule_5 = modules.MyModule_5
end
----------------------------------------
-- [REMOTE_EVENTS & REMOTE_FUNCTIONS]
----------------------------------------
local ModuleLoader = require(ServerStorage.ModuleLoader)
local RemoteEvents = ModuleLoader.RemoteEvents
local RemoteFunctions = ModuleLoader.RemoteFunctions
local MyRemote_Event_1 = RemoteEvents.MyRemote_Event_1
local MyRemote_Event_2 = RemoteEvents.MyRemote_Event_2
local MyRemote_Function_1 = RemoteFunctions.MyRemote_Function_1
local MyRemote_Function_2 = RemoteFunctions_MyRemote_Function_2
This method helps me avoid tracking module paths and lets me change them freely.
EDIT_1
It helped me a lot while refactoring the code
It will not be too good in any other scenario ![]()