@@ -316,3 +316,85 @@ expect([...makeIterableHeaders(myHeaders)].length).to.equal(2);
316316Why are you a weird fellow/gal? Anyway, prejudice aside, body typing will mean nothing to you, so forget about ` for() `
317317and anything else regarding types. Do your custom data-fetching function, add your custom body parsers and fetch away
318318using ` .fetch() ` , ` .get() ` , ` head() ` , ` .post() ` , ` .put() ` , ` .patch() ` or ` .delete() ` .
319+
320+ ## Plug-ins? Fancy Stuff?
321+
322+ Indeed, we can have fancy stuff. As demonstration, this section will show you how one can add download progress with
323+ a simple class and a custom body parser.
324+
325+ The following is a class for ** Svelte v5** . It contains a reactive ` progress ` property that is updated as download
326+ progresses.
327+
328+ > [ !NOTE]
329+ > You should have no problems translating this to Vue, SolidJS or even Angular since all these are signal-powered.
330+ > For React, you'll have to get rid of the signals part and perhaps make it callback-powered.
331+
332+ ``` ts
333+ export class DownloadProgress {
334+ progress = $state (0 );
335+
336+ constructor (response : Response ) {
337+ this .#downloadResponse (response );
338+ }
339+
340+ async #downloadResponse(response : Response ) {
341+ const totalSize = + (response .headers .get (' content-length' ) ?? 0 );
342+ let receivedSize = 0 ;
343+ const bodyReader = response .body ! .getReader ();
344+ while (bodyReader ) {
345+ const { done, value } = await bodyReader .read ();
346+ if (done ) {
347+ break ;
348+ }
349+ receivedSize += value .length ;
350+ this .progress = (receivedSize / totalSize );
351+ }
352+ }
353+ }
354+ ```
355+
356+ The class is actually discarding the contents of the downloaded file. Make sure you modify it to save the data. This
357+ example merely cares about illustrating the mechanism of how you can post-process HTTP responses.
358+
359+ ### How To Use
360+
361+ Create a custom parser for the content type that will be received, for example, ` video/mp4 ` for MP4 video files.
362+
363+ ``` ts
364+ // downloader.ts
365+ import { DownloadProgress } from ' ./DownloadProgress.svelte.js' ;
366+
367+ export default new DrFetch (/* custom fetch function here, if needed */ )
368+ .withParser (' video/mp4' , (r ) => Promise .resolve (new DownloadProgress (r )))
369+ ;
370+ ```
371+
372+ The Svelte component would use this fetcher object. The response from ` fetcher.fetch() ` (or ` fetcher.get() ` ) will
373+ carry the class instance in the ` body ` property.
374+
375+ ``` svelte
376+ <script lang="ts">
377+ import { DownloadProgress } from './DownloadProgress.svelte.js';
378+ import downloader from './downloader.js';
379+
380+ let download = $state<Download>();
381+
382+ async function startDownload() {
383+ download = (await downloader
384+ .for<200, DownloadProgress>()
385+ .get('https://example.com/my-video.mp4'))
386+ .body
387+ ;
388+ }
389+ </script>
390+
391+ <button type="button" onclick={startDownload}>
392+ Start Download
393+ </button>
394+ <progress value={download?.progress ?? 0}></progress>
395+
396+ ```
397+
398+ When the button is clicked, the download is started. The custom parser simply creates the new instance of the
399+ ` DownloadProgress ` class. Svelte's reactivity system takes care of the rest, effectively bringing the progress element
400+ to life as the download progresses.
0 commit comments