support local assets

This commit is contained in:
lovebird 2025-03-17 19:06:12 +01:00
parent 0682e23ae2
commit 0f6bcc4267
14 changed files with 224 additions and 220 deletions

File diff suppressed because one or more lines are too long

View File

@ -35,8 +35,8 @@ export default async function renderImg(props) {
const artDirectives = [],
fallbackFormat = format,
fadeInTransition = true,
includeSourceFormat = true;
fadeInTransition = false,
includeSourceFormat = false;
const {
img: imgAttributes = {},

View File

@ -8,7 +8,7 @@ import pMap from "p-map";
const imagesData = new Map();
const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
const delay = (ms = 100) => new Promise((resolve) => setTimeout(resolve, ms));
export default async function ({
src,
@ -33,7 +33,7 @@ export default async function ({
const { path, base, rest, image, imageWidth, imageHeight, imageFormat } =
await getProcessedImage(src, transformConfigs);
await delay(250);
await delay();
src = path;
rest.aspect = `${imageWidth / imageHeight}`;
@ -61,7 +61,6 @@ export default async function ({
rest
),
async () => {
await delay(250);
return await getArtDirectedImages(
artDirectives,
placeholder,

View File

@ -4,7 +4,7 @@ import getConfigOptions from "./getConfigOptions.js";
import getFallbackImage from "./getFallbackImage.js";
import pMap from "p-map";
function delay(ms) {
function delay(ms = 150) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
@ -43,7 +43,7 @@ export default async function getImageSources(
formats,
async (format) => {
try {
await delay(100);
await delay();
const srcset = await getSrcset(src, base, requiredBreakpoints, format, {
...rest,
...formatOptions[format],
@ -85,7 +85,6 @@ export default async function getImageSources(
)
return { sources: filteredSources, sizes, fallback, imagesizes };
} catch (error) {
console.error("Error in getImageSources:", error);
return { sources: [], sizes: {}, fallback: null, imagesizes: null };
}
}

View File

@ -27,9 +27,9 @@ export default async function getSrcset(
const id = `${src}?${params.slice(1)}`
const fullPath = await getSrcPath(id);
const { default: load } = await import("../../plugin/hooks/load.js");
//console.log("get source set", fullPath, src, id);
const loaded = await load(fullPath, base)
if (!loaded) {
if (!loaded)
{
return "";
}
const srcset = loaded.slice(16, -1)

View File

@ -1,12 +1,12 @@
export default {
"environment": "dev",
"environment": "build",
"isSsrBuild": false,
"projectBase": "",
"publicDir": "C:\\Users\\zx\\Desktop\\polymech\\polymech-site\\public\\",
"rootDir": "C:\\Users\\zx\\Desktop\\polymech\\polymech-site\\",
"mode": "dev",
"outDir": "dist",
"assetsDir": "/_astro",
"mode": "production",
"outDir": "C:\\Users\\zx\\Desktop\\polymech\\polymech-site\\dist\\",
"assetsDir": "_astro",
"sourcemap": false,
"assetFileNames": "/_astro/[name]@[width].[hash][extname]"
}

View File

@ -1,85 +1,85 @@
// @ts-check
import fs from "node:fs"
import { fileURLToPath } from "node:url"
import { posix as path, resolve } from "node:path"
import { saveAndCopyAsset } from "./utils/saveAndCopyAsset.js"
import vitePluginAstroImageTools, { store } from "../plugin/index.js"
import pMap from "p-map"
const filename = fileURLToPath(import.meta.url);
const astroViteConfigsPath = resolve(filename, "../../astroViteConfigs.js");
export default {
name: "imagetools",
hooks: {
"astro:config:setup": async function ({ config, command, updateConfig }) {
const environment = command;
const isSsrBuild =
command === "build" && !!config.adapter && config.output === "server";
let projectBase = path.normalize(config.base);
if (projectBase.startsWith("./")) projectBase = projectBase.slice(1);
if (!projectBase.startsWith("/")) projectBase = "/" + projectBase;
if (projectBase.endsWith("/")) projectBase = projectBase.slice(0, -1);
const astroViteConfigs = {
environment,
isSsrBuild,
projectBase,
publicDir: fileURLToPath(config.publicDir.href),
rootDir: fileURLToPath(config.root.href),
};
await fs.promises.writeFile(
astroViteConfigsPath,
`export default ${JSON.stringify(astroViteConfigs)}`
);
updateConfig({
vite: {
plugins: [vitePluginAstroImageTools],
},
});
},
"astro:build:done": async function closeBundle() {
const { default: astroViteConfigs } = await import(
// @ts-ignore
"../astroViteConfigs.js"
);
const { mode, outDir, assetsDir, isSsrBuild } = astroViteConfigs;
if (mode === "production") {
const allEntries = [...store.entries()];
const assetPaths = allEntries.filter(
([, { hash = null } = {}]) => hash
);
await pMap(
assetPaths,
async ([assetPath, { hash, image, buffer }]) => {
// delay, otherwise unknown errors occur (sharp/vips)
await new Promise((resolve) => setTimeout(resolve, 250));
try {
await saveAndCopyAsset(
hash,
image,
buffer,
outDir,
assetsDir,
assetPath,
isSsrBuild
);
} catch (error) {
console.error(error)
}
console.log(`Image processed: ${assetPath}`)
},
// higher concurrency causes sharp/vips errors as well
{ concurrency: 1 }
);
}
},
},
};
// @ts-check
import fs from "node:fs"
import { fileURLToPath } from "node:url"
import { posix as path, resolve } from "node:path"
import { saveAndCopyAsset } from "./utils/saveAndCopyAsset.js"
import vitePluginAstroImageTools, { store } from "../plugin/index.js"
import pMap from "p-map"
const filename = fileURLToPath(import.meta.url);
const astroViteConfigsPath = resolve(filename, "../../astroViteConfigs.js");
export default {
name: "imagetools",
hooks: {
"astro:config:setup": async function ({ config, command, updateConfig }) {
const environment = command;
const isSsrBuild =
command === "build" && !!config.adapter && config.output === "server";
let projectBase = path.normalize(config.base);
if (projectBase.startsWith("./")) projectBase = projectBase.slice(1);
if (!projectBase.startsWith("/")) projectBase = "/" + projectBase;
if (projectBase.endsWith("/")) projectBase = projectBase.slice(0, -1);
const astroViteConfigs = {
environment,
isSsrBuild,
projectBase,
publicDir: fileURLToPath(config.publicDir.href),
rootDir: fileURLToPath(config.root.href),
};
await fs.promises.writeFile(
astroViteConfigsPath,
`export default ${JSON.stringify(astroViteConfigs)}`
);
updateConfig({
vite: {
plugins: [vitePluginAstroImageTools],
},
});
},
"astro:build:done": async function closeBundle() {
const { default: astroViteConfigs } = await import(
// @ts-ignore
"../astroViteConfigs.js"
);
const { mode, outDir, assetsDir, isSsrBuild } = astroViteConfigs;
if (mode === "production") {
const allEntries = [...store.entries()];
const assetPaths = allEntries.filter(
([, { hash = null } = {}]) => hash
);
await pMap(
assetPaths,
async ([assetPath, { hash, image, buffer }]) => {
// delay, otherwise unknown errors occur (sharp/vips)
await new Promise((resolve) => setTimeout(resolve, 150));
try {
await saveAndCopyAsset(
hash,
image,
buffer,
outDir,
assetsDir,
assetPath,
isSsrBuild
);
} catch (error) {
console.error(error)
}
console.log(`Image processed: ${assetPath}`)
},
// higher concurrency causes sharp/vips errors as well
{ concurrency: 1 }
);
}
},
},
};

View File

@ -1,46 +1,45 @@
import fs from "node:fs/promises";
import { posix as path } from "node:path";
import { fsCachePath } from "../../utils/runtimeChecks.js";
const copied = [];
let assetsDirExists;
export async function saveAndCopyAsset(
hash,
image,
buffer,
outDir,
assetsDir,
assetPath,
isSsrBuild
) {
const src = fsCachePath + hash;
const dest = path.join(outDir, isSsrBuild ? "/client" : "", assetPath);
assetsDir = path.join(outDir, isSsrBuild ? "/client" : "/", assetsDir);
if (copied.includes(assetPath)) return;
if (!assetsDirExists) {
await fs.mkdir(assetsDir, {
recursive: true,
});
assetsDirExists = true;
}
await fs.copyFile(src, dest).catch(async (error) => {
if (error.code === "ENOENT") {
const imageBuffer = buffer || (await image.toBuffer());
await Promise.all(
[src, dest].map(async (dir) => {
await fs.writeFile(dir, imageBuffer);
})
);
} else throw error;
});
copied.push(assetPath);
}
import fs from "node:fs/promises";
import { sync as exists } from "@polymech/fs/exists"
import { posix as path } from "node:path";
import { fsCachePath } from "../../utils/runtimeChecks.js";
let copied = [];
let assetsDirExists;
export async function saveAndCopyAsset(
hash,
image,
buffer,
outDir,
assetsDir,
assetPath,
isSsrBuild
) {
const src = fsCachePath + hash;
const dest = path.join(outDir, isSsrBuild ? "/client" : "", assetPath);
assetsDir = path.join(outDir, isSsrBuild ? "/client" : "/", assetsDir);
copied = copied.filter(exists);
if (copied.includes(assetPath)) return;
if (!assetsDirExists) {
await fs.mkdir(assetsDir, {
recursive: true,
});
assetsDirExists = true;
}
await fs.copyFile(src, dest).catch(async (error) => {
if (error.code === "ENOENT") {
const imageBuffer = buffer || (await image.toBuffer());
await Promise.all(
[src, dest].map(async (dir) => {
await fs.writeFile(dir, imageBuffer);
})
);
} else throw error;
});
copied.push(assetPath);
}

View File

@ -1,63 +1,64 @@
{
"name": "imagetools",
"version": "0.9.0",
"description": "Image Optimization tools for the Astro JS framework",
"type": "module",
"types": "./types.d.ts",
"exports": {
".": "./index.js",
"./ssr": "./ssr/index.js",
"./api": "./api/index.js",
"./config": "./config.mjs",
"./components": "./components/index.js"
},
"scripts": {
"test:watch": "vitest",
"test": "vitest run"
},
"repository": {
"type": "git",
"url": "git+https://github.com/RafidMuhymin/astro-imagetools.git"
},
"keywords": [
"astro",
"astro-component",
"image",
"images",
"optimization",
"responsive-image",
"vite",
"vite-plugin",
"sharp",
"imagetools",
"codecs",
"astropub"
],
"author": "Rafid Muhymin",
"license": "MIT",
"bugs": {
"url": "https://github.com/RafidMuhymin/astro-imagetools/issues"
},
"homepage": "https://github.com/RafidMuhymin/astro-imagetools#readme",
"dependencies": {
"@astropub/codecs": "0.4.4",
"file-type": "17.1.1",
"find-cache-dir": "3.3.2",
"find-up": "^6.3.0",
"object-hash": "3.0.0",
"p-map": "^7.0.3",
"potrace": "2.1.8"
},
"optionalDependencies": {
"imagetools-core": "3.0.2"
},
"peerDependencies": {
"astro": ">=0.26 || >=1.0.0-beta"
},
"devDependencies": {
"vitest": "^0.12.4"
},
"engines": {
"node": "^14.15.0 || >=16.0.0"
}
}
{
"name": "imagetools",
"version": "0.9.0",
"description": "Image Optimization tools for the Astro JS framework",
"type": "module",
"types": "./types.d.ts",
"exports": {
".": "./index.js",
"./ssr": "./ssr/index.js",
"./api": "./api/index.js",
"./config": "./config.mjs",
"./components": "./components/index.js"
},
"scripts": {
"test:watch": "vitest",
"test": "vitest run"
},
"repository": {
"type": "git",
"url": "git+https://github.com/RafidMuhymin/astro-imagetools.git"
},
"keywords": [
"astro",
"astro-component",
"image",
"images",
"optimization",
"responsive-image",
"vite",
"vite-plugin",
"sharp",
"imagetools",
"codecs",
"astropub"
],
"author": "Rafid Muhymin",
"license": "MIT",
"bugs": {
"url": "https://github.com/RafidMuhymin/astro-imagetools/issues"
},
"homepage": "https://github.com/RafidMuhymin/astro-imagetools#readme",
"dependencies": {
"@astropub/codecs": "0.4.4",
"@polymech/fs": "file:../../../polymech-mono/packages/fs",
"file-type": "17.1.1",
"find-cache-dir": "3.3.2",
"find-up": "^6.3.0",
"object-hash": "3.0.0",
"p-map": "^7.0.3",
"potrace": "2.1.8"
},
"optionalDependencies": {
"imagetools-core": "3.0.2"
},
"peerDependencies": {
"astro": ">=0.26 || >=1.0.0-beta"
},
"devDependencies": {
"vitest": "^0.12.4"
},
"engines": {
"node": "^14.15.0 || >=16.0.0"
}
}

View File

@ -36,7 +36,7 @@ export const PRODUCTS_TARGET = (lang) => `./content/${lang}/products`
// Product assets
export const ASSETS_LOCALE = false
export const ASSETS_LOCALE = true
// OSRL - Language
export const IS_DEV = true

View File

@ -80,6 +80,7 @@ export const default_filter_locale = async (url: string) => {
}
export const image_url = async (src, fallback = DEFAULT_IMAGE_URL) => {
if(exists(src)) return src
let safeSrc = src
try {
const response = await fetch(src, { method: 'HEAD' })

View File

@ -1,15 +1,16 @@
---
import { default_image } from "@/app/config.js";
import Img from "@/components/polymech/image.astro";
import Translate from "@/components/polymech/i18n.astro";
import { Img } from "imagetools/components"
const { title, url, price, model, selected = false } = Astro.props;
const thumbnail = model?.assets?.renderings[0]?.src || default_image();
const classes = `group relative bg-white overflow-hidden group rounded-xl ${selected ? "ring-2 ring-orange-500" : ""}`
const classes = `group relative bg-white overflow-hidden group rounded-xl ${selected ? "ring-2 ring-orange-500" : ""}`;
---
<div class={classes}>
<div class="p-4 overflow-hidden group-hover:opacity-75 duration-300 transition-all">
<div
class="p-4 overflow-hidden group-hover:opacity-75 duration-300 transition-all"
>
<a href={url} title={title} aria-label={title}>
<Img
src={thumbnail}
@ -30,7 +31,7 @@ const classes = `group relative bg-white overflow-hidden group rounded-xl ${sele
<Translate>{title}</Translate>
</a>
</h3>
<p class="absolute top-4 right-4">{price}</p>
<p class="top-4 right-4"></p>
<p class="mt-1"></p>
</div>
</div>

View File

@ -2,10 +2,10 @@
import path from "node:path"
import BaseLayout from "@/layouts/BaseLayout.astro"
import Wrapper from "@/components/containers/Wrapper.astro"
import Picture from "@/components/polymech/image.astro"
import { Img } from "imagetools/components"
import { Img, Picture } from "imagetools/components"
import { getCollection } from "astro:content"
import KBot from "@/components/polymech/kbot.astro"
import Image from "@/components/polymech/image.astro"
const locale = Astro.currentLocale
const store = `${locale}/store/`
const src = `./public/products/overview-3.jpg`
@ -17,7 +17,12 @@ const abs = path.resolve(src)
<section>
<div class="py-2 space-y-2">
<div class="grid md:grid-cols-1 lg:grid-cols-1 gap-4" >
<Img src={abs} alt="Overview"></Picture>
<Image src={abs}
alt="Overview"
sizes={"(min-width: 1024px) 1024px, 1024vw"}
format={"png"}
breakpoints={[800,1200]}
/>
</div>
</div>
</section>

View File

@ -2,7 +2,6 @@
import BaseLayout from "@/layouts/BaseLayout.astro"
import Wrapper from "@/components/containers/Wrapper.astro"
import KBot from "@/components/polymech/kbot.astro"
import Map from "@/components/polymech/map.astro"
const mapOptions = {
zoom: 9,