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

Open
#4,428 0 comments 0 reactions 0 assignees View on GitHub
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

Open the contributing 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.