Can RxJS 5 and a newer release coexist in one bundle during a zero-downtime migration?
0 reputation · 04 Sept 2025, 20:22 UTC
0 reputation · 04 Sept 2025, 20:22 UTC
A small application on RxJS 5.x is planned to move to a currently supported release while the old and new releases overlap in production. The goal is to keep the existing release serving traffic and rollback-ready while a new build adopts pipeable operators and the newer API surface.
It is whether Observable instances may cross the package-version boundary. RxJS 6 introduced pipeable operators and RxJS 7 removed APIs deprecated in 6, so the two packages are not interchangeable at runtime. A bundler that hoists or deduplicates dependencies can also resolve imports to the wrong copy, and prototype patching from legacy rxjs/add imports can leak into target code.
Assuming both versions remain installed, the open questions are:
Symbol.observable, what adapter shape preserves cancellation and teardown-once semantics?35775 reputation · 05 Sept 2025, 01:30 UTC
Yes, RxJS 5 and a newer release can coexist in a single bundle during a zero-downtime migration, but only if the bundler keeps them as distinct packages. Without explicit configuration, bundlers will deduplicate them, causing runtime failures because RxJS 6+ operators cannot safely consume RxJS 5 Observable instances.
Symbol.observable and the pipe method expected by modern operators.rxjs/add/... patch imports mutate the Observable prototype globally. If both versions share a bundle, these patches can corrupt the newer version’s behavior.package.json.package.json to force separate resolution:
"dependencies": {
"rxjs": "^7.8.0",
"rxjs5": "npm:rxjs@5.7.2"
}
import { Observable } from 'rxjs5';
import 'rxjs5/add/operator/map';
import { from } from 'rxjs';
const adapted$ = from(rxjs5Observable); // wraps in RxJS 6 Observable
webpack-bundle-analyzer or by searching the minified output for two distinct rxjs substrings.node_modules.rxjs5 and rxjs6 markers.rxjs/add imports in code targeting the new version.If your bundler is not Webpack (e.g., Rollup, Parcel), the aliasing syntax differs. Confirm which bundler you are using so the aliasing configuration can be adjusted accordingly.
Use comments to ask for clarification. Post a solution as an answer.
35,775 reputation · 05 Sept 2025, 06:23 UTC
The answer states RxJS 5 Observables lack Symbol.observable, but this was added in RxJS 5.4.0 (March 2017). The real interoperability gap is that v5 Observables lack the internal _isScalar and _subscribe properties that v6+ pipeable operators expect. When a v5 Observable reaches a v6+ pipe(), it is treated as a plain thenable, causing eager subscription and breaking lazy semantics and teardown-once guarantees.
For v7 targets where rxjs-compat is unavailable, a minimal adapter preserves cancellation:
import { Observable } from 'rxjs';
function adaptV5(v5$) {
return new Observable(sub => v5$.subscribe(sub));
}Verify separation at runtime: require('rxjs@5/Observable').prototype[Symbol.observable] !== require('rxjs').prototype[Symbol.observable] must be true.