backupRoswaal has moved to roswaal.app. These pages are a backup copy.Go to roswaal.app

Modules✎

What a script requires and the services it fetches, where you declare them, and what each runtime resolves.

Pending review

A module is code in another file that this one uses. Roswaal writes the require for you — but only ever for a module you have declared, and each declaration writes exactly one, at the top of the generated file.

Tip

Nothing is required that the graph does not say. Every import in the generated file is one the panel or the canvas shows.

Declaring one

Modules live in the Variables panel, under their own heading. It is the same question the variables answer — what does this script have to hand — and a dependency belongs somewhere you can see it rather than somewhere you go looking.

Everything this script declares: its variables, its services, its modules, its locals and its functions.

Hover a control or its row to light the other.

  • VariablesValues the whole script reads and writes. See Variables and locals.
  • ServicesThe services this script fetches at the top of the file, in this order. Roblox graphs only. Drag one onto the canvas for a Get Service, or use it by name in Code Block; one nothing uses is a warning.
  • ModulesWhat this script requires. Each one writes a single require at the top of the generated file, however many places read it — so four uses are four pills and one import.
  • LocalsValues that exist inside one block. See Variables and locals.
  • FunctionsEvery function this script declares. See Functions.
FieldWhat it is
NameThe local it binds to, and what the pill shows. Yours to choose — see below
ModuleWhat goes inside require(...): a string, or on Roblox where the ModuleScript sits
MembersNames pulled off it into locals of their own, comma separated

Drag a module onto the canvas for a Get Module pill — one output, no header, exactly as a variable gives you a Get. Four of them still write one require, because the declaration is on the script rather than on any of the pills.

Require at Top declares one on the canvas instead, for when you would rather see it there. It takes the same specifier and hands back the same module.

Or drag a ModuleScript from the DataModel browser onto the Modules heading, or its graph from Graph Content or its file from Compile Content: it is declared under its own name, by where the project's node map puts it. Dropping one that is already declared changes nothing.

A Require Module or Require at Top already on the canvas can be moved here: right-click it and choose Promote to Modules. It becomes a Get Module pill for the declaration, keeping its wires, and any module function called through it is called through the declaration.

What goes in the box

A string must start with a prefix. That is not a house style: an unprefixed path is an error in Luau itself, since the require rules were amended — require("Foo") used to resolve and now does not. On Roblox you can name where the module sits instead, with no quotes: see below.

FormRobloxLuneWhat it reaches
./nameYesYesA sibling of this file
../nameYesYesUp one, then down
@self/nameYes—A child of this script
@game/Service/nameYes—Down from the DataModel root
@lune/fs—YesLune's standard library
@alias/nameNot yetYesAn alias from a .luaurc
ReplicatedStorage.Shared.GreeterYes—The ModuleScript at that place
script.Parent.UtilYes—Up from this script, then down

Warning

Specifiers are checked against the graph's runtime: @lune/fs in a Roblox graph is an error. A .luaurc alias is a warning in Roblox, which does not resolve them yet — see Aliases and .luaurc.

By where it sits

Most Roblox code requires a module by the instance, not by a string, and the Modules list takes that too. Start from a service, script or workspace, and write the path the way you would in Luau:

WrittenRequired as
ReplicatedStorage.Shared.Greeterrequire(ReplicatedStorage.Shared.Greeter)
game.ReplicatedStorage.Shared.GreeterThe same
game:GetService("ReplicatedStorage").Shared.GreeterThe same
ReplicatedStorage:WaitForChild("Shared").GreeterAs written
workspace["Main Menu"].UtilAs written

The service is fetched once, at the top, and the require reads it — the same local a Get Service for it reads. With no name given, the module is named after the ModuleScript.

Info

A path is names after dots, names in brackets and :WaitForChild(...). Anything else — another call, an operator — is an error rather than written, because a field in a panel is not somewhere code should be able to hide.

Naming it yourself

The name is a choice, not a derivation. Two modules can genuinely want to be called util — ./combat/util and ./inventory/util — and only you can say which becomes combatUtil.

So a name you type is used exactly. It is never quietly turned into util2: two declarations wanting one name is an error naming both, because a file can bind it once and the fix is a rename that is yours to pick.

Members, and the Roblox datatypes in Lune

Members bind names from inside the module to locals of their own. It is Lune's own idiom, and it is what makes the Roblox datatypes work there.

luau
local roblox = require("@lune/roblox")
local Vector3 = roblox.Vector3
local CFrame = roblox.CFrame

With Vector3 bound, Vector3.new(1, 2, 3) means what it means in Roblox — so a graph moved between runtimes needs the declaration, not different nodes. Shadowing a name Luau provides is allowed here because it is the point; Roswaal warns, so that naming a module table is a decision rather than an accident.

Declaring services

A Roblox graph's Variables panel has a Services heading above Modules. A service declared there is fetched at the very top of the file, in the order you list them, whether or not a node asks for it — so Code Block can read Players by name, and the top of the file reads the way you would write it.

Add takes a service by name, or drag one from the DataModel browser onto the heading. Drag a declared service onto the canvas for a Get Service, which reads the same local. A Get Service for a service you have not declared still works, and fetches it after the declared ones; right-click it and choose Promote to Services to declare it.

Warning

A service nothing uses is a warning. Declare what the script reads, so the top of the file is a true list of what it depends on. On Lune, which has no services, a declared one is an error.

Where the requires end up

At the top, below the GetService calls — where a hand-written Roblox file puts them, and in the order you declared them. Declared services come first, then any a node asked for.

luau
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")

local Greeter = require(ReplicatedStorage.Shared.Greeter)
local Combat = require("@game/ReplicatedStorage/Combat")

Info

Deleting a module leaves the pills that read it in place, reporting an error — as deleting a variable does.

Not reviewed yet