Best practice for client only scripts in modules?

require() can be used in conjunction with an Asset ID to load module scripts named MainModule to a game. Currently, this is what I use in my game for tools. Main script requires a tool asset ID, tool module script sets up the remote events and parents a global clientside script to ReplicatedStorage, and then returns the tool instance for either parenting to StarterPack or cloning to players who are supposed to have it. As for the global clientside script (responsible for visual effects associated with the tool) set to RunContext Client parented to to ReplicatedStorage, I was told this was bad practice for some reason, but this only way this can work, because this is the only place besides Workspace that continually replicates anything placed in it after the initial snapshot. If I use ReplicatedFirst or anything else with a legacy LocalScript, if for whatever reason the server script fails to parent the clientside script to ReplicatedFirst or StarterPlayerScripts before the initial snapshot where their contents are replicated to a client, then they will never end up running. This creates a race condition between the first player joining having their data replicated, and the server script run.

Are there any reliable solutions to this problem besides parenting a Script with RunContext set to Client to ReplicatedStorage which is allegedly bad practice?

Also, aside from the aforementioned downside, what are the pros and cons of this system of having tools as independent modules so I will not have to have multiple copies of the same tool if I have multiple games?

While using a global client-side script with RunContext set to Client and parented to ReplicatedStorage may work in some cases, it is generally considered bad practice due to potential security risks (Can’t find the source) and limitations. Instead, I would recommend using alternative methods to achieve the desired functionality without compromising security and reliability.

One reliable solution to the problem you described is to use a combination of ReplicatedFirst and StarterPlayerScripts. You can place the client-side script in StarterPlayerScripts, and it will automatically replicate to the player when they join the game. Additionally, you can use ReplicatedFirst to ensure that the client-side script is replicated to the player before any other scripts are executed.

Extra Data

Pros

  1. Code Reusability
  2. Easy matinence
  3. Organisation

Cons

  1. Increased complexity
  2. Potential performance impact

Overall, using independent modules for tools can be a good approach for code reusability and organization.

I’m wondering why it is potentially insecure. Are you saying that exploiters would be able to modify constants before the script assigns them?


I’ve never used this method, but I’ve heard that LocalScripts are best when run under PlayerScripts or ReplicatedFirst. Client Script RunContexts are something that I’ve been lazy with using them in old Workspace Scripts.

A well-known working method for preventing potential race conditions is to parent your LocalScripts to StarterPlayerScripts and not use a Client RunContext.

I was going to add this back yesterday but I didn’t have enough time, but I can’t actually find my source and that part of the point shouldn’t be taken too much into account, but I do remember hearing about it somewhere (I think on the devforum?)

Hi, it seems this topic has aged but I will add that the reason you shouldn’t put it in ReplicatedStorage for execution is primarily due to using a “storage” to use it? The semantics make no sense here for that reason.

There is more information about RunContext in this article than I have learned.

The primary reason this exists is probably because you can develop standalone systems with both server and client contexts in one package, without having to delegate them to specific parts of the hierarchy. It is implied by “How can you use it?” section.