optimization

This commit is contained in:
lovebird 2025-03-09 14:18:01 +01:00
parent 6888866f0b
commit df27705b43
10 changed files with 10855 additions and 220 deletions

View File

@ -3,6 +3,8 @@ import tailwindcss from '@tailwindcss/vite'
import { imagetools } from "imagetools" import { imagetools } from "imagetools"
import react from "@astrojs/react" import react from "@astrojs/react"
import mdx from "@astrojs/mdx"; import mdx from "@astrojs/mdx";
import { defineConfig } from 'astro/config';
import compress from 'vite-plugin-compression';
export default defineConfig({ export default defineConfig({
devToolbar: { devToolbar: {
@ -14,13 +16,22 @@ export default defineConfig({
}, },
vite: { vite: {
plugins: [ plugins: [
tailwindcss() tailwindcss({
config: './tailwind.config.cjs',
jit: true
}),
compress({
algorithm: 'gzip', // You can also use 'brotliCompress' for Brotli
threshold: 1024, // Compress files larger than 1KB
deleteOriginFile: false, // Keep original files (optional)
})
], ],
build: { build: {
target: 'esnext', target: 'esnext',
assetsDir: './assets', assetsDir: './assets',
modulePreload: { polyfill: false }, modulePreload: { polyfill: false },
commonjsOptions: { esmExternals: true } commonjsOptions: { esmExternals: true },
assetsInlineLimit: 1024
}, },
ssr: { ssr: {
external: ['cacache', 'glob', 'xlsx', 'sharp', '@polymech/kbot-d'] external: ['cacache', 'glob', 'xlsx', 'sharp', '@polymech/kbot-d']

View File

@ -1,107 +1,107 @@
// @ts-check // @ts-check
import crypto from "node:crypto"; import crypto from "node:crypto";
import objectHash from "object-hash"; import objectHash from "object-hash";
import getImageSources from "./getImageSources.js"; import getImageSources from "./getImageSources.js";
import getProcessedImage from "./getProcessedImage.js"; import getProcessedImage from "./getProcessedImage.js";
import getArtDirectedImages from "./getArtDirectedImages.js"; import getArtDirectedImages from "./getArtDirectedImages.js";
import pMap from "p-map"; import pMap from "p-map";
const imagesData = new Map(); const imagesData = new Map();
const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms)); const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
export default async function ({ export default async function ({
src, src,
type, type,
sizes: imagesizes, sizes: imagesizes,
format, format,
breakpoints, breakpoints,
placeholder, placeholder,
fallbackFormat, fallbackFormat,
includeSourceFormat, includeSourceFormat,
formatOptions, formatOptions,
artDirectives, artDirectives,
transformConfigs, transformConfigs,
}) { }) {
try { try {
const args = Array.from(arguments); const args = Array.from(arguments);
const hash = objectHash(args); const hash = objectHash(args);
if (imagesData.has(hash)) { if (imagesData.has(hash)) {
return imagesData.get(hash); return imagesData.get(hash);
} }
const start = performance.now(); const start = performance.now();
const { path, base, rest, image, imageWidth, imageHeight, imageFormat } = const { path, base, rest, image, imageWidth, imageHeight, imageFormat } =
await getProcessedImage(src, transformConfigs); await getProcessedImage(src, transformConfigs);
await delay(250); await delay(100);
src = path; src = path;
rest.aspect = `${imageWidth / imageHeight}`; rest.aspect = `${imageWidth / imageHeight}`;
if (!fallbackFormat) { if (!fallbackFormat) {
fallbackFormat = imageFormat; fallbackFormat = imageFormat;
} }
// Fetch both image sources and art-directed images // Fetch both image sources and art-directed images
const [mainImage, artDirectedImages] = await pMap( const [mainImage, artDirectedImages] = await pMap(
[ [
async () => async () =>
await getImageSources( await getImageSources(
src, src,
base, base,
image, image,
format, format,
imageWidth, imageWidth,
imagesizes, imagesizes,
breakpoints, breakpoints,
placeholder, placeholder,
imageFormat, imageFormat,
formatOptions, formatOptions,
fallbackFormat, fallbackFormat,
includeSourceFormat, includeSourceFormat,
rest rest
), ),
async () => { async () => {
await delay(250); await delay(100);
return await getArtDirectedImages( return await getArtDirectedImages(
artDirectives, artDirectives,
placeholder, placeholder,
format, format,
imagesizes, imagesizes,
breakpoints, breakpoints,
fallbackFormat, fallbackFormat,
includeSourceFormat, includeSourceFormat,
formatOptions, formatOptions,
rest rest
); );
}, },
], ],
async (task) => await task(), async (task) => await task(),
{ concurrency: 1 } { concurrency: 1 }
); );
// Ensure artDirectedImages is an array // Ensure artDirectedImages is an array
const images = Array.isArray(artDirectedImages) ? [...artDirectedImages, mainImage] : [mainImage]; const images = Array.isArray(artDirectedImages) ? [...artDirectedImages, mainImage] : [mainImage];
const uuid = crypto.randomBytes(4).toString("hex").toUpperCase(); const uuid = crypto.randomBytes(4).toString("hex").toUpperCase();
const returnObject = { const returnObject = {
uuid, uuid,
images, images,
}; };
imagesData.set(hash, returnObject); imagesData.set(hash, returnObject);
const end = performance.now(); const end = performance.now();
console.log( console.log(
`Responsive Image sets generated for ${type} at ${args[0].src} in ${end - start}ms` `Responsive Image sets generated for ${type} at ${args[0].src} in ${end - start}ms`
); );
return returnObject; return returnObject;
} catch (error) { } catch (error) {
console.error("Error processing images:", error); console.error("Error processing images:", error);
throw error; throw error;
} }
} }

View File

@ -1,91 +1,91 @@
// @ts-check // @ts-check
import getSrcset from "./getSrcset.js"; import getSrcset from "./getSrcset.js";
import getConfigOptions from "./getConfigOptions.js"; import getConfigOptions from "./getConfigOptions.js";
import getFallbackImage from "./getFallbackImage.js"; import getFallbackImage from "./getFallbackImage.js";
import pMap from "p-map"; import pMap from "p-map";
function delay(ms) { function delay(ms) {
return new Promise((resolve) => setTimeout(resolve, ms)); return new Promise((resolve) => setTimeout(resolve, ms));
} }
export default async function getImageSources( export default async function getImageSources(
src, src,
base, base,
image, image,
format, format,
imageWidth, imageWidth,
imagesizes, imagesizes,
breakpoints, breakpoints,
placeholder, placeholder,
imageFormat, imageFormat,
formatOptions, formatOptions,
fallbackFormat, fallbackFormat,
includeSourceFormat, includeSourceFormat,
rest rest
) { ) {
try { try {
const calculatedConfigs = getConfigOptions( const calculatedConfigs = getConfigOptions(
imageWidth, imageWidth,
imagesizes, imagesizes,
breakpoints, breakpoints,
format, format,
imageFormat, imageFormat,
fallbackFormat, fallbackFormat,
includeSourceFormat includeSourceFormat
); );
const { formats, requiredBreakpoints } = calculatedConfigs; const { formats, requiredBreakpoints } = calculatedConfigs;
imagesizes = calculatedConfigs.imagesizes; imagesizes = calculatedConfigs.imagesizes;
const maxWidth = requiredBreakpoints[requiredBreakpoints.length - 1]; const maxWidth = requiredBreakpoints[requiredBreakpoints.length - 1];
const sliceLength = -(maxWidth.toString().length + 2); const sliceLength = -(maxWidth.toString().length + 2);
const sources = await pMap( const sources = await pMap(
formats, formats,
async (format) => { async (format) => {
try { try {
await delay(250); await delay(100);
const srcset = await getSrcset(src, base, requiredBreakpoints, format, { const srcset = await getSrcset(src, base, requiredBreakpoints, format, {
...rest, ...rest,
...formatOptions[format], ...formatOptions[format],
}); });
const srcsets = srcset.split(", "); const srcsets = srcset.split(", ");
const srcObject = const srcObject =
format === fallbackFormat format === fallbackFormat
? { src: srcsets[srcsets.length - 1].slice(0, sliceLength) } ? { src: srcsets[srcsets.length - 1].slice(0, sliceLength) }
: {}; : {};
return { return {
...srcObject, ...srcObject,
format, format,
srcset, srcset,
}; };
} catch (error) { } catch (error) {
console.error(`Error processing format ${format}:`, error); console.error(`Error processing format ${format}:`, error);
return null; return null;
} }
}, },
{ concurrency: 1 } { concurrency: 1 }
); );
const filteredSources = sources.filter(Boolean); const filteredSources = sources.filter(Boolean);
const sizes = { const sizes = {
width: maxWidth, width: maxWidth,
height: Math.round(maxWidth / rest.aspect), height: Math.round(maxWidth / rest.aspect),
}; };
const fallback = await getFallbackImage( const fallback = await getFallbackImage(
src, src,
placeholder, placeholder,
image, image,
fallbackFormat, fallbackFormat,
formatOptions, formatOptions,
rest rest
) )
return { sources: filteredSources, sizes, fallback, imagesizes }; return { sources: filteredSources, sizes, fallback, imagesizes };
} catch (error) { } catch (error) {
console.error("Error in getImageSources:", error); console.error("Error in getImageSources:", error);
return { sources: [], sizes: {}, fallback: null, imagesizes: null }; return { sources: [], sizes: {}, fallback: null, imagesizes: null };
} }
} }

View File

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

235
public/css/global.css Normal file
View File

@ -0,0 +1,235 @@
@import "tailwindcss";
@plugin "@tailwindcss/typography";
@layer components {
.prose-styles {
@apply hover:prose-a:text-black prose prose-blockquote:border-l-black prose-blockquote:text-neutral-600 prose-code:text-black prose-headings:text-black text-neutral-600 prose-pre:rounded-xl prose-pre:p-4 max-w-none prose-headings:font-medium prose-pre:normal-case prose-pre:bg-white;
/* Base layout classes */
@apply prose max-w-3xl pt-0 mx-auto;
}
.simple-prose-styles {
@apply prose text-xs prose-headings:text-xs prose-pre:normal-case;
}
}
@layer base {
a {
@apply text-blue-400 no-underline transition-colors;
}
a:hover {
@apply underline;
}
}
@layer base {
table {
@apply min-w-full border-collapse;
}
table thead {
@apply bg-gray-200;
}
table th {
@apply py-3 px-6 text-left text-xs font-medium text-gray-600 uppercase tracking-wider;
}
table td {
@apply py-4 px-6 border-b border-gray-200;
}
table tbody tr {
@apply transition-colors;
}
table tbody tr:nth-child(odd) {
@apply bg-white;
}
table tbody tr:nth-child(even) {
@apply bg-gray-50;
}
table tbody tr:nth-child(odd):hover {
@apply bg-orange-50;
}
table tbody tr:nth-child(even):hover {
@apply bg-orange-100;
}
}
@layer base {
.astro-imagetools-img {
@apply min-w-full border-collapse rounded-lg overflow-hidden;
background-image: none !important;
object-fit: contain;
}
.lightbox-main{
background-image: none !important;
}
}
@layer base {
.specs-table {
@apply min-w-full border-collapse rounded-lg overflow-hidden;
}
.specs-table thead {
@apply bg-gray-200;
}
.specs-table th {
@apply py-3 px-6 text-left text-xs text-gray-600 uppercase tracking-wider;
}
.specs-table td {
@apply py-4 px-6 border-b border-gray-200;
}
.specs-table tbody tr {
@apply transition-colors;
}
.specs-table tbody tr:nth-child(odd) {
@apply bg-white;
}
.specs-table tbody tr:nth-child(even) {
@apply bg-gray-50;
}
.specs-table tbody tr:nth-child(odd):hover {
@apply bg-orange-50;
}
.specs-table tbody tr:nth-child(even):hover {
@apply bg-orange-100;
}
/* Bold the first column cells */
.specs-table th:first-child,
.specs-table td:first-child {
@apply font-semibold;
}
}
@layer components {
.table-default {
@apply min-w-full border-collapse shadow-lg;
}
.table-default thead {
@apply bg-gray-200;
}
.table-default th {
@apply py-3 px-6 text-left text-xs font-medium text-gray-600 uppercase tracking-wider;
}
.table-default td {
@apply py-4 px-6 border-b border-gray-200;
}
.table-default tbody tr {
@apply transition-colors;
}
/* Alternating row colors */
.table-default tbody tr:nth-child(odd) {
@apply bg-white;
}
.table-default tbody tr:nth-child(even) {
@apply bg-gray-50;
}
/* Hover effects with orange tint */
.table-default tbody tr:nth-child(odd):hover {
@apply bg-orange-50;
}
.table-default tbody tr:nth-child(even):hover {
@apply bg-orange-100;
}
}
@theme {
/* Typography*/
--font-sans: "Inter", sans-serif;
--font-mono: "IBM PLex Mono", monospace;
--text-xs:1rem;
/* Colors */
--color-orange-50: hsl(22, 100%, 96%);
--color-orange-100: hsl(25, 100%, 91%);
--color-orange-200: hsl(22, 100%, 82%);
--color-orange-300: hsl(20, 100%, 71%);
--color-orange-400: hsl(16, 100%, 60%);
--color-orange-500: hsl(14, 100%, 52%);
--color-orange-600: hsl(9, 100%, 50%);
--color-orange-700: hsl(6, 98%, 40%);
--color-orange-800: hsl(4, 87%, 34%);
--color-orange-900: hsl(4, 83%, 28%);
--color-orange-950: hsl(1, 89%, 15%);
/* colors */
--color-white: #fafafa;
--color-black: #12161d;
}
@supports (font-variation-settings: normal) {
:root {
font-family: InterVariable, sans-serif;
}
}
:root {
/* Typography*/
font-family: Inter, sans-serif;
font-feature-settings: "liga" 1, "calt" 1,
/* Contextual Alternates */ "dlig" 1, /* Discretionary Ligatures */ "ss07" 1,
/* fSquare punctuation */ "ss08" 1, /* Square quotes */ "zero" 1,
/* Slashed zero */ "tnum" 1, /* Tabular numbers */ "cv03" 1,
/* Open six */ "cv04" 1, /* Open nine */ "cv01" 1,
/* Alternate one */ "cv09", /* Flat-top three */ "cv02" 1; /* Open 4 */
/* style code blocks*/
}
.markdown-content {
@apply prose dark:prose-invert max-w-none font-mono;
}
/* Headings (Scaled Down & Responsive) */
.markdown-content h1 {
@apply text-xl font-medium mt-5 mb-3 md:mt-6 md:mb-4;
}
.markdown-content h2 {
@apply text-xs font-medium mt-4 mb-2 md:mt-5 md:mb-3;
}
.markdown-content h3 {
@apply text-sm font-medium mt-3 mb-1 md:mt-4 md:mb-3;
}
.markdown-content h4 {
@apply text-neutral-500 font-medium mt-3 mb-1 md:mt-4 md:mb-2;
}
.markdown-content h5 {
@apply text-sm font-medium mt-2 mb-1 md:mt-3 md:mb-2;
}
.markdown-content h6 {
@apply text-xs font-medium mt-2 mb-1 uppercase md:mt-3 md:mb-2;
}
/* Paragraphs */
.markdown-content p {
@apply text-neutral-500 leading-relaxed mb-3 md:mb-4;
}
/* Lists */
.markdown-content ul {
@apply list-disc list-inside ml-0 pl-0 md:ml-5;
}
.markdown-content li {
@apply text-neutral-500 leading-relaxed;
}
.markdown-content ol {
@apply list-decimal list-inside ml-3 md:ml-5;
}
/* Code Blocks */
.markdown-content pre {
@apply bg-gray-900 text-white p-2 rounded-md overflow-x-auto md:p-3;
}
.markdown-content code {
@apply bg-gray-800 text-xs p-1 rounded-md md:text-sm;
}
/* Links */
.markdown-content a {
@apply text-blue-600 hover:underline dark:text-blue-400;
}
/* Blockquotes */
.markdown-content blockquote {
@apply border-l-4 border-gray-500 pl-3 italic text-gray-600 md:pl-4;
}

5
public/js/cdn.min.js vendored Normal file

File diff suppressed because one or more lines are too long

2
public/js/flowbite.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -16,6 +16,10 @@ import StructuredData from './head/ArticleStructuredData.astro'
import Hreflang from '@/components/polymech/hreflang.astro' import Hreflang from '@/components/polymech/hreflang.astro'
import { IComponentConfig } from "@polymech/commons" import { IComponentConfig } from "@polymech/commons"
// Determine the path to your compiled Tailwind CSS.
// Assuming your built Tailwind CSS ends up in 'global.css' in your public directory after Astro build.
const tailwindCSSPath = "/global.css"; // <- **Important: Verify this path after your build process**
export interface Props { export interface Props {
title?: string; title?: string;
meta_title?: string; meta_title?: string;
@ -132,11 +136,9 @@ const keywords = await item_keywords(item, Astro.currentLocale)
<link rel="preload" href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;1,100;1,200;1,300;1,400;1,500;1,600;1,700&display=swap" as="style" /> <link rel="preload" href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;1,100;1,200;1,300;1,400;1,500;1,600;1,700&display=swap" as="style" />
<link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;1,100;1,200;1,300;1,400;1,500;1,600;1,700&display=swap" rel="stylesheet" media="print" onload="this.onload=null;this.removeAttribute('media');" /> <link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;1,100;1,200;1,300;1,400;1,500;1,600;1,700&display=swap" rel="stylesheet" media="print" onload="this.onload=null;this.removeAttribute('media');" />
<script src="/js/flowbite.min.js" defer></script>
<script src="https://cdn.jsdelivr.net/npm/flowbite@3.0.0/dist/flowbite.min.js" defer></script> <script src="/js/cdn.min.js" defer></script>
<!-- alpine JS -->
<script src="//unpkg.com/alpinejs" defer></script>
<StructuredData frontmatter={item} /> <StructuredData frontmatter={item} />

View File

@ -1,12 +1,12 @@
/** @type {import('tailwindcss').Config} */ /** @type {import('tailwindcss').Config} */
export default { export default {
content: ["./src/**/*.{astro,html,js,jsx,md,mdx,svelte,ts,tsx,vue}"], content: ["./src/**/*.{astro,html,js,jsx,md,mdx,svelte,ts,tsx,vue}"],
theme: { theme: {
extend: {}, extend: {},
}, },
daisyui: { plugins: [require("@tailwindcss/typography")],
// Add your daisy ui themes here presets: [
themes: ["night"],
},
plugins: [require("daisyui"), require("@tailwindcss/typography")], ]
}; }

File diff suppressed because one or more lines are too long