feature:compile

Table of contents

  1. Introduction
  2. Compiling every feature of the product
  3. Rebuilding on every change
  4. Building for production
  5. Checking a bundle against its manifest
  6. A feature with frontend/
  7. Declaring the globals of the page
  8. Shipping vendored wheels
  9. The toolchain
  10. Legacy features
  11. Reference
    1. Options
    2. Errors
  12. Requirements
  13. See also

Introduction

feature:compile builds the JavaScript and CSS bundle of a feature. A feature with a frontend/ folder builds in the SPLENT toolchain image, against its own dependencies, and needs no product. Run it after you change the frontend code, or leave it watching.

splent feature:compile notes
🚀 Compiling splent_feature_notes in the SPLENT toolchain...
  npm      installing frontend/node_modules from the lock (npm ci)...
âś… Successfully compiled splent_feature_notes in development mode!

The bundle lands in assets/dist, with a manifest of what it holds in assets/meta/manifest.json.


Compiling every feature of the product

splent feature:compile

Without a name, it builds every feature the selected product declares. Pinned features are skipped, since their release carries the bundle. When any build fails, it ends with Compilation failed for N feature(s): <features> and exits 1.


Rebuilding on every change

splent feature:compile notes --watch
đź‘€ Watching splent_feature_notes in development mode...
    log: docker logs -f splent_frontend_splent_feature_notes    stop: docker stop splent_frontend_splent_feature_notes

The rebuilds run in a detached container, splent_frontend_<feature>. Starting it again replaces the one that was running.


Building for production

splent feature:compile notes --prod

A production build is minified, has no source maps, and writes the licence texts of what it ships to assets/meta/third_party.json. FLASK_ENV=production does the same.

--release is what feature:release runs. A production build into an emptied assets/dist, which fails for a feature that would be skipped.


Checking a bundle against its manifest

splent feature:compile --verify
❌ splent_io/splent_feature_notes: the bundle does not match its manifest
     assets/dist/notes.bundle.js changed after the build

--verify builds nothing and needs no Docker. Every file the manifest lists must be in assets/dist with its sha256, nothing else may be, and the lock must be the one the build installed. It exits 1 on any mismatch.

A pinned feature is checked where the product finds it, and must hold a production build. Each feature docker/frontend.lock.json lists must carry the manifest and version it names. The production Dockerfile runs --verify, so an image only serves the bundles its releases built.


A feature with frontend/

feature:create --frontend writes frontend/ for a new feature, and feature:frontend:init adds it to an existing one.

splent_feature_notes/
├── frontend/
│   ├── package.json          # dependencies, peers and the "splent" block
│   ├── package-lock.json     # committed
│   ├── .npmrc                # save-exact, ignore-scripts, engine-strict
│   ├── webpack.extra.js      # optional, merged over the preset
│   └── node_modules/         # ignored
└── src/splent_io/splent_feature_notes/assets/
    ├── js/                   # your sources
    ├── dist/                 # the bundle, served
    └── meta/                 # manifest and licence data, never served
{
  "name": "@splent-io/splent_feature_notes",
  "private": true,
  "license": "LGPL-3.0-or-later",
  "engines": { "node": "^24.22.1", "npm": "^11.19.1" },
  "dependencies": { "chart.js": "4.5.1" },
  "peerDependencies": { "bootstrap": "^5.2.0" },
  "splent": {
    "schema": 1,
    "entries": { "notes": "./js/scripts.js" }
  }
}

The feature brings no webpack and no config, the toolchain does. Manage dependencies with feature:npm.

Bootstrap and feather-icons come from the shell. Declare them under peerDependencies, and import { Modal } from "bootstrap" becomes window.bootstrap. As a dependency, or by an inner path such as bootstrap/js/dist/modal, they stop the build. A singleton such as dropzone may be bundled by one feature only, which product:validate checks.

splent key What it declares
entries {"<name>": "./js/scripts.js"} builds dist/<name>.bundle.js. {"import": "...", "type": "module"} makes an ES module. {} builds none
shell What templates take from the shell, such as {"bootstrap": "^5.2.0", "bootstrap-css": "^5.2.0", "icons": "feather"}
provides What the feature puts on the page, {"<name>": {"kind": "lib", "global": "<global>", "version": "<semver>"}}, or kind api
consumes What it takes from another feature, {"<name>": {"feature": "<provider>", "range": "^1"}}
vendored Files from no npm package, see vendored wheels
csp Sources its pages need, such as {"script-src": ["'wasm-unsafe-eval'"]}, which the product approves
licenseTexts {"<package>": "<path in frontend/>"}, for a package without its licence files
licenseExceptions [{"package", "reason", "expires"}], what the licence gate lets through until a date

