I like Lua's approach to modules. In Lua, a file is basically equivalent to a function body. It accepts arguments and can return values. In JavaScript, this is not allowed.
In Lua, a function can accept multiple arguments in a tuple called `...`. Every file is implicitly a vararg function, so we can unpack the `...` to get arguments.
> add.lua
local a,b = ...
return a + b
> file.lua
local add = load 'add.lua'
print(add(1,2)) --> 3
load takes a file path and returns that source file as a function.
Most files ignore arguments, but they do return values. > add2.lua
return function(a,b) return a + b end
> file2.lua
local add = require 'add'
print(add(1,2))
`require` loads a source file, executes it, and returns the value that it returns. It is similar to `return load(fileName)()`, but it also has a search mechanism, and caches the result. So, the Lua equivalent of export default is simply returning a value at the end of a source file.The named exports are also easy to replicate. You simply return an object with the keys you want.
> math.lua
return {
add = function(a,b) return a + b end,
sub = function(a,b) return a - b end
}
> other.lua
local math = require 'math'
local add, sub = math.add, math.sub
You can also have something similar to the `export function name(){}` declaration. > hello.lua
local exports = {}
function exports.hello()
print "Hello World"
end
exports.VERSION = '0.0.1'
return exports
> file3.lua
local hello = require'hello'.hello
local version = require'hello'.VERSION
hello() --> Hello World
In all, I think the Lua's require is a much cleaner way to implement modules. Unfortunately, it cannot handle circular references. It may be possible to add this feature using Lua's coroutines, however. I will have to research how it is handled in JavaScript to be sure.