Why Nexus Project
Simplified Requires
The primary goal of Nexus Project is to reduce
the complexity of requiring ModuleScripts.
Using a Folder in ReplicatedStorage with a
set of ModuleScripts and other instances would
look like this:
--[[ Without Nexus Project. --]] local ClientModules = game:GetService("ReplicatedStorage"):WaitForChild("ClientModules") local UICreator = require(Project:WaitForChild("UICreator")) local ColorUtil = require(Project:WaitForChild("Util"):WaitForChild("ColorUtil")) local TweenUtil = require(Project:WaitForChild("Util"):WaitForChild("TweenUtil")) local DefaultColors = require(Project:WaitForChild("Data"):WaitForChild("UI"):WaitForChild("DefaultColors")) --[[ With Nexus Project. --]] --Create the base project. local NexusProject = require(game:GetService("ReplicatedStorage"):WaitForChild("NexusProject")) local Project = NexusProject.new(game:GetService("ReplicatedStorage"):WaitForChild("ClientModules")) --Require several modules. local UICreator = Project:GetResource("UICreator") local ColorUtil = Project:GetResource("Util.ColorUtil") local TweenUtil = Project:GetResource("Util.TweenUtil") local DefaultColors = Project:GetResource("Data.UI.DefaultColors")
Non-Module Resources
Along with ModuleScripts, other data can be
retrieved or stored. This is useful for other
Roblox instances, as well as configurable items
or constants.
--Create the base project. local NexusProject = require(game:GetService("ReplicatedStorage"):WaitForChild("NexusProject")) local Project = NexusProject.new(game:GetService("ReplicatedStorage"):WaitForChild("ClientModules")) --Store some values. Project:SetResource("Constants.ConfirmColor",Color3.new(0,1,0)) Project:SetResource("Constants.CancelColor",Color3.new(1,0,0)) --Get the values. local BaseButtonObject = Project:GetResource("Base.UI.Buttton") local ConfirmColor = Project:GetResource("Constants.ConfirmColor") local CancelColor = Project:GetResource("Constants.CancelColor") local ConfirmButtonBase,CancelButtonBase = BaseButtonObject:Clone(),BaseButtonObject:Clone() ConfirmButtonBase.BackgroundColor3,CancelButtonBase.BackgroundColor3 = ConfirmColor,CancelColor
Custom Base Paths
A project may store objects in different places. All of these can be combined into a single project.
--Create the base project. local NexusProject = require(game:GetService("ReplicatedStorage"):WaitForChild("NexusProject")) local Project = NexusProject.new(game:GetService("ReplicatedStorage"):WaitForChild("ClientModules")) --Add external path bases. Project:CreatePathLink("Workspace",game:GetService("Workspace")) Project:CreatePathLink("Common",game:GetService("ReplicatedStorage"):WaitForChild("CommonModules")) --Get several resources. local Baseplate = Project:GetResource("Workspace.Baseplate") local Terrain = Project:GetResource("Workspace.Terrain") local CFrameTweenUtil = Project:GetResource("Common.Util.CFrameTweenUtil")
Path Redirecting
For public libraries, modules may need to be moved to make it more clear, or to refactor code.
--Create the base project. local NexusProject = require(game:GetService("ReplicatedStorage"):WaitForChild("NexusProject")) local Project = NexusProject.new(game:GetService("ReplicatedStorage"):WaitForChild("ClientModules")) --Redirect resources. Project:SetResource("ColorUtil",Project:GetResource("Util.ColorUtil")) Project:SetResource("TweenUtil",Project:GetResource("Util.TweenUtil"))
Cyclic Dependency Detection and Correction
Cyclic dependency (A requires B, B requires A) happens a lot and can be hard to detect. Using "contexts", detecting them can be pretty easy. For example, assume there are the following scripts:
--ReplicatedStorage/Client local NexusProject = require(script:WaitForChild("NexusProject")) local Client = NexusProject.new(script) return Client
--ReplicatedStorage/Client/Util/ColorUtil local Client = require(script.Parent.Parent):GetContext(script) local TweenUtil = Client:GetResource("Util.TweenUtil") local ColorUtil = {} return ColorUtil
--ReplicatedStorage/Client/Util/TweenUtil local Client = require(script.Parent.Parent):GetContext(script) local TeleportUtil = Client:GetResource("Util.TeleportUtil") local TweenUtil = {} return TweenUtil
--ReplicatedStorage/Client/Util/TeleportUtil local Client = require(script.Parent.Parent):GetContext(script) local ColorUtil = Client:GetResource("Util.ColorUtil") local TeleportUtil = {} return TeleportUtil
Would result in the following warning:
A dependency loop exists: Util.ColorUtil Util.TweenUtil Util.TeleportUtil Util.ColorUtil Use NexusProject::SetResource or NexusProjectContext::SetContextResource to allow the loop to end without having to load the resources.
The last line shows how it can be mitigated. All 3 modules end up in a deadlock since each need each other to finish loading to continue. The quick way to resolve this is to set one of the resources so the others can finish loading.
--ReplicatedStorage/Client/Util/TweenUtil local Client = require(script.Parent.Parent):GetContext(script) local TweenUtil = {} Client:SetContextResource(TweenUtil) local TeleportUtil = Client:GetResource("Util.TeleportUtil") return TweenUtil