I cannot claim to be more than a dabbler with Luatex, nor really a Lua person; I hope those more knowledgeable than I am will forgive my blunders, but I can at least report my experience.
package.searchers is replaced, so that when you
require a module from TeX, Luatex uses TeX's searching mecanism not the usual one. That means in practice that when you run Lua from within Luatex, it won't find modules that your normal system Lua finds. (I don't know enough about the architecture, but I assume it's deliberate, because it wants to be able safely to maintain different parallel structures and be sure that LuaTeX will always pick up TeX-appropriate modules, even if other modules are installed elsewhere.)
In practice that means that if you have installed a lua module via luarocks, you will need either to place a copy, or to include a symbolic link, within a directory that
kpathsea will find. Luarocks is a pretty simple-minded thing, as far as I can tell, and simply dumps files in a convenient directory, so you should be able to find them and link to them or copy them. The documentation rather cutely warns "Of course it no big deal to write an alternative loader and use
that in a macro package", though for some of us (like me!) that may be quite a big deal.
I have no experience of how this plays if you are using a lua module which is not pure Lua but is relying on code compiled from C. Luatex itself already links some such libraries (like
slnunicode), but I have no idea how that may affect your use case I'm afraid. I'd hope it would "just work", but ...
When you are building something which you want to test both as a standalone and as something that will be tied to TeX, I found by trial and error:
If you need (as you conceivably may) code that executes only if it is in one environment or another, test for the definition of
lua.version which will be defined if you are running in Luatex. I suppose strictly speaking just a check for lua is enough (and a check for
lua.version isn't safe, because if
lua is undefined it will error).
if lua and lua.version then
-- we're in LuaTeX
-- we're not
One way of developing in parallel is to use
texlua as your lua interpreter. If you do that, you will get access automatically to the statically linked libraries that are always part of luatex (like
slnunicode, i.e. without needing to
require them). And your script will run more or less "as if" it were running via a call from a TeX document. But there's a catch. Texlua does not automatically "find" the
kpathsea function, so you need to "tell" it what to do:
kpse.set_program_name("kpsewhich") -- or whatever
Now, for instance
local xml = require("luaxml-domobject")
will find the appropriate module in the TeX directory tree, using
kpsewhich: without that magic, you will get the dismal complaints from
package.loader about not finding the module. Or, worse, you will get a module with that name, but not the one you will get when Luatex is "really" in charge.
The code below may be easier to follow than the explanation! If you run it with
texlua you will get one output; if with
lua a slightly different output, but in both cases it works.
local luatexing = lua and lua.version
-- local lpeg shadows global lpeg if luatex is running this
local lpeg = lpeg
if luatexing then
-- if luatex is not in charge we need to require the library
lpeg = require("lpeg")
-- The output here will differ depending on
-- whether we have luatex (with statically
-- linked unicode library) or not. Of course,
-- we could then `require` something
if luatexing then
io.write(unicode.utf8.lower("Ê") .. "\n")
io.write(string.lower("Ê") .. "!\n")
-- But this will work in either case: with
-- luatex via the statically linked lpeg
-- library. With regular lua via the require
j = lpeg.P("a matcher")
io.write(j:match("a matcher") .. "\n")
What I don't know, because I haven't really explored it, is whether one needs to be careful to remove the
kpathsea setting from a file that is going to be called directly from a TeX document, where it will already be set. But for development purposes this setup, if any is needed at all, enables you to get reasonably close to the way a script is going to be interpreted when it is called from within a TeX run.