I'm creating a custom cycle.js driver with the purpose of preloading images. The main function exports a sink stream imagesToLoad
emitting an array of image URLs. Those are then loaded by the driver and should return a stream that emits when the images are finished loading.
I can subscribe to the stream returned by the driver inside the driver's code and see that the loaded images are indeed emitted but never when mapping from inside the main function.
I am probably doing something wrong but I cannot see what exactly.
import { from, Subject } from 'rxjs'
import { adapt } from '@cycle/run/lib/adapt'
const loadImage = (src) =>
new Promise((resolve, reject) => {
const img = new Image()
img.addEventListener('load', () => resolve(img))
img.addEventListener('error', (err) => reject(err))
img.src = src
})
export const makeImageLoaderDriver = () => {
const imageLoaderDriver = (sink$) => {
const imageCache = {}
const source$ = new Subject()
from(source$).subscribe({
next(images) {
const imagesPromises = images.map((src) => {
const imgSuccess = { src, loaded: true }
if (!!imageCache[src]) return Promise.resolve(imgSuccess)
return loadImage(src)
.then(() => {
imageCache[src] = imgSuccess
})
.catch((error) => {
imageCache[src] = { src, loaded: false, error }
})
})
Promise.all(imagesPromises).then(() => {
source$.next(imageCache)
})
},
})
return adapt(source$)
}
return imageLoaderDriver
}
const drivers = {
imagesToLoad: makeImageLoaderDriver(),
}
run(main, drivers)
export function main(sources) {
sources.imagesToLoad.pipe(map(console.log)) // THIS NEVER LOGS ANYTHING
return {
imagesToLoad: of([ imageUrl1, imageUrl2 ]),
}
}
sources.imagesToLoad.pipe(map(console.log))
creates a new Observable, but this Observable is not named (as a const
) and is not used anywhere else. It's just dropped and never subscribed to, so effectively that line in main
does nothing.
It needs to get plugged into one of the other stream pipelines that will some way end up in the sink. For instance, get the output of that operation, name it as a const
, and then use that const
stream in another stream pipeline, and this stream pipeline must eventually end up in a sink.
To debug, you can put .subscribe()
after the map
, and most likely you will see the console.log
happen. Just don't leave the subscribe()
in the code because Cycle.js is a framework where you don't ever need to subscribe on the main
side, because subscriptions are meant for the drivers side.
Notice also that your driver takes sink$
as input but it never uses that. You should subscribe to sink$
and perform effects based on its emissions.