Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit45ccd39

Browse files
authored
Adding more injector safety (#3590)
* Zone wrapper noops for our other helpers* Add a warning / error on potential Zone / hydration issues* Pass injection context to `zoneWrapFn` * Pass injection context into the Promise wrapper* `beforeAuthStateChanged` should not block
1 parent01597da commit45ccd39

File tree

3 files changed

+55
-11
lines changed

3 files changed

+55
-11
lines changed

‎src/auth/firebase.ts‎

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more aboutcustomizing how changed files appear on GitHub.

‎src/zones.ts‎

Lines changed: 53 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@ import {
44
Injector,
55
NgZone,
66
PendingTasks,
7-
inject
7+
inject,
8+
isDevMode,
9+
runInInjectionContext
810
}from'@angular/core';
911
import{pendingUntilEvent}from'@angular/core/rxjs-interop';
1012
import{
@@ -76,31 +78,71 @@ function getSchedulers() {
7678
returninject(ɵAngularFireSchedulers);
7779
}
7880

81+
varalreadyWarned=false;
82+
functionwarnOutsideInjectionContext(original:any,operation:string){
83+
if(isDevMode()){
84+
console.warn(`Firebase API called outside injection context:${operation}(${original.name})`);
85+
if(!alreadyWarned){
86+
alreadyWarned=true;
87+
console.error("Calling Firebase APIs outside of an Injection context may destabilize your application leading to subtle change-detection and hydration bugs. Find more at https://github.com/angular/angularfire/blob/main/docs/zones.md");
88+
}
89+
}
90+
}
91+
7992
functionrunOutsideAngular<T>(fn:(...args:any[])=>T):T{
80-
returninject(NgZone).runOutsideAngular(()=>fn());
93+
letngZone:NgZone|undefined;
94+
try{
95+
ngZone=inject(NgZone);
96+
}catch(e){
97+
warnOutsideInjectionContext(fn,"runOutsideAngular");
98+
}
99+
if(!ngZone){returnfn();}
100+
returnngZone.runOutsideAngular(()=>fn());
81101
}
82102

83103
functionrun<T>(fn:(...args:any[])=>T):T{
84-
returninject(NgZone).run(()=>fn());
104+
letngZone:NgZone|undefined;
105+
try{
106+
ngZone=inject(NgZone);
107+
}catch(e){
108+
warnOutsideInjectionContext(fn,"run");
109+
}
110+
if(!ngZone){returnfn();}
111+
returnngZone.run(()=>fn());
85112
}
86113

87114
exportfunctionobserveOutsideAngular<T>(obs$:Observable<T>):Observable<T>{
88-
returnobs$.pipe(observeOn(getSchedulers().outsideAngular));
115+
letschedulers:ɵAngularFireSchedulers|undefined;
116+
try{
117+
schedulers=getSchedulers();
118+
}catch(e){
119+
warnOutsideInjectionContext(obs$,"observeOutsideAngular");
120+
}
121+
if(!schedulers){returnobs$;}
122+
returnobs$.pipe(observeOn(schedulers.outsideAngular));
89123
}
90124

91125
exportfunctionobserveInsideAngular<T>(obs$:Observable<T>):Observable<T>{
92-
returnobs$.pipe(observeOn(getSchedulers().insideAngular));
126+
letschedulers:ɵAngularFireSchedulers|undefined;
127+
try{
128+
schedulers=getSchedulers();
129+
}catch(e){
130+
warnOutsideInjectionContext(obs$,"observeInsideAngular");
131+
}
132+
if(!schedulers){returnobs$;}
133+
returnobs$.pipe(observeOn(schedulers.insideAngular));
93134
}
94135

95136
constzoneWrapFn=(
96137
it:(...args:any[])=>any,
97-
taskDone:VoidFunction|undefined
138+
taskDone:VoidFunction|undefined,
139+
injector:Injector,
98140
)=>{
99141
return(...args:any[])=>{
100142
if(taskDone){
101143
setTimeout(taskDone,0);
102144
}
103-
returnrun(()=>it.apply(this,args));
145+
returnrunInInjectionContext(injector,()=>run(()=>it.apply(this,args)));
104146
};
105147
};
106148

@@ -117,6 +159,7 @@ export const ɵzoneWrap = <T= unknown>(it: T, blockUntilFirst: boolean): T => {
117159
pendingTasks=inject(PendingTasks);
118160
injector=inject(Injector);
119161
}catch(e){
162+
warnOutsideInjectionContext(it,"ɵzoneWrap");
120163
return(itasany).apply(this,_arguments);
121164
}
122165
// if this is a callback function, e.g, onSnapshot, we should create a pending task and complete it
@@ -127,7 +170,7 @@ export const ɵzoneWrap = <T= unknown>(it: T, blockUntilFirst: boolean): T => {
127170
taskDone||=run(()=>pendingTasks.add());
128171
}
129172
// TODO create a microtask to track callback functions
130-
_arguments[i]=zoneWrapFn(_arguments[i],taskDone);
173+
_arguments[i]=zoneWrapFn(_arguments[i],taskDone,injector);
131174
}
132175
}
133176
constret=runOutsideAngular(()=>(itasany).apply(this,_arguments));
@@ -153,8 +196,8 @@ export const ɵzoneWrap = <T= unknown>(it: T, blockUntilFirst: boolean): T => {
153196
()=>
154197
newPromise((resolve,reject)=>{
155198
pendingTasks.run(()=>ret).then(
156-
(it)=>run(()=>resolve(it)),
157-
(reason)=>run(()=>reject(reason))
199+
(it)=>runInInjectionContext(injector,()=>run(()=>resolve(it))),
200+
(reason)=>runInInjectionContext(injector,()=>run(()=>reject(reason)))
158201
);
159202
})
160203
);

‎tools/build.ts‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ ${exportedZoneWrappedFns}
7575
browserSessionPersistence:null,
7676
indexedDBLocalPersistence:null,
7777
prodErrorMap:null,
78+
beforeAuthStateChanged:{blockUntilFirst:false},
7879
}),
7980
reexport('database','rxfire','rxfire/database',tsKeys<typeofimport('rxfire/database')>()),
8081
reexport('database','firebase','firebase/database',tsKeys<typeofimport('firebase/database')>()),

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp