feat(envs): remove core envs from the manifest, load them as regular envs#10465
feat(envs): remove core envs from the manifest, load them as regular envs#10465davidfirst wants to merge 156 commits into
Conversation
PR Summary by QodoLoad former core envs as regular registry envs with legacy version pinning
AI Description
Diagram
High-Level Assessment
Files changed (15)
|
Code Review by Qodo
1. In-flight load returns early
|
…cope capsules, restore bit-aspect cmd
|
Code review by qodo was updated up to the latest commit c7dd1a7 |
…cted pre-install warning, regen references
|
Code review by qodo was updated up to the latest commit e6418b9 |
|
Code review by qodo was updated up to the latest commit c9eca3d |
…aspect and env envs to core
…eambit/bit into remove-core-envs-from-manifest
|
Code review by qodo was updated up to the latest commit 3f5c24e |
…nv templates on demand - register legacy core env ids as core extension names so their config entries stay name-only (versionless): prevents env-as-dependency edges that created circular TS project references in lane/tag builds - require the aspect env eslint/prettier configs lazily (saves ~400 file reads per bit command) - bit create: fall back to --env for template lookup, incl. templates registered on the generator slot by envs loaded from the global scope - rewrite e2e node-env fixtures to compose on the core aspect env instead of @teambit/node
|
Code review by qodo was updated up to the latest commit 0607c7d |
- teambit.harmony/aspect and teambit.envs/env become regular envs with pinned legacy versions. components using them get the exact released behavior after bit install (the react-free aspect env rewrite is reverted) - move the bit-aspect template and harmony starters to the generator aspect so 'bit create bit-aspect' and 'bit new' work without loading the env - bind manifest deps of legacy envs to pinned versions in scope context (models built when these envs were core don't list them as dependencies) - load the full manifest graph when loading aspects from the global scope - keep legacy core env ids versionless when configured via bit create/env set
|
Code review by qodo was updated up to the latest commit b23b273 |
…ion when available - fixes the ci snap failure: pinned-version copies of workspace components leaked into the load groups and into the snap list - review fixes: index-based BFS queue in getDependentsIds, guard the typescript require in the fallback compiler, suppress legacy-env load failures only when the env package itself is missing, match both quote styles when detecting fixture env packages
|
Code review by qodo was updated up to the latest commit 94eddce |
|
Code review by qodo was updated up to the latest commit 5422e3c |
|
Code review by qodo was updated up to the latest commit b46d725 |
|
Code review by qodo was updated up to the latest commit 9c25b12 |
|
Code review by qodo was updated up to the latest commit e45aa83 |
…om-manifest # Conflicts: # pnpm-lock.yaml # scopes/harmony/cli-reference/cli-reference.docs.mdx
|
Code review by qodo was updated up to the latest commit 34e4544 |
|
Code review by qodo was updated up to the latest commit 5b7b9cb |
|
Code review by qodo was updated up to the latest commit 4caa63f |
|
Code review by qodo was updated up to the latest commit 11930cb |
…ed ci-merge status The fallback (return the configured env id when no aspect entry matches) is correct for getEnvId reporting but too aggressive for calculateEnvId, which feeds addNonLoadedEnvAsComponentIssues: it surfaced a NonLoadedEnv/ExternalEnvWithoutVersion tag-blocker during 'bit ci merge' (env-set on a lane), failing status verification.
| const [inFlightIds, idsToLoad] = partition(notLoadedIds, (id) => | ||
| this.workspace.inFlightAspectsLoads.has(aspectLoadInFlightKey(id)) | ||
| ); | ||
| if (inFlightIds.length) { | ||
| this.logger.debug(`${loggerPrefix} skipping aspects that are already loading: ${inFlightIds.join(', ')}`); | ||
| } | ||
| notLoadedIds = idsToLoad; | ||
| if (!notLoadedIds.length) { | ||
| span.setAttribute('alreadyLoaded', true); | ||
| return []; | ||
| } | ||
| const inFlightAdded = notLoadedIds.map(aspectLoadInFlightKey); | ||
| inFlightAdded.forEach((id) => this.workspace.inFlightAspectsLoads.add(id)); | ||
| try { | ||
| return await this.loadAspectsAfterInFlightCheck(notLoadedIds, span, neededFor, mergedOpts, loggerPrefix); | ||
| } finally { | ||
| inFlightAdded.forEach((id) => this.workspace.inFlightAspectsLoads.delete(id)); | ||
| } |
There was a problem hiding this comment.
1. In-flight key mismatch 🐞 Bug ☼ Reliability
WorkspaceAspectsLoader tracks in-flight loads using the pre-resolved aspect id string, but then resolves ids to versioned ComponentIDs before loading; versionless and versioned requests for the same aspect won’t match and can run duplicate concurrent loads. This undermines the intended cycle/dedup guard and can re-run non-idempotent initialization work in parallel.
Agent Prompt
### Issue description
`WorkspaceAspectsLoader` uses `workspace.inFlightAspectsLoads` to dedupe/break re-entrant loads, but it checks/adds keys based on the *raw requested ids* (`notLoadedIds`). Later in the same flow it resolves those ids to canonical `ComponentID`s (often versioned) and loads by those resolved ids.
If the same aspect/env is requested concurrently once as `scope/name` and once as `scope/name@x.y.z`, the in-flight Set will treat them as different keys (for non-legacy aspects), allowing duplicate concurrent loads.
### Issue Context
The codebase explicitly supports env/aspect references without a version in some flows (e.g. envs-config / legacy ids), so versionless inputs are expected.
### Fix Focus Areas
- scopes/workspace/workspace/workspace-aspects-loader.ts[121-203]
- scopes/envs/envs/legacy-core-envs.ts[57-66]
### Suggested fix
Canonicalize the in-flight key to match the canonical id used for loading:
- Resolve ids (or at least normalize) **before** `inFlightAspectsLoads.has/add/delete`.
- For versionless requested ids, consider using `id.split('@')[0]` as the in-flight key (or store *both* the versionless key and the resolved versioned key) so that later versioned requests map to the same in-flight entry.
- Keep legacy-core-env single-instance semantics intact (current `aspectLoadInFlightKey()` behavior).
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
|
Code review by qodo was updated up to the latest commit 6588503 |
Removes the env aspects (
teambit.react/react,teambit.harmony/node,teambit.harmony/aspect,teambit.envs/env,teambit.mdx/mdx,teambit.mdx/readme) from the core manifest to slim Bit. They now act like any other env, installed from the registry.New default env:
teambit.harmony/empty-env(core). A totally empty env - no compiler, no tester, no preview, no dependency policy. Components with no env configured use it and work fully offline out of the box (add → compile no-op → tag/snap → export). Since it has no behavior, it has nothing to drift when bit itself changes - the one env that is safe to keep core (and versionless in models) forever. To get a dev experience, users configure a real env (bit createflows already do).teambit.harmony/aspectandteambit.envs/envare removed like the rest, with zero behavior change. Their implementation is untouched (react-based, preview and all) - users get the exact released behavior afterbit install(the pinned-version machinery auto-installs them). New envs are created from the bitdev env packages (bit create react-envetc.), so these built-in envs are legacy surface. Thebit-aspecttemplate and the harmony starters moved to the core generator aspect, sobit create bit-aspectandbit newkeep working out of the box (the created aspect needsbit installbefore it loads, like any env).Versionless by design. Config entries for the removed env ids are persisted by name, without a version - exactly as they were when core (registered as core-extension names). Keeping them versionless is deliberate on two counts. First, it keeps the env from becoming a dependency edge of its own components; otherwise an env such as react, whose dependency closure includes components that use it as their env, creates circular TS project references and breaks lane/tag builds. Second, it preserves forward compatibility: a re-tag under the new bit keeps the env id versionless, so a teammate who has not upgraded yet (whose bit still ships these as core) can import the re-tagged component and resolve the env - instead of receiving a versioned id their bit has no component for. The alternative (showing the component as modified and pinning the env on the next tag) would silently break not-yet-upgraded consumers.
Backward compatibility. Old components have the removed envs saved without a version.
legacy-core-envs.tsmaps them to pinned versions, applied only at the resolution/loading/install level - stored objects are never mutated. Versionless legacy ids match the env slot ignoring version,bit installauto-adds their packages, and single-instance semantics are enforced (a loaded version is reused rather than loading another copy). Not-installed legacy envs fail fast with aNonLoadedEnvissue suggestingbit install- no scope-capsule isolation in workspace context (which used to take minutes). Old components load without being reported as modified, and re-tagging keeps the env versionless - covered end-to-end bye2e/harmony/legacy-core-env-back-compat.e2e.ts, which imports a component exported by a pre-removal bit (env saved versionless) and asserts it is not modified and stays versionless after a re-tag.Relocated core wiring: the
bit aspectCLI command moved toteambit.workspace/workspace;validateBeforePersistHookmoved toteambit.dependencies/dependency-resolver; the dead@teambit/legacylink is now skipped instead of crashing.Also fixes latent issues this path exposed: versionless seeders filtering out all manifests in
loadExtensionsByManifests, circular env chains causing infinite component-load recursion, versioned core-aspect ids escaping core filters anddoRequiremutating shared core manifests, stack overflows from recursive graph traversal, and a spuriousMissingDistsissue for compiler-less envs.Verified locally: fresh workspace (JS and TS components) - clean status in ~1s, tag/snap/export offline,
bit envs/bit testgraceful; this repo's workspace - status/insights/list-core clean; the seven repo components that relied on the default env are now explicitly set to the node env.bit create <template> --env <removed-env>loads the env's templates on demand from the global scope (pinned version); this path also loads the full manifest graph, and binds manifest deps of legacy envs to their pinned versions (models built when these envs were core don't list them as dependencies). The e2esetCustomEnvhelper installs the env package the fixture imports (e.g.@teambit/node).