Skip to content
bizzehdee edited this page Jun 23, 2026 · 3 revisions

Modules

DScript supports CommonJS-style require / exports and ES-module import / export syntax. Both styles share the same module cache.

Setting up a module loader

Supply a callback that resolves a module path to its source code:

engine.ModuleLoader = (path, fromPath) =>
    File.ReadAllText(Path.Combine(baseDir, path + ".ds"));
  • path — the string passed to require() or import … from
  • fromPath — the absolute path of the file that issued the require (empty for top-level code)

Return the source text of the module. Throw an exception to signal a missing module.

CommonJS — require / exports

Exporting (named exports via export keyword, or by assigning module.exports):

// math.ds
export function add(a, b) { return a + b; }
export const PI = 3.14159;

Or the long form:

// math.ds
function add(a, b) { return a + b; }
const PI = 3.14159;

module.exports = { add, PI };

Importing:

var math = require("math");
console.log(math.add(2, 3));  // 5
console.log(math.PI);         // 3.14159

ES module import

import { add, PI } from "math";
import * as math from "math";
import defaultExport from "utils";

Named imports bind the named exports directly. Namespace imports (* as) bind the whole exports object.

Module environment globals

Every module has access to these built-in globals:

Global Value
__filename Absolute path of the current module file
__dirname Directory part of __filename
module The module object (module.exports, module.filename, module.loaded)
exports Alias for module.exports
// Inside any required module:
console.log(__filename);   // "/app/lib/math.ds"
console.log(__dirname);    // "/app/lib"
console.log(module.loaded); // false during execution, true after

Replacing module.exports

To export a single value (function, class, or primitive), assign module.exports directly:

// greeter.ds
module.exports = function(name) {
    return `Hello, ${name}!`;
};

// caller
var greet = require("greeter");
greet("Alice");  // "Hello, Alice!"

Dynamic import() (ES2020)

import(specifier) loads a module at runtime and returns a Promise that resolves with the module's exports. Unlike static import declarations, the specifier can be any expression.

// Load by dynamic path
var name = condition ? 'moduleA' : 'moduleB';
import(name).then(function(m) {
    m.doSomething();
});

// Await a dynamic import inside an async function
async function load() {
    var { answer } = await import('math');
    return answer;
}

The returned Promise resolves synchronously (module loading is synchronous in DScript). If the module cannot be found, the Promise is rejected with an error message.

Module caching applies: calling import('same-path') twice invokes the ModuleLoader only once.

import.meta (ES2020)

Inside any module (required or top-level), import.meta provides context about the currently executing module:

import.meta.url       // same as __filename: the resolved module path
import.meta.filename  // same as __filename
import.meta.dirname   // same as __dirname: directory containing the module
// Inside lib/math.ds:
console.log(import.meta.url);      // "lib/math.ds"
console.log(import.meta.dirname);  // "lib"

When running code that was not loaded via the module loader (e.g. the top-level script passed directly to the engine), import.meta.url and import.meta.dirname are empty strings.

Module caching

Every resolved path is compiled and executed exactly once. Subsequent require() calls return the cached module.exports object without re-running the module body. This means module-level side effects (logging, registering listeners, etc.) only happen once.

Circular dependencies

If module A requires module B, and module B requires module A, DScript breaks the cycle by returning the partial exports of A (whatever has been assigned to module.exports so far) when B tries to require it. Design modules to avoid cycles where possible.

Default exports

// utils.ds
export default function helper() { return 42; }

// caller
import helper from "utils";
helper();  // 42

export default sets the default property on the exports object. The import defaultName from "module" form binds that property to defaultName.

Clone this wiki locally