Fabric - modularizing your code!

Hello!
I’d wanted to introduce small “framework” to modularize your code.

Fabric is inspired by knit framework. Better to use it for a client or server only stuff right now, because it doesn’t have server-client communication, which will be added soon.

Here’s how to use it:

  1. Let’s create a MathCloth dependency to later utilize it.
local MathCloth = {}

function MathCloth:initialize()
	print("MathCloth: Initializing...")
end

function MathCloth:start()
	print("MathCloth: Starting...")
end

function MathCloth:sum(a: number, b: number): number
	return a + b
end

return MathCloth

image

  1. Let’s create the “Example Cloth” where we are going to utilize the MathCloth dependency.
local ExampleCloth = {
	dependencies = {"MathCloth"}
}

function ExampleCloth:initialize()
	print("ExampleCloth: Initializing...")
end

function ExampleCloth:start()
	print("ExampleCloth: Starting...")
	local MathCloth = self.dependencies.MathCloth
	print(MathCloth:sum(1, 2))
end

return ExampleCloth

image

  1. So now that we have both cloths to start the whole framework up, we need to create a bootsrap.
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local ServerStorage = game:GetService("ServerStorage")

local Fabric = require(ReplicatedStorage.Fabric)
local serverFabric = Fabric.new()

print("Server Bootstrap: Starting initialization...")

local registeredCloths = serverFabric:registerFromFolder(ServerStorage.Cloths)
print("Server Bootstrap: Registered server cloths:", table.concat(registeredCloths, ", "))

serverFabric:startAll()
print("Server Bootstrap: All server systems started!")

image

  1. Testing time!
    image

“What are the use cases?”
The main point of the module to make your code decently readable by introducing dependencies and global modularization. Recommended to use on large game systems where it’s already hard to navigate through many modules.

So yeah a pretty solid “framework” i’d say. The fabric also has a various checks for types and errors of the users. Thats about it.

3 Likes
Rate
  • Cool
  • Bad

0 voters

HI! So I’ve seen a few simple errors with your framework.

1st:
I would add assert(clothRegistry[clothName], `could not find module {clothName}`
Just incase someone misspells the cloth name or there was an error with your module.

function Fabric:getCloth(clothName: string)
	return clothRegistry[clothName]
end

2nd: You use Ipairs, and pairs alot when It might eventually end up getting deprecated. You can remove them without having much effect on your script and to save you from future issues with deprecation.

3rd: I don’t think pcall is really needed cause it might end up slowing down the performance of this specific function, what you could do is verify that the module exist and all, then continue end, or just do if module exist and if the type is a table then write the code.

for _, item in ipairs(folder:GetDescendants()) do
		if item:IsA("ModuleScript") then
			local success, result = pcall(function()
				local moduleData = require(item)
				if type(moduleData) == "table" then
					local clothName = item.Name
					self:registerCloth(clothName, moduleData)
					table.insert(registeredModules, clothName)
				end
			end)

			if not success then
				warn(string.format("Failed to register cloth '%s': %s", item.Name, result))
			end
		end
	end

Thanks for the tips i will try to optimize the usage of anything that may slow down or deprecate in the future. Though the pcall is for errors and user friendly experience.
Edit: just got an idea to make two separate versions of the module for starters and pros.

Edit 2: I will also add a tips in errors to actually help people use the module, i will try to make them as simple as they can get so even some n00bs can code something with it.

UPDATE!
Added Built-In dependencies.

  1. Networking
    Allows to easily send packets from server to client and broadcast data to all clients.

Code example:

Server:

local ExampleCloth = {
	dependencies = {"Networking"}
}

function ExampleCloth:initialize()
	print("ExampleCloth: Initializing...")
end

function ExampleCloth:start()
	print("ExampleCloth: Starting...")
        task.wait(5)
	local Networking = self.dependencies.Networking
	Networking:broadcast("test", {"anything here lol", Instance.new("Part", workspace)})
end

return ExampleCloth

Client:

local ExampleCloth = {
	dependencies = {"Networking"}
}

function ExampleCloth:initialize()
	print("ExampleCloth: Initializing...")
end

function ExampleCloth:start()
	print("ExampleCloth: Starting...")
	local Networking = self.dependencies.Networking
	Networking:onPacket("test", function()
		print("Test packet received!")
	end)
end

return ExampleCloth

image

Mini update, added task library to not stop the whole fabric when calling wait or doing some loops.

Who told you that pairs and ipairs will be deprecated in the future?

There was conversation post, and it talked about how to use pairs and Ipairs properly, and a few comments stated that pairs and ipairs might be getting deprecated in the future to make luau syntax cleaner, also not specifying pairs or ipairs is faster so

post: For i, v in pairs which is the table? - #8 by weakroblox35

UPDATE!
Added tips for easier usage of the framework!
изображение

UPDATE!
изображение
Added a bunch of built-in dependencies from me, some people and my friends.

Zipper is a module for creating sliders. By cordie.
RichText from Defaultio
ObjectCache
Lock on by me
R6 Blurry accessory fixer by me.

UPDATE!
Removed some of the built-in dependencies and fixed some of them.
Added new ones!
image