Skip to content

Instantly share code, notes, and snippets.

@jherr
Last active June 12, 2024 06:20
Show Gist options
  • Save jherr/14cf3143ab1dc40ebc8a29d992c71419 to your computer and use it in GitHub Desktop.
Save jherr/14cf3143ab1dc40ebc8a29d992c71419 to your computer and use it in GitHub Desktop.
Helper to download images from Builder.IO converted Figma React/Tailwind from using <img> tags into <Image> components
/*
Converts a NextJS React file generated by Visual Copilot that includes <img> tags into <Image> components. File contents
come as STDIN and files are copied to /public and the re-implementation comes out STDOUT.
cat src/app/page.tsx | node scripts/download-images.js | pbcopy
*/
const fs = require("fs");
const https = require("https");
const readline = require("readline");
async function main() {
// Read all the STDIN
const rl = readline.createInterface({
input: process.stdin,
});
let input = "";
rl.on("line", (line) => {
input += line + "\n";
});
rl.on("close", async () => {
const downloads = {};
// Find all the image tags and fix them
input = input.replace(/<img\s+(.*?)\/>/gms, (val) => {
if (val.includes("src=")) {
const url = val.match(/src="(.*?)"/)[1];
const id = url.match("TEMP/([^?]*)")[1];
val = val.replace(`src="${url}"`, `src="/${id}.unk"`);
downloads[url] = id;
}
if (val.includes("srcSet=")) {
const values = val.match(/srcSet="(.*?)"/)[1];
const urls = values.split(",");
let url = urls[0].split(" ")[0];
url = url.replace(/&width=(.*?)/);
const id = url.match("TEMP/([^?]*)")[1];
val = val.replace(`srcSet="${values}"`, `src="/${id}.unk"`);
const sizes =
urls.map((url) => {
return url?.trim()?.split(" ")?.[1];
}) || [];
val = val.replace(
/<img/,
`<img sizes="${sizes.filter((v) => v).join(", ")}"`
);
downloads[url] = id;
}
if (!val.includes("alt=")) {
val = val.replace(
/<img/,
'<img alt="Replace with an informative alt text"'
);
}
val = val.replace(/<img/, "<Image");
return val;
});
await Promise.all(
Object.keys(downloads).map(async (url) => {
await new Promise((resolve) => {
https.get(url, async (response) => {
// Figure out what type of image this is
let ext = "png";
const type = response.headers["content-type"];
if (type.includes("svg")) {
ext = "svg";
} else if (type.includes("jpeg") || type.includes("jpg")) {
ext = "jpg";
}
// Download the file into /public
await new Promise((frs) => {
const file = fs.createWriteStream(
`./public/${downloads[url]}.${ext}`
);
response.pipe(file);
file.on("finish", () => {
file.close();
frs();
});
});
// Replace the src URL with a new URL that has the right extension
input = input.replace(
`"/${downloads[url]}.unk"`,
`"/${downloads[url]}.${ext}"`
);
// Figure out the size of the image
let width = 1000;
let height = 1000;
if (ext === "svg") {
const svgCode = fs.readFileSync(
`./public/${downloads[url]}.svg`,
"utf-8"
);
width = svgCode.match(/width="(.*?)"/)[1];
height = svgCode.match(/height="(.*?)"/)[1];
}
// Add the height and width because the Image component requires it
input = input.replace(
`"/${downloads[url]}.${ext}"`,
`"/${downloads[url]}.${ext}" width={${width}} height={${height}}`
);
resolve();
});
});
})
);
// Output the adjusted code
console.log(input);
});
}
main();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment