I use the following in several parts of my code:
--- Helper to deal with circular module require situations. Provided module access is not -- needed immediately (in particular, it can wait until the requiring module has loaded), -- the lazy-required module looks like and may be treated as a normal module. -- @string name Module name, as passed to @{require}. -- @treturn table Module proxy, to be accessed like the module proper. function LazyRequire (name) local mod return setmetatable({}, { \_\_index = function(\_, k) mod = mod or require(name) return mod[k] end }) end
Then in module1 :
local module2 = LazyRequire("module2") -- custom require local M = {} -- ... stuff function M.DoSomethingCool () module2.AwesomeFunction() -- module2 is require()'d on first access end function M.Init () -- get things in order! end -- ... more stuff return M
and in module2:
local M = {} local module1 = require("module1") -- n.b. normal require module1.Init() -- other stuff... function M.AwesomeFunction () -- awesomeness end return M
This works quite well when one of the modules will only need the other down the road, and not in the main chunk.