Modules and dependencies
Split a package's code into modules under lib/, load them with
require, and depend on other packages to load theirs.
Load your own modules
A module is a .lua file under your package's lib/ folder. It returns
what other files get when they load it, usually a table of functions.
This package holds one module, numbers, and an app script that uses
it:
name "@me/toolbox"
version "0.1.0"
api_version "*"
kind "app"
license "0BSD"
local numbers = {}
function numbers.clamp(x, low, high)
return math.max(low, math.min(high, x))
end
return numbers
local numbers = require("numbers")
print("clamped " .. numbers.clamp(14, 0, 10))
require("numbers") loads lib/numbers.lua and returns its table.
How require finds a module
A module's name is its path under lib/, with dots between folders and
no .lua. Names always start from lib/: there are no relative names
such as ./sibling, and no package.path to change.
| You write | It loads |
|---|---|
require("numbers") | lib/numbers.lua |
require("ui.toolbar") | lib/ui/toolbar.lua |
require("@alice/greeter") | what the dependency @alice/greeter returns from its init.lua |
require("@alice/ | that dependency's lib/messages.lua |
One name is one file: ui is lib/ui.lua, whatever lib/ui/ holds, and
a folder alone is not a module.
Each module runs once per app, the first time it is required; every
later require of it returns the same value. A module that returns
nothing gives true. Two modules that require each other raise an error
instead of waiting forever. A name that finds no file raises an error
naming the path it tried:
require: module 'nums' not found in package (looked for lib/nums.lua)
To load a file by its exact path instead, use Dir:require or
File:require. They run the file at that path, with no lib/ in front
and no .lua added, and keep their modules apart from require's.
A file from a folder or file your app was granted compiles as text;
only the Lua files of a sealed package load compiled.
Depend on another package
List each package yours uses in the manifest's requires block, by its
@scope/name. A dependency is a library or an asset pack: an app is
started, not required (Launch other apps).
While you develop them together, a dependency comes from your workspace
(Work on several packages together):
requires {
package "@alice/greeter" workspace=#true
}
A published dependency comes from the registry instead, with a SemVer
range of versions. namespace= names the registry namespace it is
published in; without it, the dependency resolves in the namespace the
--namespace entry of
datumhue pkg update gives:
requires {
package "@alice/greeter" version="^1.0"
package "@studio/art" version="~0.3" namespace="@studio"
}
Your code then loads the dependency with require("@alice/greeter"),
and a module under its lib/ with a slash path. A dependency can list
the modules it offers in an exports line of its manifest; then only
those answer a slash path, and any other raises with a message that
lists them. Its init.lua is always reachable.
A dependency's files sit in your package under deps/, so the image
assets/hero.png of an asset pack @alice/art is
datumhue..
Pin and update dependencies
datumhue pkg update resolves your registry dependencies and writes
package.lock.kdl, which pins each to the exact published content it
resolved to. It skips yanked versions.
$ datumhue pkg update
$ datumhue pkg outdated
datumhue pkg push publishes against that lock without resolving again,
and fails when a pinned dependency has been yanked or removed since. To
move to newer versions, run pkg update, read the change to the lock
file, and push. datumhue pkg outdated lists the dependencies with a
newer version, or with a pin that has been yanked.
A paid dependency is bought once, from the store's Creator shelf. Then
pkg update delivers its source into your package at deps/, yours to
read, adapt under the seller's terms, and keep. It ships inside your
published package, and the lock records it as delivered rather than
pinned. To fetch a fresh copy, delete its folder and run pkg update.
When a dependency cannot be found
DatumHue resolves every dependency before the first line of your Lua runs. A missing dependency, or an app listed as a dependency, stops the launch with a message naming it.
A registry dependency stops it the same way when no published version matches its range, or when two ranges ask for versions no single one satisfies.
See also
Reference used on this page: Dir:require File:require Package:dir