wex_addon_dev_javascript
Version: 8.1.5
wex-addon-dev-javascript extends wex for JavaScript and TypeScript developers: it enforces a standard project layout — requiring package.json, tsconfig.json, .npmrc, src/, tests/, and the corresponding .gitignore rules — and in local environments symlinks locally-developed npm packages directly into a running container's node_modules/ so monorepo packages resolve without a registry publish cycle. It also contributes a node service and a vite service, each backed by Docker Compose, where the vite service patches allowedHosts in vite.config.ts for reverse-proxy use and the node service handles lockfile refresh, annotated-tag release, and registry polling for npm package suites managed through wex.
Table of Contents
- Installation
- Quickstart
- Tests
- Architecture
- Integration in the Suite
- Dependencies
- Versioning & Compatibility Policy
- License
- About us
- Known Limitations & Roadmap
- Status & Compatibility
- Useful Links
- Migration Notes
Installation
pip install wexample-wex-addon-dev-javascript
Requires Python >=3.10.
Quickstart
Install the package:
pip install wexample-wex-addon-dev-javascript
The public entry point is JavascriptAddonManager, defined in src/wexample_wex_addon_dev_javascript/javascript_addon_manager.py:
from wexample_wex_addon_dev_javascript.javascript_addon_manager import JavascriptAddonManager
Pass it to the kernel's setup() call to register the JavaScript addon slot:
from wexample_wex_core.common.kernel import Kernel
kernel = Kernel()
kernel.setup(addons=[JavascriptAddonManager])
After setup() returns, the kernel recognises three workdir types: javascript, javascript-package, and javascript-packages-suite. Any workdir resolved against a directory holding a package.json will be matched to the appropriate class.
The addon also contributes four service commands to the node and vite namespaces. Wire locally-developed npm packages into a running container's node_modules/ — replacing the registry copy with a live symlink — with:
wex node::service/install_local
Refresh the lockfile in the container after a package.json dependency change (the command detects whether the project uses npm, pnpm, or Yarn from whichever lockfile is present):
wex node::service/refresh_lock --npm_packages "@vendor/my-lib"
Patch vite.config.ts so the Vite dev server accepts requests from any host — required when the service runs behind a reverse proxy:
wex vite::service/install
Check whether the Vite dev server inside its container is responding:
wex vite::service/ready
Tests
This project uses pytest for testing and pytest-cov for code coverage analysis.
Installation
First, install the required testing dependencies:
.venv/bin/python -m pip install pytest pytest-cov
Basic Usage
Run all tests with coverage:
.venv/bin/python -m pytest --cov --cov-report=html
Common Commands
# Run tests with coverage for a specific module
.venv/bin/python -m pytest --cov=your_module
# Show which lines are not covered
.venv/bin/python -m pytest --cov=your_module --cov-report=term-missing
# Generate an HTML coverage report
.venv/bin/python -m pytest --cov=your_module --cov-report=html
# Combine terminal and HTML reports
.venv/bin/python -m pytest --cov=your_module --cov-report=term-missing --cov-report=html
# Run specific test file with coverage
.venv/bin/python -m pytest tests/test_file.py --cov=your_module --cov-report=term-missing
Viewing HTML Reports
After generating an HTML report, open htmlcov/index.html in your browser to view detailed line-by-line coverage information.
Coverage Threshold
To enforce a minimum coverage percentage:
.venv/bin/python -m pytest --cov=your_module --cov-fail-under=80
This will cause the test suite to fail if coverage drops below 80%.
Architecture
The addon is a pure Python package that extends wex with JavaScript and TypeScript support. It has four layers: an addon manager that registers workdir types, a workdir hierarchy that enforces project layout and owns the release lifecycle, a file layer that controls what package.json and tsconfig.json contain when written to disk, and a service layer that contributes node and vite Docker service definitions with their commands.
Entry point
src/wexample_wex_addon_dev_javascript/javascript_addon_manager.py is the only class the host kernel needs. It extends AbstractAddonManager and returns three workdir types from get_workdir_types():
| key | class |
|---|---|
javascript |
JavascriptWorkdir |
javascript-package |
JavascriptPackageWorkdir |
javascript-packages-suite |
JavascriptPackagesSuiteWorkdir |
The kernel resolves a directory to the right class by matching that key against the workdir type declared in the project's wex config.
Workdir layer
The three classes form a linear inheritance chain.
JavascriptWorkdir
src/wexample_wex_addon_dev_javascript/workdir/javascript_workdir.py is the base. It extends CodeBaseWorkdir (from wexample-wex-addon-app) and WithAiWorkdirMixin. Its prepare_value() declares the required filesystem layout that wex will enforce: package.json, tsconfig.json, .npmrc, a src/ tree, a tests/ tree, and .gitignore rules covering node_modules/, dist/, build/, .npm, and .eslintcache. JS/TS files under src/ and tests/ are captured by a ChildrenFilterOption that matches *.js|jsx|ts|tsx and applies the BiomeOption from wexample-filestate-javascript. The class also appends JavascriptOptionsProvider to the options chain and returns a JavascriptPackageJsonFile from get_app_config_file().
JavascriptPackageWorkdir
src/wexample_wex_addon_dev_javascript/workdir/javascript_package_workdir.py extends JavascriptWorkdir and adds everything a publishable npm package needs.
Naming. get_project_name() returns @{vendor}/{kebab-case-name}, giving packages their scoped npm identity.
Layout addition. prepare_value() appends .github/workflows/publish.yml to the enforced file tree. The content is read from the bundled resource src/wexample_wex_addon_dev_javascript/resources/package_publish.yml — a GitHub Actions workflow that publishes to npm on any v* tag push.
Release lifecycle. release() runs three steps in order:
_refresh_lockfile()— detects which lockfile is present (package-lock.json,pnpm-lock.yaml, oryarn.lock) and runs the matching lock-only refresh command on the host machine.super().release()— inherited bump, commit, and publish flow;_publish()overrides the publish step to create an annotated git tag (v{version}) and push it to the configured deployment remote, which triggers the CI workflow above._wait_for_registry()— pollsNpmRegistryGateway.has_version()every 30 s for up to 20 minutes before the suite loop advances to the next dependent package.
Version bump classification. _classify_version_bump() inspects the git diff of src/ since the last tag: no changes → minor bump; whitespace-only diff → minor; non-TypeScript files only → intermediate; any .ts/.tsx change → major.
JavascriptPackagesSuiteWorkdir
src/wexample_wex_addon_dev_javascript/workdir/javascript_packages_suite_workdir.py extends FrameworkPackageSuiteWorkdir. It discovers child packages by looking for directories inside npm/ that contain a package.json, and resolves each child as a JavascriptPackageWorkdir.
File layer
NodePackageJsonFile
src/wexample_wex_addon_dev_javascript/file/node_package_json_file.py composes AppDependenciesConfigFileMixin with JsonFile. It exposes the dependency-manifest API (add_dependency, add_dependency_from_string, get_dependencies_versions) and reads dependencies plus peerDependencies as the set of declared runtime constraints. Any workdir that ships a package.json — including polyglot app manifests — can attach this class.
JavascriptPackageJsonFile
src/wexample_wex_addon_dev_javascript/file/javascript_package_json_file.py extends NodePackageJsonFile. Its dumps() stamps name, version, and repository from the parent workdir before delegating to the JSON serialiser. It also calls _apply_default_publish_config(), which sets type: "module", ensures publishConfig.access defaults to "public", and — when neither exports nor a dist-targeting files array is already present — injects a default exports map ("./*": { types: "./dist/*.d.ts", default: "./dist/*.js" }), a files: ["dist"] list, and a typesVersions block so consumers can import without transpiling sources.
JavascriptTsconfigJsonFile
src/wexample_wex_addon_dev_javascript/file/javascript_tsconfig_json_file.py extends JsonFile. Its dumps() fills in compilerOptions defaults (target: ES2020, module: NodeNext, moduleResolution: NodeNext, rootDir: src, outDir: dist, declaration: true, declarationMap: true, sourceMap: true, strict: false, esModuleInterop: true, skipLibCheck: true, forceConsistentCasingInFileNames: true) and sets include: ["src"], exclude: ["dist", "node_modules", "tests"]. All defaults use setdefault, so anything already in the file is left untouched.
Service layer
Two service namespaces ship as self-contained directories, each containing a service.yml, a docker/docker-compose.yml, and a commands/service/ package.
vite service
Defined in src/wexample_wex_addon_dev_javascript/services/vite/service.yml. The container (${APP_PROJECT_NAME}_vite) runs oven/bun:latest, mounts the app path to /app, persists node_modules in a named volume vite_node_modules, and starts with bun install --no-cache && bun run dev --host. The exposed port is controlled by the VITE_PORT var (default 8080), which the compose file also passes to nginx-proxy via VIRTUAL_PORT.
src/wexample_wex_addon_dev_javascript/services/vite/app_service.py composes the base AppService with AgentContributingServiceMixin, which makes the AI agent declared in src/wexample_wex_addon_dev_javascript/services/vite/ai/agents/main/agent.yml discoverable by wex talk. The agent's system prompt lives in src/wexample_wex_addon_dev_javascript/services/vite/ai/agents/main/about-service.md.
vite::service/install — src/wexample_wex_addon_dev_javascript/services/vite/commands/service/install.py patches vite.config.ts or vite.config.js to add server: { allowedHosts: true } inside defineConfig. It handles two shapes: a bare defineConfig() call and a defineConfig({ ... }) block. The patch is idempotent (skips if allowedHosts is already present).
vite::service/ready — src/wexample_wex_addon_dev_javascript/services/vite/commands/service/ready.py reads app.project_name from the runtime config, resolves the container name as {project_name}_vite, reads VITE_PORT from the service manifest vars, then runs docker exec {container} bun -e "await fetch('http://localhost:{port}')" and returns a BooleanResponse.
node service
Defined in src/wexample_wex_addon_dev_javascript/services/node/service.yml. The container (${APP_PROJECT_NAME}_node) runs node:20-alpine, mounts the app path to /var/www/html, and stays alive with tail -f /dev/null so subsequent docker exec calls can run inside it.
node::service/install_local — src/wexample_wex_addon_dev_javascript/services/node/commands/service/install_local.py reads the local_packages.javascript key from the runtime config (a map of vendor names to package directories). It builds a shell script that first installs the full node_modules tree (using whichever of yarn, pnpm, or npm the project's lockfile identifies), then iterates every directory under /var/www/javascript-dev/{vendor}/, reads its package.json to get the name field, removes the corresponding entry from node_modules/, and replaces it with a symlink to the local source. The script runs inside the service container via docker exec.
node::service/refresh_lock — src/wexample_wex_addon_dev_javascript/services/node/commands/service/refresh_lock.py accepts a --npm_packages option listing the changed packages (for logging), then runs a lockfile-only install inside the container: yarn install if yarn.lock is present, pnpm install --lockfile-only if pnpm-lock.yaml, or npm install --package-lock-only if package-lock.json.
Common utilities
src/wexample_wex_addon_dev_javascript/common/npm_registry_gateway.py is a thin HTTP client over AbstractGateway. Its single public method has_version(package, version) fetches /{encoded_package_name} from the configured registry URL, parses the JSON manifest, and returns True if version appears in the versions map. It accepts an optional token for Bearer auth on private registries. JavascriptPackageWorkdir._wait_for_registry() calls it in a polling loop with a 30-second delay and a 40-attempt ceiling (20 minutes total).
Constants
src/wexample_wex_addon_dev_javascript/const/tags.py declares DomainTag with three values — domain:dev-server, domain:frontend, domain:service — which the service commands attach via the @command(tags=[...]) decorator. Tags govern how wex talk and automated agents filter and describe available commands.
Integration in the Suite
This package is part of the Wexample Suite — a collection of high-quality, modular tools designed to work seamlessly together across multiple languages and environments.
Related Packages
The suite includes packages for configuration management, file handling, prompts, and more. Each package can be used independently or as part of the integrated suite.
Visit the Wexample Suite documentation for the complete package ecosystem.
Dependencies
- attrs: >=23.1.0
- cattrs: >=23.1.0
- wexample-api: >=6.8.0
- wexample-filestate-javascript: >=6.6.0
- wexample-wex-addon-ai: >=15.0.0
- wexample-wex-addon-app: >=31.0.0
Versioning & Compatibility Policy
Wexample packages follow Semantic Versioning (SemVer):
- MAJOR: Breaking changes
- MINOR: New features, backward compatible
- PATCH: Bug fixes, backward compatible
We maintain backward compatibility within major versions and provide clear migration guides for breaking changes.
License
This project is licensed under the MIT License - see the LICENSE file for details.
Free to use in both personal and commercial projects.
About us
Wexample stands as a cornerstone of the digital ecosystem — a collective of seasoned engineers, researchers, and creators driven by a relentless pursuit of technological excellence. More than a media platform, it has grown into a vibrant community where innovation meets craftsmanship, and where every line of code reflects a commitment to clarity, durability, and shared intelligence.
This packages suite embodies this spirit. Trusted by professionals and enthusiasts alike, it delivers a consistent, high-quality foundation for modern development — open, elegant, and battle-tested. Its reputation is built on years of collaboration, refinement, and rigorous attention to detail, making it a natural choice for those who demand both robustness and beauty in their tools.
Wexample cultivates a culture of mastery. Each package, each contribution carries the mark of a community that values precision, ethics, and innovation — a community proud to shape the future of digital craftsmanship.
Known Limitations & Roadmap
Current limitations and planned features are tracked in the GitHub issues.
See the project roadmap for upcoming features and improvements.
Status & Compatibility
Maturity: Production-ready
Python Support: >=3.10
OS Support: Linux, macOS, Windows
Status: Actively maintained
Useful Links
- Homepage: https://github.com/wexample/python-wex-addon-dev-javascript
- Documentation: docs.wexample.com
- Issue Tracker: https://github.com/wexample/python-wex-addon-dev-javascript/issues
- Discussions: https://github.com/wexample/python-wex-addon-dev-javascript/discussions
- PyPI: pypi.org/project/wexample-wex-addon-dev-javascript
Migration Notes
When upgrading between major versions, refer to the migration guides in the documentation.
Breaking changes are clearly documented with upgrade paths and examples.
Metadata
Release files for wexample-wex-addon-dev-javascript 8.1.5
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| wexample_wex_addon_dev_javascript-8.1.5.tar.gz | 28.9 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| wexample_wex_addon_dev_javascript-8.1.5-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 65.2 kB
Release files / wexample_wex_addon_dev_javascript-8.1.5.tar.gz
| Download URL | wexample_wex_addon_dev_javascript-8.1.5.tar.gz |
|---|---|
| Size | 28.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
b7c9ed5dfc66de19e0a439d45b5aef9cabf1bb26ebf4fb7aba984cac3cf5ebdb
|
|
BLAKE2b-256 checksum How to use checksums |
5763757da243fb862a482839449c54faa794adb5934eeb8b1b7fcc310a6463b1
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
pdm/2.25.9 CPython/3.12.3 Linux/6.8.0-139-generic
|
Release files / wexample_wex_addon_dev_javascript-8.1.5-py3-none-any.whl
| Download URL | wexample_wex_addon_dev_javascript-8.1.5-py3-none-any.whl |
|---|---|
| Size | 36.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
a07fda1df3266598cc1a267f97a7ba02af5bb422cec80d98669ddd6019bd1dac
|
|
BLAKE2b-256 checksum How to use checksums |
45b24aef851f5e1ab07fdae261ff9cab33d890ef8a969add817e0c836a447ff9
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
pdm/2.25.9 CPython/3.12.3 Linux/6.8.0-139-generic
|