Skip to content

WebArtWork/waw

waw Framework

waw is a minimal Node.js (≥ 24) platform that loads modules and either:

  • executes a CLI command exposed by modules (cli.js), or
  • boots the runtime by sequentially loading each module’s index.js.

The core is intentionally small. It does not implement application frameworks, routing, databases, generators, or business logic — modules do.


Philosophy

  • Tiny core — only module discovery, dependency install, ordering, CLI dispatch, runtime bootstrap
  • Modules first — all behavior comes from modules
  • Explicit over magic — behavior is defined by files (module.json, cli.js, index.js)
  • Sync by default — dependency installation and module load preparation are deterministic

If a feature is not implemented by a module, it does not exist.


Requirements

  • Node.js ≥ 24
  • npm available in PATH

Installation

npm install -g waw

Project structure (minimal)

project/
├── config.json
├── server.json          (optional)
├── server/              (default local modules folder; configurable)
│   ├── my-module/
│   │   ├── module.json
│   │   ├── index.js     (optional runtime entry)
│   │   └── cli.js       (optional CLI commands)

How waw works

1) Configuration & module discovery

On startup, waw reads config from (merged, later wins):

  1. Global waw/config.json
  2. Global waw/server.json
  3. Project ./config.json
  4. Project ./server.json

Then it discovers modules:

  • Local modules: directories under /<project>/<config.server>

    • If config.server is not set and a server/ folder exists, it uses "server".
  • Global modules: declared in config.modules and fetched into the globally installed waw package under waw/server/<name>.

Global module fetch behavior:

  • config.modules is interpreted as a map of { <moduleName>: <orgKey> }.

  • Supported orgKey values are:

    • wawhttps://github.com/WebArtWork/waw-{NAME}.git
    • itkpgit@github.com:IT-Kamianets/waw-{NAME}.git
  • If a required global module directory is missing, waw performs a destructive force sync of that repo into waw/server/<name>.

Fallback behavior:

  • If no modules are found at all, waw force-syncs and loads a global module named core from the waw org pattern.

Project-type auto modules:

  • If the project contains one of these marker files:

    • angular.json → loads global module angular
    • react.json → loads global module react
    • vue.json → loads global module vue
    • wjst.json → loads global module wjst
  • Each is fetched from the waw org pattern if missing.

Note: In this repository, the loader contains only these mechanics. Any application/framework behavior must be implemented by modules.


2) Module definition (module.json)

Each module is a folder containing module.json.

Supported fields used by this loader include:

  • dependencies: an object of npm dependencies to install into the module directory
  • before / after: ordering constraints (string or array; supports "*")
  • priority: numeric priority used only when ordering constraints form a cycle

The loader normalizes and augments module metadata at load time:

  • m.__root / m.rootPath: absolute path to the module folder
  • m.__name: directory name (module name)
  • m.__global: boolean whether module is global
  • m.files: snapshot list of files under the module directory (excluding node_modules and .git)

3) Dependencies

Modules may declare npm dependencies inside module.json:

{
  "dependencies": {
    "express": "^4.19.0"
  }
}

Behavior:

  • Dependencies are installed synchronously during module loading.

  • Installation is performed into <moduleRoot>/node_modules.

  • waw installs all declared deps in a single npm i call using:

    • --no-save --no-package-lock --no-audit --no-fund --loglevel=error
    • --legacy-peer-deps
  • The loader checks installed versions with a small semver matcher supporting:

    • exact x.y.z
    • ^x.y.z, ~x.y.z
    • >=x.y.z
    • * / latest

No package.json is created inside modules by the loader.


4) Module ordering (before / after)

Modules may define ordering rules in module.json:

{ "before": "*" }
{ "after": "core", "before": "*" }

Rules:

  • before / after accept a string or an array
  • "*" means “all modules except those explicitly constrained in the opposite direction”
  • Ordering is a stable topological sort based on discovery order
  • If constraints produce a cycle, waw falls back to sorting by priority (descending)

5) CLI commands (cli.js)

A module may provide CLI commands by including a file named exactly cli.js.

Example:

// cli.js
module.exports.love = function (waw) {
  console.log("waw loves you :)");
  process.exit(0);
};

Run:

waw love

Dispatch rules:

  • waw reads the raw command from process.argv[2].

  • CLI files are scanned from the last module to the first (later modules override earlier ones).

  • Only files with base name cli.js are considered (not *.cli.js).

  • Matching is attempted in this order:

    1. exact key match with raw command (ex[cmdRaw])
    2. exact key match with lowercased command (ex[cmd])
    3. case-insensitive scan of exported keys
  • cli.js may export:

    • an object of command functions, and/or

    • a function (cmdRaw, waw) => boolean|void

      • If it returns false, it is treated as “not handled” and waw continues scanning.
      • Any other return value (or no return) is treated as handled.

When a command is executed, the command receives a context object (see below) and the process is expected to exit if appropriate.


6) Runtime (index.js)

If no CLI command is handled, waw starts the runtime using nodemon.

Nodemon runs util.runtime.js and watches:

  • Project:

    • <project>/server
    • <project>/angular.json
    • <project>/react.json
    • <project>/vue.json
    • <project>/config.json
  • Global waw install:

    • <waw>/server
    • <waw>/config.json

When runtime starts, waw sequentially loads each module’s index.js:

  • If <moduleRoot>/index.js exists and exports a function, it is called as await func(waw).
  • Errors are caught and printed; loading proceeds to the next module.

The waw context

Every CLI command and runtime module receives a shared waw object containing:

Core properties

  • argv — CLI args after waw (process.argv.slice(2))
  • projectPath — current working directory
  • modulesPath — resolved modules directory in the project (defaults to <project>/server)
  • wawPath — directory of the globally installed waw package
  • wawModulesPath<wawPath>/server
  • configPath / configServerPath — project config file paths
  • wawConfigPath / wawConfigServerPath — global config file paths
  • config — merged config snapshot (global + project)
  • projectType — one of: angular | react | vue | wjst | waw | ""

FS helpers

  • exists(...parts)
  • isFile(...parts)
  • isDir(...parts)
  • ensureDir(...parts)
  • rm(...parts)
  • readText(path, fallback?)
  • writeText(path, data)
  • readJson(path, fallback?)
  • writeJson(path, obj, pretty = true)
  • readWrite(fromPath, toPath, replaceMap)

Utilities

  • terminal — interactive CLI helper (ask/confirm/choose + spinner)
  • git — git workflows utility (init, attach, forceSync, publish, etc.)

Events

  • emit(event, ...args)
  • on(event, fn)
  • once(event, fn)
  • off(event, fn)

Extra fields injected by the loader

When running CLI commands, waw injects these additional fields:

  • modules — ordered list of loaded modules
  • module — current module object
  • module_root — current module root path
  • module_config — current module config object (module.json content + loader metadata)

What waw is not

  • Not a backend framework
  • Not tied to Express/MongoDB/etc.
  • Not a generator by default
  • Not async-heavy
  • Not opinionated

Those belong in modules.


Contributing

Contributions are welcome:

  • Improve the loader (keep it small)
  • Improve documentation
  • Create modules
  • Report bugs

See CONTRIBUTING.md.


License

MIT © Web Art Work

About

One Framework for Everything. ( Websites / Mobile apps / Desktop apps )

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors