Skip to content

Instantly share code, notes, and snippets.

@lambdaxyzt
Last active April 8, 2025 21:37
Show Gist options
  • Save lambdaxyzt/1ad05e98b73aab71fc7714d150a1480a to your computer and use it in GitHub Desktop.
Save lambdaxyzt/1ad05e98b73aab71fc7714d150a1480a to your computer and use it in GitHub Desktop.

Revisions

  1. lambdaxyzt revised this gist Jan 13, 2024. 2 changed files with 3 additions and 1 deletion.
    2 changes: 1 addition & 1 deletion image.server.js
    Original file line number Diff line number Diff line change
    @@ -5,7 +5,7 @@ import axios from "axios";
    import path from "node:path";
    import cacache from "cacache";
    import { finished } from "node:stream/promises"
    import {widths as widths_,defaultQuality as defaultQuality_} from "./image"
    import {widths as widths_,defaultQuality as defaultQuality_} from "./variable"
    export const cachePathImage = path.resolve('./.cache/image')
    export const cachePathMainImage = path.resolve('./.cache/image/tmp')

    2 changes: 2 additions & 0 deletions variables.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,2 @@
    export const widths = [640, 828, 1080, 1920];
    export const defaultQuality = 75;
  2. lambdaxyzt revised this gist Jan 13, 2024. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion image.jsx
    Original file line number Diff line number Diff line change
    @@ -1,4 +1,4 @@
    // client side component
    // resource route component
    import React from "react";
    import { PassThrough } from "node:stream"
    import fs from "node:fs"
  3. lambdaxyzt revised this gist Jan 13, 2024. No changes.
  4. lambdaxyzt revised this gist Jan 13, 2024. 2 changed files with 2 additions and 0 deletions.
    1 change: 1 addition & 0 deletions image.jsx
    Original file line number Diff line number Diff line change
    @@ -1,3 +1,4 @@
    // client side component
    import React from "react";
    import { PassThrough } from "node:stream"
    import fs from "node:fs"
    1 change: 1 addition & 0 deletions image.server.js
    Original file line number Diff line number Diff line change
    @@ -1,4 +1,5 @@
    // library : sharp , cacache
    // server side
    import sharp from "sharp";
    import axios from "axios";
    import path from "node:path";
  5. lambdaxyzt created this gist Jan 13, 2024.
    47 changes: 47 additions & 0 deletions image.jsx
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,47 @@
    import React from "react";
    import { PassThrough } from "node:stream"
    import fs from "node:fs"
    import {createReadableStreamFromReadable} from "@remix-run/node"
    import { defaultQuality,widths,mainImageReadStream,generatedImageReadstream, isThereImage,BadImageResponse } from "../../util/image.server"

    export const loader = async ({ request }) => {
    const url = new URL(request.url);
    const src = url.searchParams.get("src");
    const width = url.searchParams.get("w");
    if (!src || !width ) {
    return BadImageResponse();
    }
    try{
    if(!await isThereImage(src)) {
    for (const width of widths) {
    await generatedImageReadstream(await mainImageReadStream(src),src,width,defaultQuality)
    }
    } else {
    const {size,fileStream,hash} = await generatedImageReadstream(await mainImageReadStream(src),src,width,defaultQuality)
    const body = new PassThrough()
    const stream = fileStream
    stream.on('error', err => body.end(err))
    stream.on('end', () => body.end())
    stream.pipe(body)
    return new Response(createReadableStreamFromReadable(body), {
    status: 200,
    headers: {
    'content-type': 'image/webp',
    'content-length': String(size),
    'content-disposition': `inline; filename="${hash}.webp"`,
    'cache-control': 'public, max-age=31536000, immutable',
    },
    })
    }
    } catch(e) {
    console.log(e)
    return BadImageResponse();
    }
    }

    /*
    # tnx to
    - https://github.com/ccssmnn : https://github.com/remix-run/remix/discussions/2905#discussioncomment-2596810
    - https://stackoverflow.com/a/51302466/12814525
    - https://github.com/epicweb-dev/web-forms
    */
    96 changes: 96 additions & 0 deletions image.server.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,96 @@
    // library : sharp , cacache
    import sharp from "sharp";
    import axios from "axios";
    import path from "node:path";
    import cacache from "cacache";
    import { finished } from "node:stream/promises"
    import {widths as widths_,defaultQuality as defaultQuality_} from "./image"
    export const cachePathImage = path.resolve('./.cache/image')
    export const cachePathMainImage = path.resolve('./.cache/image/tmp')

    export const widths = widths_
    export const defaultQuality = defaultQuality_
    export const BadImageResponse = () => {
    const buffer = Buffer.from(
    "PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48IS0tIFVwbG9hZGVkIHRvOiBTVkcgUmVwbywgd3d3LnN2Z3JlcG8uY29tLCBHZW5lcmF0b3I6IFNWRyBSZXBvIE1peGVyIFRvb2xzIC0tPg0KPHN2ZyB3aWR0aD0iODAwcHgiIGhlaWdodD0iODAwcHgiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4NCjxwYXRoIGQ9Ik0xNC4yNjM5IDE1LjkzNzVMMTIuNTk1OCAxNC4yODM0QzExLjc5MDkgMTMuNDg1MSAxMS4zODg0IDEzLjA4NiAxMC45MjY2IDEyLjk0MDFDMTAuNTIwNCAxMi44MTE4IDEwLjA4MzggMTIuODE2NSA5LjY4MDQ4IDEyLjk1MzZDOS4yMjE4OCAxMy4xMDk1IDguODI4MTQgMTMuNTE3MiA4LjA0MDY4IDE0LjMzMjZMNC4wNDQwOSAxOC4yODAxTTE0LjI2MzkgMTUuOTM3NUwxNC42MDUzIDE1LjU5OUMxNS40MTEyIDE0Ljc5OTggMTUuODE0MSAxNC40MDAyIDE2LjI3NjUgMTQuMjU0M0MxNi42ODMxIDE0LjEyNiAxNy4xMiAxNC4xMzExIDE3LjUyMzYgMTQuMjY4N0MxNy45ODI0IDE0LjQyNTEgMTguMzc2MSAxNC44MzM5IDE5LjE2MzQgMTUuNjUxNEwyMCAxNi40OTM0TTE0LjI2MzkgMTUuOTM3NUwxOC4yNzUgMTkuOTU2NU0xOC4yNzUgMTkuOTU2NUMxNy45MTc2IDIwIDE3LjQ1NDMgMjAgMTYuOCAyMEg3LjJDNi4wNzk4OSAyMCA1LjUxOTg0IDIwIDUuMDkyMDIgMTkuNzgyQzQuNzE1NjkgMTkuNTkwMyA0LjQwOTczIDE5LjI4NDMgNC4yMTc5OSAxOC45MDhDNC4xMjc5NiAxOC43MzEzIDQuMDc1MTIgMTguNTMyMSA0LjA0NDA5IDE4LjI4MDFNMTguMjc1IDE5Ljk1NjVDMTguNTI5MyAxOS45MjU2IDE4LjczMDEgMTkuODcyNyAxOC45MDggMTkuNzgyQzE5LjI4NDMgMTkuNTkwMyAxOS41OTAzIDE5LjI4NDMgMTkuNzgyIDE4LjkwOEMyMCAxOC40ODAyIDIwIDE3LjkyMDEgMjAgMTYuOFYxNi40OTM0TTQuMDQ0MDkgMTguMjgwMUM0IDE3LjkyMjEgNCAxNy40NTc1IDQgMTYuOFY3LjJDNCA2LjA3OTkgNCA1LjUxOTg0IDQuMjE3OTkgNS4wOTIwMkM0LjQwOTczIDQuNzE1NjkgNC43MTU2OSA0LjQwOTczIDUuMDkyMDIgNC4yMTc5OUM1LjUxOTg0IDQgNi4wNzk4OSA0IDcuMiA0SDE2LjhDMTcuOTIwMSA0IDE4LjQ4MDIgNCAxOC45MDggNC4yMTc5OUMxOS4yODQzIDQuNDA5NzMgMTkuNTkwMyA0LjcxNTY5IDE5Ljc4MiA1LjA5MjAyQzIwIDUuNTE5ODQgMjAgNi4wNzk5IDIwIDcuMlYxNi40OTM0TTE3IDguOTk5ODlDMTcgMTAuMTA0NSAxNi4xMDQ2IDEwLjk5OTkgMTUgMTAuOTk5OUMxMy44OTU0IDEwLjk5OTkgMTMgMTAuMTA0NSAxMyA4Ljk5OTg5QzEzIDcuODk1MzIgMTMuODk1NCA2Ljk5OTg5IDE1IDYuOTk5ODlDMTYuMTA0NiA2Ljk5OTg5IDE3IDcuODk1MzIgMTcgOC45OTk4OVoiIHN0cm9rZT0iIzAwMDAwMCIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiLz4NCjwvc3ZnPg==",
    "base64"
    );
    return new Response(buffer, {
    status: 500,
    headers: {
    "Cache-Control": "max-age=0",
    "Content-Type": "data:image/svg+xml;base64",
    "Content-Length": buffer.length.toFixed(0),
    },
    });
    };

    export const isThereImage = async (url) => {
    const isContentThere = await cacache.get(cachePathMainImage, url).then(
    () => {
    return true
    },
    () => {
    return false
    }
    )
    return isContentThere
    };


    export const mainImageReadStream = async (url) => {
    const isContentThere = await isThereImage(url)
    if (!isContentThere) {
    const response = await axios({
    method: 'GET',
    url: url,
    responseType: 'stream'
    })
    // pipe the result stream into a file on disc
    await response.data.pipe(cacache.put.stream(cachePathMainImage, url).on('integrity', d => console.log(`integrity digest is ${d}`)))
    }

    return cacache.get.stream(
    cachePathMainImage, url
    )
    }



    export const generatedImageReadstream = async (mainImageReadstream, url, width, quality) => {
    const urlKey = `url:${url},w:${width},q:${quality}`
    const isContentThere = await isThereImage(urlKey)
    if (!isContentThere) {
    const pipeline = sharp();
    pipeline
    .resize(parseInt(width))
    .webp({
    quality: parseInt(quality),
    })
    // pip it to cache by cacache library
    .pipe(
    cacache.put.stream(
    cachePathImage, urlKey
    )
    );
    // transform then cache it accroding to pipline
    await finished(mainImageReadstream.pipe(pipeline));
    }
    const {size,integrity} = await cacache.get.info(cachePathImage, urlKey)
    const fileStream = cacache.get.stream(
    cachePathImage, urlKey
    )
    return {
    fileStream,
    size,
    hash:integrity,
    }
    };

    /*
    # tnx to
    - https://github.com/ccssmnn : https://github.com/remix-run/remix/discussions/2905#discussioncomment-2596810
    - https://stackoverflow.com/a/51302466/12814525
    - https://github.com/epicweb-dev/web-forms
    */