Index

JSCompiler

MMO\client · 1 symbol · generated 30 Sep 2026

class

JSCompiler

JSCompiler.php:27

Bundle the package's javascript into a single file.

class MMO\client\JSCompiler extends MMO\core\classes\aModule use MMO\core\classes\tWithOptions
Namespace
MMO\client
Extends
aModule
Uses traits
tWithOptions
The sources declare their dependencies with `MMO.provide()` / `MMO.require()` at the top of each file ([`loopDeclarations`](https://mmoframework.fr/documentation/mmo.client/php/JSCompiler.md#jscompiler-loopdeclarations)). This compiler reads those declarations to: 1. sort the files so a namespace is always defined before the file that requires it, 2. emit the namespace bootstrap (`var MMO = MMO || {}; MMO.core = MMO.core || {}; ...`), 3. strip the declarations themselves, which have no meaning at runtime, 4. optionally drop the comments and the indentation ([`minify`](https://mmoframework.fr/documentation/mmo.client/php/JSCompiler.md#jscompiler-minify)), 5. write a v3 source map pointing back at the original files. This replaces the google closure compiler the package used until 3.0.13. Closure did the same four jobs plus local variable renaming, which measured 2.5% of the gzipped payload -- not worth a 14MB jar and a jvm in the build chain. Nothing here needs java, node, or any binary: it is plain php. Note this is a *bundler*, not an optimizer: it never rewrites an expression, so what ships is what was written. A syntax error in a source file is therefore a syntax error in the bundle; `php -l` has no javascript equivalent here, and the test suite (`tests/js-node`) is what catches it.

Index

PROVIDEThe declarations this compiler understands, in the order they matter.
REQUIRE
banner
minify
opts
sourceMap
sourcesContent
addOptions($opts, $appendList)Merge $opts into the existing options (through merge), rather than replacing them wholesale like setOptions.
bootstrap($namespaces)The var MMO = MMO || {}; lines that declare every provided namespace, parents first.
buildSourceMap($filename, $sorted, $files, $mappings)
clearOptions()Empty the options bag.
compile($filename, $files, $opts, $debug)Compile the sources into one bundle.
DefaultConfig() static
getOption($key, $default)
getOptions()
loopDeclarations($code)Read the MMO.provide() / MMO.require() calls at the top of a source.
minify($code)Drop the comments and the indentation of a javascript source, without ever joining two lines.
setOption($key, $value)Set (or, with a null $value, remove) a single option.
setOptions($opts)Replace the whole options bag.
sort($files)Sort the files so that every MMO.require()d namespace is provided by an earlier file.
VLQ($value) staticBase64 variable-length quantity, as the source map spec defines it.

Constants2

PROVIDE

The declarations this compiler understands, in the order they matter.

const PROVIDE = 'provide'

REQUIRE

const REQUIRE = 'require'

Properties5

banner

string $banner
Type
string

opts

protected array $opts = []
Type
array

sourceMap

?bool $sourceMap
Type
null | bool

sourcesContent

bool $sourcesContent
Type
bool

Methods14

addOptions($opts, $appendList)

tWithOptions.php:65

Merge $opts into the existing options (through merge), rather than replacing them wholesale like setOptions.

function addOptions(array $opts, bool $appendList = false): void
$optsarraythe options to merge in
$appendList = falseboolif true, a list-valued option is appended to (rather than replaced by) the corresponding list in $opts -- see \MMO\core\arrays\merge for the exact semantics
returnsvoid
$t->setOptions(['a' => 1, 'tags' => ['x']]); $t->addOptions(['b' => 2, 'tags' => ['y']]); $t->getOptions(); // ['a' => 1, 'tags' => ['y'], 'b' => 2] -- 'tags' is replaced, not appended ($appendList=false)

bootstrap($namespaces)

JSCompiler.php:126

The var MMO = MMO || {}; lines that declare every provided namespace, parents first.

function bootstrap(array $namespaces): array
$namespacesarrayin load order
returnsarrayone statement per line

buildSourceMap($filename, $sorted, $files, $mappings)

JSCompiler.php:345
protected function buildSourceMap(string $filename, array $sorted, array $files, array $mappings): string
$filenamestringthe bundle the map describes
$sortedarraythe sources, in bundle order
$filesarrayfilename => declarations + code
$mappingsarrayone [sourceIndex, sourceLine] (or null) per bundle line
returnsstringthe json map

clearOptions()

tWithOptions.php:39

Empty the options bag.

function clearOptions(): void
returnsvoid
$t->clearOptions(); // getOptions() === []

compile($filename, $files, $opts, $debug)

JSCompiler.php:276

Compile the sources into one bundle.

function compile(string $filename, array $files, array $opts = [], bool $debug = true): int
$filenamestringthe bundle to write
$filesarraythe sources; order does not matter, sort
$opts = []arrayper-compilation overrides of the public properties
$debug = truebooltrue for a readable bundle with a source map, false for a minified one
returnsintthe number of bytes written
throwswhen a source does not exist

getOption($key, $default)

tWithOptions.php:49
function getOption(string $key, mixed $default = null): mixed
$keystring
$default = nullmixedreturned if $key is not set
returnsmixed
$t->getOption('a', 'fallback'); // the current value of 'a', or 'fallback' if not set

getOptions()

tWithOptions.php:20
function getOptions(): array
returnsarrayevery option currently set
$t->getOptions(); // ['a' => 1, 'tags' => ['x']]

loopDeclarations($code)

JSCompiler.php:61

Read the MMO.provide() / MMO.require() calls at the top of a source.

function loopDeclarations(string $code): array
$codestring
returnsarraystring[], require: string[]}

minify($code)

JSCompiler.php:156

Drop the comments and the indentation of a javascript source, without ever joining two lines.

function minify(string $code): arrayNot joining lines is deliberate: it removes every automatic-semicolon-insertion hazard, keeps the source map accurate line for line, and costs ~2% of the gzipped payload against a minifier that collapses everything onto one line. The scanner tracks strings, template literals and regex literals, because a `/` means division or a regex depending on what precedes it, and `//` inside either is not a comment.
$codestring
returnsarraystring[], 1: int[]} the kept lines, and the source line each one came from