version and scripts are not read.


Declaring the globals of the page

Every build lints your own modules for names the page must define. A name passes when the browser defines it or something declares it.

Global Declared by
SPLENT Always, the framework’s runtime
bootstrap, feather A peer dependency on the singleton, or its entry in splent.shell
The global of a splent.provides entry The feature itself
The first segment of a splent.consumes key The feature it consumes from
__webpack_public_path__, __webpack_nonce__ webpack

Any other name stops the build, here and at the release gate.

[charts] ERROR in src/splent_io/splent_feature_charts/assets/js/scripts.js:12:5: 'KTApp' is not defined. A global of the page is declared where it comes from (a peerDependency, splent.shell, splent.consumes), or with a line // splent-global: <name> <why>.

When the page has the name for another reason, declare it in the file that reads it, with the reason. /* global */ and eslint-disable comments are not read.

// splent-global: Plotly drawn by the product's own layout

Shipping vendored wheels

An entry of splent.vendored whose path is under dist/ is copied there as it is, such as a Python wheel an in-browser runtime installs.

"vendored": [
  {"name": "solver", "version": "1.8", "license": "MIT", "source": "pypi",
   "path": "dist/runtime/solver-1.8-py3-none-any.whl", "sha256": "…"},
  {"name": "engine", "version": "0.2.0", "license": "GPL-3.0-or-later",
   "source": "vendor/ of this repository", "from": "wheels/engine-0.2.0-py3-none-any.whl",
   "path": "dist/runtime/engine-0.2.0-py3-none-any.whl", "sha256": "…"}
]

Without from, the build fetches the wheel with pip download from pypi or the https URL in source, into the untracked frontend/vendored/. With from, it is a file the feature keeps under frontend/. A file with another sha256 stops the build.


The toolchain

The image splent-frontend:<hash> is built here the first time a command needs it, from splent_cli/toolchain/ in the CLI’s package. The tag is the sha256 of those files, so the same CLI always builds the same image. It carries Node 24.22.1, npm 11.19.1, webpack 5 with its loaders and plugins, eslint and the SPLENT preset.

A build runs with --network none, and can only write assets/dist and assets/meta. npm ci runs only when the lock changed. Modules resolve only from the feature’s own node_modules, and two features never collide on one page. frontend/webpack.extra.js, an object or a function of (preset, {mode, feature}), is merged over the preset.


Legacy features

A feature without frontend/package.json builds with its own assets/js/webpack.config.js, inside the product’s running web container, against the product’s node_modules.

splent feature:compile notes --dev

--dev and --prod choose the container, <product>_web or <product>_web_deploy, and default to SPLENT_ENV. It works from the host too.

Inside the product’s web container there is no Docker daemon, so a feature with frontend/ is left to the CLI, with a note.


Reference

Options

Option Description
FEATURE_NAME Optional. notes, splent_feature_notes or splent-io/splent_feature_notes. Without it, every feature of the product
--watch Rebuild on every change. Ignored in production mode
--dev Legacy features only. Run in the development container, without changing the build mode
--prod Production build. Legacy features also run in the production container
--release The build a release ships, into an emptied assets/dist. Not with --watch
--verify Build nothing, check each bundle against its manifest. Not with --watch or --release

Errors

Message What to do
frontend/package-lock.json is missing Install the dependencies with feature:npm, which writes the lock
frontend/package.json changed after the lock was written Run splent feature:npm <feature> install
'<name>' is not defined Declare the global
No running container found for <product> (<env>) Legacy feature. Run splent product:up --<env>
The <product> web container runs the workspace at <path>, not this one Legacy feature. Start this workspace’s product
<feature> is pinned (<version>): a release builds the bundle of the working copy --release needs the editable copy

Requirements

  • A feature with frontend/ needs Docker, and the network the first time the image builds and whenever the lock changes.
  • A legacy feature, or no feature named, needs a selected product (SPLENT_APP). A legacy build also needs the product’s web container running, with node_modules installed.

See also


Back to top

splent. Distributed by an LGPL license v3. Contact us: drorganvidez@us.es