I understand that global variables on highly frowned upon in the roblox development community, but if all of my studio members are okay with using them I don’t see an issue. My usage is to make a library importer that can work for any script. This is how its used.
local module = shared.import("ModuleName")
I much prefer this to inputting the entire directory into the require() function because I frequently change folder names and how my scripts are set up, I’m also used to python environments so this makes code feel more natural to me. The only downside is that the auto predict is lost but I’m considering making a vscode extension that will bring it back.
Is there anything that will actually make development more difficult with my approach besides global variables just being “bad” or “ugly”.
Also in terms of performance, this is with 10,000 iterations so I’d say its negligible.
Just make sure that there is only one point of entry into your codebase on the server and one on the client. This way, you can assure that you set the import function before it gets accessed anywhere.
This isn’t awful, the only problem is that with a global namespace like this external code could also set the “import” key to something else, leading to a conflict, but as long as you keep this in mind when using other people’s libraries, you should be fine.
Some other people make the import function a module and require that from a predictable location instead, but I understand why you’d go for this approach.
So I plan on having a module script that will have this import function, and at the point of entry in both server and client they will require this module, that way making sure there will never be a conflict
I do this sometimes, but I’ve found that I like to sort of do the structuring myself so I can extend my code easier. This is how I’ve been doing it lately (and I’ve started liking this a lot). I have a module named “Directory” which is a fancy function which will return certain things with a path name.
Sometimes I put the result of the module in shared or _G (fun fact: two different tables with different values). Sometimes I copy and paste two lines to require it from somewhere like ReplicatedStorage.
I made a module that requires other modules for me, and it lazy loads them, so it doesn’t require any of the modules until I want it to
I have this in my main script on both server and client
local Quire = require(game:GetService("ReplicatedStorage"):WaitForChild("Shared").Quire)
_G.Quire = Quire
and this allows me to retrieve it easily in other scripts
local Quire = _G.Quire
local SomeModule = Quire("SomeModule")
--[[
simplified requiring of modules
use: local module = Quire(moduleName)
searches if there is already a module cached in cachedRequiredModules, if there it's returned, otherwise it will iterate through
the ancestorsToCheck table, if it's found it returns the module and caches it
--]]
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local ServerScriptService = game:GetService("ServerScriptService")
local RunService = game:GetService("RunService")
local isServer = RunService:IsServer()
local ancestorsToCheck = {ReplicatedStorage:WaitForChild("Shared")}
local cachedRequiredModules = {}
if isServer then
cachedRequiredModules["DataStore2"] = require(ServerScriptService.DataStore2)
-- all the places to check for server modules
table.insert(ancestorsToCheck, ServerScriptService.Server)
else
-- all the places to check for client modules
table.insert(ancestorsToCheck, ReplicatedStorage:WaitForChild("ClientModules"))
end
local Quire = {
__call = function(_, moduleName)
local module = cachedRequiredModules[moduleName]
if not module then -- no module found, searching for it
for _, ancestorToCheck in ipairs(ancestorsToCheck) do
local foundModule = ancestorToCheck:FindFirstChild(moduleName, true)
if foundModule then -- module found, returning it
module = require(foundModule)
cachedRequiredModules[moduleName] = module
break
end
end
end
return module
end
}
setmetatable(Quire, Quire)
return Quire
I’d say it’s worth doing, if it saves you time and makes things easier, why wouldn’t you do it?
Edit: might of misunderstood your post, might just be a opinion, but depending on how much variables you do it for, you will probably end up forgetting them and that could cause confusion
That’s actually the same thing I’m doing, I have a module called import which returns the import function (forgot I could make a metatable __call) and then I just set shared.import to that module.
One annoying thing about this is that most vscode extensions block _G and shared because they don’t like it so I might switch back to doing things in roblox studio.
Dirtying up your global environment is not needed and if proceeded down this path it can be tricky having control of what parts of your code can access this and what’s stored within it st all times. It’s good to keep your code de coupled as possible.
Probably works for small projects. However, the model quickly breaks if you plan to include third party modules which are unaware of your naming scheme.
You could have separate inclusion models for different parts of your code, but that sort of inconsistency often leads to bugs.
That said, I have a utility require as well that leverages loadstring when script is nil. This allows me to make changes and test without having to press play.