MemberJunction / MemberJunction/MJ
mj app install puts shared *-actions packages in the client bootstrap, pulling Node built-ins into the Explorer bundle and breaking the build
- Dominant language
- TSQL
- Stars
- 29
- Forks
- 6
- Avg merge
- 2d 1h
- Merged PRs (30d)
- 323
Description
Found while installing Open Apps into a fresh MJ `6.1.0-edge.6` distribution host on 2026-09-12.
## What happens
After `mj app install` of any BizApp chain (here: bizapps-common → bizapps-tasks → bizapps-forms), the host Explorer **cannot build or serve**. Both `ng build` and `ng serve` die with dozens of Node built-ins that cannot be resolved for the browser:
```
✘ [ERROR] Could not resolve "fs"
node_modules/@google-cloud/storage/build/esm/src/bucket.js:17:20:
17 │ import * as fs from 'fs';
✘ [ERROR] Could not resolve "path"
✘ [ERROR] Could not resolve "stream"
✘ [ERROR] Could not resolve "node:async_hooks"
✘ [ERROR] Could not resolve "child_process"
✘ [ERROR] Could not resolve "crypto"
```
## Cause
`mj app install` appends **`shared`**-role packages to the **client** list as well as the server list. The generated client bootstrap therefore namespace-imports the actions packages into the Angular bundle:
```ts
// ===== BEGIN Open App client bootstrap (managed by `mj app` / `mj codegen manifest`) =====
import * as __openAppClient2 from '@mj-biz-apps/common-actions';
import * as __openAppClient6 from '@mj-biz-apps/tasks-actions';
import * as __openAppClient9 from '@mj-biz-apps/forms-actions';
```
Each `*-actions` package depends on `@memberjunction/actions`, which reaches `@memberjunction/storage`, which reaches `@google-cloud/storage`, which imports `fs`, `path`, `stream`, `crypto`, `child_process` and `node:async_hooks`.
An actions package is Node-side by construction. Marking it `shared` is what the manifest format offers and what every first-party BizApp does, so this hits the whole family rather than one app.
## Verification
Setting `Enabled: false` on only the `*-actions` (and `tasks-core`) entries in `dynamicPackages.client`, regenerating the manifest, and restarting `ng serve` produced a clean compile and a working Explorer on the same host. Nothing else changed.
## Suggested fix
Either stop appending `shared` packages to the client bootstrap by default, or give the manifest a way to say a shared package is server-only — a `platform: 'node' | 'browser' | 'both'` on the package entry, defaulting to `both` for entities and `node` for actions.
## Also seen alongside
The client entries are written with `StartupExport: undefined` even when the manifest declares one (e.g. `@mj-biz-apps/forms-ng` declares `LoadBizAppsFormsClient`). Server entries carry theirs correctly. Harmless today — the client bootstraps by namespace import — but the config records something false.
## Environment
MJ `v6.1.0-edge.6`, distribution install, `@mj-biz-apps/{common,tasks,forms}` installed via `mj app install`.
Contributor guide
Research direction
Start with the `mj app install` and `mj codegen manifest` paths that write `dynamicPackages.client` and the generated client bootstrap. Compare how shared packages and `StartupExport` are written for client versus server entries, then verify that the installed BizApp chain builds and serves without Node built-in resolution errors while server entries retain their exports.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- angular, node.js, typescript
- Domain
- build-system, cli, frontend
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 55/100