Current section
Files
Jump to
Current section
Files
README.md
**English** | [Korean](README.ko.md) | [Japanese](README.ja.md)
# glendix
`glendix` is the JavaScript-target build and rendering bridge for Mendix
Pluggable Widgets written in Gleam.
Its package boundary is explicit:
- **glendix** owns Pluggable Widgets Tools orchestration, widget definition
editing, external npm React bindings, and the Lustre-to-React bridge;
- **mendraw** owns Mendix client values and bindings generated from installed
`.mpk` assets;
- **mxpak** owns Marketplace search, package download, cache, lockfiles, and
workspace deduplication;
- **glendam** owns generic browser automation.
Glendix does not implement Marketplace access or browser automation.
## Install
```toml
[dependencies]
glendix = ">= 5.2.0 and < 6.0.0"
```
Add `mendraw` only when the project uses Mendix client values or installed MPK
components, and add/use `mxpak` only when package acquisition is required.
A widget project's `package.json` normally includes the Mendix Pluggable Widgets
Tools and their React peer dependencies.
## Experimental native package managers
Glendix can isolate Mendix Pluggable Widgets Tools from the project's package
manager and JavaScript runtime:
```toml
[javascript]
runtime = "bun"
[tools.glendix]
pm = "bun"
compatibility = "experimental-native"
```
| `pm` | Gleam runtime | Dependency install |
| --- | --- | --- |
| `npm` | `node` | `npm install` |
| `yarn` | `node` | `yarn install` |
| `pnpm` | `node` | `pnpm install` |
| `bun` | `bun` | `bun install` |
| `deno` | `deno` | hoisted manual `deno install` with the required lifecycle scripts allowed |
In this mode, Glendix invokes the installed Pluggable Widgets Tools CLI with the
selected runtime and places temporary `node`, `npm`, and `npx` compatibility
shims only on that child process's `PATH`. The shims satisfy the tool's hard
Node/npm checks and route supported install, run, and exec calls back to the
selected package manager. They are removed after the command; no global binary,
lockfile, or package-manager setting is replaced. Interactive npm lockfile
migration is disabled, so the selected manager's lockfile remains authoritative.
This is an explicit experimental compatibility mode, not a complete npm
emulator. npm and Bun projects must allow or trust the lifecycle scripts
required by the Mendix toolchain, Yarn projects must use the `node-modules`
linker, and pnpm projects must allow the same native build scripts. Deno
projects must grant their Gleam commands the required permissions and allow
those scripts during install. Invoke dependency modules with an explicit
matching runtime, for example
`gleam run -m glendix/build --runtime bun` or `--runtime deno`; use
`--runtime node` for npm, Yarn, and pnpm.
## Basic widget
```gleam
import mendraw/mendix
import redraw
import redraw/dom/attribute
import redraw/dom/html
pub fn widget(props: mendix.JsProps) -> redraw.Element {
let title = mendix.get_string_prop(props, "title")
html.section([attribute.class("widget")], [html.text(title)])
}
```
This example composes Glendix with Mendraw in the application. Glendix itself
remains independently usable for external React bindings and Lustre rendering.
## Lustre bridge
```gleam
import glendix/lustre as glendix_lustre
import gleam/int
import lustre/effect
import lustre/element
import lustre/element/html
import lustre/event
import redraw
type Model { Model(count: Int) }
type Message { Increment }
fn update(model: Model, message: Message) -> #(Model, effect.Effect(Message)) {
case message {
Increment -> #(Model(model.count + 1), effect.none())
}
}
fn view(model: Model) -> element.Element(Message) {
html.button([event.on_click(Increment)], [
html.text("Count: " <> int.to_string(model.count)),
])
}
pub fn component() -> redraw.Element {
glendix_lustre.use_tea(#(Model(0), effect.none()), update, view)
}
```
## External npm React components
Configure exports in `gleam.toml`:
```toml
[tools.glendix.bindings]
recharts = ["PieChart", "Pie"]
```
Install the npm package, then run `gleam run -m glendix/install`. Glendix owns
both component lookup and element construction; Mendraw is not required:
```gleam
import gleam/result
import glendix/binding
import redraw
import redraw/dom/attribute
pub fn pie_chart(
attributes attributes: List(attribute.Attribute),
children children: List(redraw.Element),
) -> Result(redraw.Element, binding.BindingError) {
use module <- result.try(binding.module("recharts"))
use component <- result.try(binding.resolve(module, "PieChart"))
Ok(binding.element(component, attributes, children))
}
```
`binding.element_` creates an element with children only, and
`binding.void_element` creates one without children.
## WebAssembly dependencies
Glendix automatically packages browser WebAssembly modules referenced with the
standard static URL form used by browser toolchains:
```javascript
new URL("./engine_bg.wasm", import.meta.url)
```
The generated Rollup configuration copies each binary into the widget
`assets/` directory with a deterministic content hash. It rewrites the runtime
URL to the correct Mendix route for both AMD and ES module outputs, so the same
MPK works in classic and modern web clients. Query strings and fragments are
preserved, and repeated references to one binary emit a single asset.
Only static relative `.wasm` references can be packaged automatically. A
missing referenced file fails the build with its module and resolved path.
Projects that replace Glendix's generated `rollup.config.mjs` must compose
equivalent asset handling in their custom configuration.
## Installed Marketplace widgets
Package acquisition is a separate step owned by mxpak:
```toml
[tools.mxpak]
mode = "extract"
[tools.mxpak.widgets.Charts]
version = "3.0.0"
```
```sh
mxp install
gleam run -m mendraw/install
gleam run -m glendix/install
gleam run -m glendix/build
```
- `mxp install` writes package assets to `build/widgets/`.
- `mendraw/install` generates typed MPK bindings.
- `glendix/install` installs JavaScript dependencies and generates Glendix npm
bindings.
- `glendix/build` creates the production `.mpk`.
Projects that do not use Marketplace widgets omit the first two steps.
## Commands
| Command | Responsibility |
| --- | --- |
| `gleam run -m glendix/install` | Install JS dependencies and generate Glendix npm bindings |
| `gleam run -m glendix/define` | Edit widget property definitions |
| `gleam run -m glendix/dev` | Run the development build/server |
| `gleam run -m glendix/build` | Build a production `.mpk` |
| `gleam run -m glendix/start` | Connect to the configured Mendix test project |
| `gleam run -m glendix/lint` | Run lint checks |
| `gleam run -m glendix/lint_fix` | Apply lint fixes |
| `gleam run -m glendix/release` | Run the release build |
## Development
```sh
gleam deps download
gleam format --check
gleam check
gleam build --warnings-as-errors
gleam docs build
gleam test --runtime bun
```
## License
[MIT License](LICENSE)