setOption($key, $value)

tWithOptions.php:77

Set (or, with a null $value, remove) a single option.

function setOption(string $key, mixed $value): void
$keystring
$valuemixedif null, the option is unset entirely rather than being set to null
returnsvoid
$t->setOption('a', 1);$t->setOption('a', null); // removes 'a' from getOptions()

setOptions($opts)

tWithOptions.php:30

Replace the whole options bag.

function setOptions(array $opts): void
$optsarray
returnsvoid
$t->setOptions(['a' => 1]);

sort($files)

JSCompiler.php:83

Sort the files so that every MMO.require()d namespace is provided by an earlier file.

function sort(array $files): arrayA require nobody provides is only a warning: a source may legitimately depend on something the host page loads on its own. A cycle is a warning too -- the file is emitted where it was first reached, which is what closure did, and is correct as long as the cycle is between namespaces that only reference each other at call time (the case throughout this package).
$filesarray
returnsarraythe filenames, in load order

VLQ($value)

staticJSCompiler.php:375

Base64 variable-length quantity, as the source map spec defines it.

protected static function VLQ(int $value): string
$valueint
returnsstring
Inherited members (47)
ConstantsDeclared byDescription
ALERTiLogLevelAlert: Action must be taken immediately.
ALLiLogLevelMask for all
ALL_PLUSiLogLeveldebug everything
BACKTRACEiLogLevel
CRITICALiLogLevelCritical: Critical conditions.
DEBUGiLogLevelDebug: Detailed debug information.
DEEPiLogLeveldebug everything with arguments
EMERGENCYiLogLevelEmergency: System is unusable.
ERRORiLogLevelError: Runtime errors that do not require immediate action but should typically be logged and monitored.
ERROR_PLUSiLogLevelMask for all error
FATALiLogLevelMask for all fatal error
INFOiLogLevelInfo: Interesting events.
INFO_PLUSiLogLevelMask for all errors/warning/notices/info
MEMORYiLogLevelinclude backtrace object
NOTICEiLogLevelNotice: Normal but significant events.
NOTICE_PLUSiLogLevelMask for all errors/warning/notices/info
TRACEiLogLevelinclude backtrace as origins
WARNINGiLogLevelWarning: Exceptional occurrences that are not errors.
WARNING_PLUSiLogLevelMask for all errors and warnings
PropertiesDeclared byDescription
verbosityaModule
MethodsDeclared byDescription
alert($message, $context)aModuleAction must be taken immediately.
backtraces($message, $context)aModuleForce-log a message at INFO level together with a full stack trace/memory snapshot (iLogLevel::BACKTRACE), bypassing the verbosity mask entirely (any non-zero verbosity is enough to trigger it).
Configure($config)aModuleMerge $config into this module's configuration in the shared Configuration.
critical($message, $context)aModuleCritical conditions. No-op if CRITICAL is currently filtered out by the verbosity mask.
debug($message, $context)aModuleDetailed debug information.
debugName()aModuleHuman-readable identifier used as the default {origin} in this instance's log messages.
emergency($message, $context)aModuleSystem is unusable. No-op if EMERGENCY is currently filtered out by the verbosity mask.
error($message, $context)aModuleRuntime errors that do not require immediate action but should typically be logged and monitored.
getVerbosity()aModule
info($message, $context)aModuleInteresting events. No-op if INFO is currently filtered out by the verbosity mask.
Instantiate($config)aModule(Re)create the shared instance immediately, configured with $config merged into the class's existing config.
IsShared()aModule
log($level, $message, $context)aModuleLogs with an arbitrary level.
notice($message, $context)aModuleNormal but significant events.
offsetExists($key)aModule\ArrayAccess::offsetExists -- tells whether $key is a declared property at all, regardless of whether it is currently readable/writable through array access.
offsetGet($key)aModule\ArrayAccess::offsetGet -- reads a property directly, unless it has a #[Serialize(serialize: 'methodName')] attribute, in which case that zero-argument method is called instead (e.g.
offsetSet($key, $value)aModule\ArrayAccess::offsetSet -- sets a property directly, unless it has a #[Serialize(unserialize: 'methodName')] attribute, in which case that method is called with $value instead (e.g.
offsetUnset($key)aModule\ArrayAccess::offsetUnset -- equivalent to $module[$key] = null.
serialize($path, $serializer)aModule\MMO\core\interfaces\iSerializable::serialize -- exports every property (via
setVerbosity($verb)aModuleSet the current verbosity mask, replacing whatever it was before.
Shared()aModuleGet the shared instance, creating (and configuring) it on first call.
testVerbosity($level)aModuleTest whether a given level (or set of levels) is currently enabled by this instance's verbosity mask.
traitUnshare($serialize)aModuleRemove the shared instance, so the next Shared() call creates a fresh one.
unserialize($data, $path, $instances)aModule\MMO\core\interfaces\iSerializable::unserialize -- merges $data onto DefaultConfig, runs it through the (possibly overridden) constructor, then applies each resulting value to its property (via
Unshare($serialize)aModuleLike tSingleton::Unshare, but also disconnects this module's instance from every event it was listening to (via Event::DisconnectListeners) before dropping it.
warning($message, $context)aModuleExceptional occurrences that are not errors.
__construct($config)aModuleprotected constructor, so it is not possible to do new Module(...) called by the serialization process just before being injected with data.