# Per-app dependencies and versions

What wu install aggregates, how it resolves majors, and when it creates local toolchains.

<span id="instalar-desde-declaraciones-de-cada-parte"></span>

<span class="section-anchor" id="section-1"></span>

## Installing from each part's declarations

```bash
wu install
```

`wu i` is an alias. The command aggregates shell and app declarations, edits the root manifest and invokes npm. It adds `wu-framework` and `esbuild` from the catalog if nobody declares them. `wu add` and the `wu create` wizard use the same installer.

Add dependencies to the microapp or shell that consumes them, then run `wu install` again. Running only `npm install` at the root does not recalculate the aggregate or `.wu-deps.json`.

<span id="resolución-de-bibliotecas"></span>

<span class="section-anchor" id="section-2"></span>

## Library resolution

Compatible ranges are intersected: `^19.0.0` and `^19.3.0` produce `^19.3.0`. Incompatible groups use aliases; the newest group keeps the main name. The resolver distinguishes 0.x lines (`zone.js--0.15`) and incompatible pins within one major (`lodash--4.17.20`). Each package appears in one root section; `dependencies` wins if any app declares it there.

```json
{
  "dependencies": {
    "react": "^19.0.0",
    "react--17": "npm:react@^17.0.0"
  }
}
```

The override map links each original import to the correct alias:

```json
{
  "mf-legacy": {
    "react": "react--17"
  }
}
```

Keys are directories, such as `mf-legacy`, not catalog names, such as `legacy`. Development and build load that map. This does not mean every React consumer shares one instance: each compatible set must resolve the correct identity.

Resolution supports `^`, `~`, comparators, exact versions, wildcards, partial versions, hyphen ranges and up to 32 `||` alternatives. It does not apply npm’s extra rule restricting prereleases to the comparator’s version tuple: check the installed version when using prereleases. Non-SemVer values, such as dist-tags or Git URLs, remain explicit pins and differing declarations produce a warning.

<span id="identidad-de-módulos-en-desarrollo"></span>

<span class="section-anchor" id="section-3"></span>

## Module identity in development

Each import resolves from its source file, respecting local and nested `node_modules`, pnpm, links and `.wu-deps.json`. URLs identify version and location. Packages in `shared`, and always `wu-framework`, resolve from the root as one instance; an incompatible local copy produces a warning. Do not put a library in `shared` if different versions must coexist.

<span id="toolchains-distintas"></span>

<span class="section-anchor" id="section-4"></span>

## Different toolchains

Vite, plugins, and other build tools need a different strategy. The algorithm chooses the major with the most declarations among apps still sharing the root; ties favor the higher version. Incompatible applications move to local installation. This decision repeats because removing an app's votes may change another majority.

```json
{
  "mf-vite-antiguo": {
    "_toolchain": "local"
  }
}
```

The CLI installs inside that app, and the build uses its `node_modules/vite`. The map is rewritten on every installation or removed if no overrides remain. WU-managed local trees include provenance information so they can be removed when no longer needed.

<span id="dependencias-locales"></span>

<span class="section-anchor" id="section-5"></span>

## Local dependencies

A `file:` declaration is preserved and rewritten relative to the root. For example, `file:../ui` inside `mf-panel/package.json` becomes a path to `ui/` from the aggregated manifest. The current collector skips `link:` and `workspace:` declarations; this mechanism does not implement a complete npm workspace manager.

<span id="reescritura-del-manifiesto-raíz"></span>

<span class="section-anchor" id="section-6"></span>

## Rewriting the root manifest

A root manifest without `_wu` is rejected with exit code `1`. `--force` authorizes managing it while preserving its fields and dependencies; if the JSON is broken, it replaces it and keeps the original in `package.json.bak`.

```bash
wu install --force
```

`--force` and `-f` belong to WU: they enable rewriting, not general passthrough of npm options. There are no public `--frozen-lockfile`, `--offline`, or `--no-install` options, or package-manager selector.

`_wu.managed` records dependencies written by WU so only entries no app still declares can be removed. Custom scripts, workspaces, overrides, engines and manually added dependencies are preserved. `dev` and `build` are created only when absent. JSON writes are atomic with a `.bak` copy; an older `_wu` marker is migrated on the first installation.

<span id="migrar-un-proyecto-a-cli-12"></span>

<span class="section-anchor" id="section-7"></span>

## Migrate a project to CLI 1.2

`wu update` updates the global tool. `wu upgrade` compares the shell and apps with the installed CLI catalog, which in 1.2.0 targets WU Framework `^4.0.0`. First review the [framework migration](/docs/guides/releases/): updating ranges does not automatically migrate all APIs.

```sh
wu upgrade --dry-run
wu upgrade --json
wu upgrade --yes
wu install
wu doctor --json
wu build
```

Without flags, `upgrade` shows the plan and asks for confirmation. `--dry-run` writes nothing; `--json` applies only with `--yes`; `--check` returns `2` when changes are pending. It never downgrades: newer or open ranges and non-SemVer protocols are preserved. Exact pins require `--force`, which still cannot downgrade them. Missing dependencies are reported without being added. An error or confirmation without a terminal returns `1`.

Migrations recognize older templates and save `<file>.bak`: unique Stencil tags, removal of unused `@stencil/core`, an Astro shell using DOM APIs, selectors with `CSS.escape`, missing `.gitignore` rules and Qwik/Svelte runtimes in `shared`. Changes are idempotent; customized sources that do not match are left intact with a note. The command does not install dependencies: finish with `wu install`.

Range example: a declared `wu-framework: ^3.2.1` becomes `^4.0.0`; `react: ^19.4.0` stays because it is ahead of the catalog’s `^19.3.0`; `react: 19.2.0` keeps its pin unless `--force` is used. Do not add `_wu.managed` manually: `wu install` maintains it.

<span id="salidas-y-errores"></span>

<span class="section-anchor" id="section-8"></span>

## Outputs and errors

Invalid JSON in the configuration or an app manifest stops installation with a line, column and exit code `1`, before writing. Write failures, a foreign root manifest without `--force`, and npm failures in the root or local toolchains also exit with `1`. With library conflicts, the root invocation includes `--legacy-peer-deps`.

<span id="referencia-de-implementación"></span>

<span class="section-anchor" id="section-9"></span>

## Implementation references

- `wu-cli/src/commands/install.zig`
- `wu-cli/src/commands/upgrade.zig`
- `wu-cli/src/commands/codemods.zig`
- `wu-cli/src/config/semver.zig`
- `wu-cli/src/config/json_doc.zig`
- `wu-cli/src/runtime/module_graph.zig`
- `wu-cli/tests/install-preserva.test.cjs`
- `wu-cli/tests/upgrade.test.cjs`
- `wu-cli/tests/dev-module-resolution.test.cjs`