The reason why it doesn't work with your example is that you are using scaledToFill() modifier on image, and here it matters in this particular case.
First you declared ZStack which is itself doesn't ignore safe area. After you put Image and resizable. What resizable does, is it stretches the image to fit its view, in your case it is the ZStack.
Let's see what we have until now.We have an image which stretches till the safe area.
ZStack {
Image("Breakfast").resizable()
}

So from now on you put edgesIgnoringSafeArea on Image, which lets the image cover all the area(ignore safe area).
Now you have Zstack which respects safe area, and Image which ignores safe area. This let you put VStack in ZStack and add staff inside it. VStack will fill its parent view, which is ZStack, so it too will respect safe area(See code and image below).
ZStack {
Image("Breakfast").resizable().edgesIgnoringSafeArea(.all)
VStack {
Text("hello")
Spacer()
}
}

And here at last you add .scaledToFill() modifier, which stretches the image to contain all the area, and by doing this it makes ZStack view to become the hole area, as fitting view's (ZStack, HStack, VStack) calculates its size based on its content.

Useful link:
Fitting and filling views in SwiftUI
How to resize a SwiftUI Image and keep its aspect ratio