Introducing Require-by-String

Luau already supports this outside Roblox with .luaurc files, so it’s surprising to see this feature released on Roblox without it.

If you use Luau outside Roblox (with a runtime such as Lune, lrt, seal, etc.), you can define aliases like so:

// in ./.luaurc (json file schema)
{
    "aliases": {
        "utils": "./src/utils/" // where . refers to the project's directory
    }
}

Assuming you have a hypothetical file named path.luau in the folder (directory) ./src/utils, you can require it with:

-- in ./src/main.luau
local path = require("@utils/path")

I’m not exactly sure how they’d translate this to the Roblox datamodel, but perhaps a top-level Config file could be nice.

3 Likes

There’s other engines that use this kind of thing, probably not the exact same thing though, but I’m pretty glad it’s made its way over to Roblox either way!! It’s about time.

3 Likes

I’m really confused as to why you can’t use this to require children of a script (like require(“/module”))

Require by instance id / unique id coming when?

Is this supposed to only work for require-by-string? This isn’t possible with normal requires for whatever reason.

I am too, you wouldn’t really even need the slash if this was possible.

Because requiring like that is not possible on vanilla Luau, this is only possible on Roblox, in filesystem projects, you can’t put files under files the way Roblox allows you to put instances inside instances

2 Likes

Good feature. Love to use this!

How could the new “require by string” feature be strategically utilized to streamline module management and improve code readability, especially in projects that rely on external tools like Rojo or involve cross-platform Luau development?

1 Like

This should work… require(Script.ScriptName)

This has been answered somewhat by the Luau team on Discord, but for the sake of repeating it publicly (noting that I’m not a Roblox employee and thus my words mean nothing, and I am also paraphrasing):

The work required to get aliasing is roughly the same work needed to establish what a “library” is for Roblox (“project-relative requires” can be thought of as an equivalent to an aliases that points to the root of a library), and they felt it wasn’t worth blocking the release of require-by-string over.

This is one of their bigger priorities right now, so I’d expect at least an update on it soon™. This won’t be a Packages situation where the feature is half baked and sits for years.

5 Likes

Honestly this is a horrible reason to inconvenience literally everybody else that wants to use these features.

It’s more logical to take both approaches and make it even more convenient for people who are only working with Roblox, rather than inconveniencing everybody for cross-runtime compatibility’s sake. People who aren’t only working with Roblox can just code it in a way where it’s compatible for what they’re trying to achieve.

Ran into an issue when using require-by-string today, I believe it may be intended behavior but just want to confirm:

If I require my modules at the top of my script, these are equivalent, as stated in the announcement:

local Module = require(script.Parent.Parent.Folder.ModuleScript)
local SameModule = require("../Folder/ModuleScript")

However, if I am requiring the module inside of a function, they are not equivalent:

--No longer requiring the module out here.

local function DoSomethingWithModule()

     local Module = require(script.Parent.Parent.Folder.ModuleScript) --Works
     local SameModule = require("../Folder/ModuleScript") --Errors
end

return DoSomethingWithModule --will be called in a different script

I’m assuming the errors are happening because by the time the require-by-string line executes, it is technically running in another script that required the function above, so the Parent reference is not the same? So it may not be a bug? but was still a bit confusing to me because I thought the require-by-string statement was truly equivalent.

(I’m not using Rojo or anything, just vanilla Studio for this example)

1 Like

Woah, a New Feature is going to be in the ModuleScript… This is such a Wild, Great News scenario! If the Require-By-String thing was in Studio, That ModuleScript should Work…

Don’t worry, you can still store Vector3’s and Color3’s, you’ll just have to convert each value (Red, Green Blue or X, Y, Z) into their own individual numbers and unpack them when you want to use it.

Here’s some post’s that go more into it, Cheers.

Don’t forget buffers, buffers being able to be used in datastores is super epic

I still kind of want to know how (and why) he expects to store instances in a datastore. (in a not-to-be-rude way)

Currently really the only good way to do it is to store it as a buffer containing all the modifiable properties of the Instance, and then storing them similarly to how C stores structs (sequentially).

I honestly don’t know how a first-party implementation would be better than this considering it’s already pretty small (like less than 120 bytes to store all properties of a Part), and you can make it even smaller by making assumptions suiting your needs (for example if all your parts are red you don’t need to store color)

1 Like

Honestly really surprised there’s no way to reference the current script in this without naming it.

I’m constantly adding other child scripts into one parent script that manages all of them and it really would be nice if there was some equivalent to require(script.Child) in this syntax instead of require(‘./modName/Child’)
E.g. some sort of require(‘script/Child’) or require(‘$child’) or require(‘/child’) or something

I know I could still just use script.Child, but it would be nice to stay consistent with my require format and this in general seems like it’s going to become a more powerful way once aliasing comes.

3 Likes

I came here just to suggest the same thing, yeah! “script/Child” would be an absolute path which they do not support yet, so I would rather prefer some other prefix like “$” or something else instead of “.” to access the current script level, agreed. I mean … of course normally you cannot put files inside of files in the File Explorer but Roblox supports that so it would be cool if we got this functionality in string requires, too.

This is not intended behavior, and a fix will be in shortly—thank you for flagging it! An exported function (a closure) is expected to capture its environment, including the context from which require-by-string is resolved.

In the meantime, I wouldn’t recommend relying on the current behavior. If you’d like the correct behavior right now, I’d recommend performing the actual require-by-string call outside of the closure, storing the result in a variable, and referring to it inside the closure using the variable:

-- For now, keep outside of closure
local result = require("../Folder/ModuleScript")

local function DoSomethingWithModule()
     print(result)
end

return DoSomethingWithModule

I’ll update when this is fixed.

1 Like