lune-org/lune

Lune does not cache require results across files

Closed this issue · 4 comments

The results of requiring a file is only cached in that specific file. This means that if two different scripts both require a script, it will run twice, which can be very problematic for modules that are supposed to contain a global state.

Simple reproduction:
test1.luau (file to run):

local result1 = require("./test3")
local result2 = require("./test3")
local result3 = require("./test2")
print(result1 == result2, result1 == result3) --> true, false

test2.luau:

return require("./test3")

test3.luau:

print("test3 ran") --> test3 ran (x2)

return {}

This bit me pretty hard recently. I was trying to create a Logging class which would be instantiated and returned in a logging.luau file to keep around a singleton. It took me a while to figure out that every time I required that file I was getting back a brand new Logging instance. I would really like to see support for module caching by default, with a way to bypass the cache in special situations (I think Jest would benefit from this in particular for its module mocking)

Just ran into this trying to write a basic testing framework, is the only workaround to use true globals instead?

I added a test that demonstrates the issue and does indeed fail, opened a draft PR with the test here: #170

I would not know how to even begin solving the issue, but hopefully the test is useful

Oh nice, looks like @kennethloeffler has a PR fixing this already, so speedy!

If for any reason someone is unable to use a lune version that has the fix in the future, I made a little workaround that is quite un-intrusive and still works with lsp (luau-lsp at least).

Gist for the workaround module here: https://gist.github.com/itsfrank/c3e193338612eb00324dc2340aaffa79

You can use it like so:

local some_module_state = {}
some_module_state.foo = "bar"

some_module_state = require("modulestate.luau").get_state("<unique name>", some_module_state)
-- from here on out, `some_module_state` will have the values from the global state
-- but luau-lsp still treats it like a local table, so typing `some_module_state.` will suggest `foo` with type string

When the fix is merged you should be able to just delete the require("modulestate.luau").get_state line and everything should work as intended