Parallelize @astrojs/image transforms (#4626)
This commit is contained in:
parent
5231ec05d2
commit
494c2b8353
4 changed files with 31 additions and 7 deletions
5
.changeset/rich-dolphins-teach.md
Normal file
5
.changeset/rich-dolphins-teach.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
'@astrojs/image': patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Parallelize image transforms
|
|
@ -40,6 +40,7 @@
|
||||||
"test": "mocha --exit --timeout 20000 test"
|
"test": "mocha --exit --timeout 20000 test"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@altano/tiny-async-pool": "^1.0.2",
|
||||||
"image-size": "^1.0.2",
|
"image-size": "^1.0.2",
|
||||||
"magic-string": "^0.25.9",
|
"magic-string": "^0.25.9",
|
||||||
"mime": "^3.0.0",
|
"mime": "^3.0.0",
|
||||||
|
|
|
@ -7,6 +7,8 @@ import type { SSRImageService, TransformOptions } from '../loaders/index.js';
|
||||||
import { loadLocalImage, loadRemoteImage } from '../utils/images.js';
|
import { loadLocalImage, loadRemoteImage } from '../utils/images.js';
|
||||||
import { debug, info, LoggerLevel, warn } from '../utils/logger.js';
|
import { debug, info, LoggerLevel, warn } from '../utils/logger.js';
|
||||||
import { isRemoteImage } from '../utils/paths.js';
|
import { isRemoteImage } from '../utils/paths.js';
|
||||||
|
import OS from 'node:os';
|
||||||
|
import { doWork } from '@altano/tiny-async-pool';
|
||||||
|
|
||||||
function getTimeStat(timeStart: number, timeEnd: number) {
|
function getTimeStat(timeStart: number, timeEnd: number) {
|
||||||
const buildTime = timeEnd - timeStart;
|
const buildTime = timeEnd - timeStart;
|
||||||
|
@ -23,19 +25,26 @@ export interface SSGBuildParams {
|
||||||
|
|
||||||
export async function ssgBuild({ loader, staticImages, config, outDir, logLevel }: SSGBuildParams) {
|
export async function ssgBuild({ loader, staticImages, config, outDir, logLevel }: SSGBuildParams) {
|
||||||
const timer = performance.now();
|
const timer = performance.now();
|
||||||
|
const cpuCount = OS.cpus().length;
|
||||||
|
|
||||||
info({
|
info({
|
||||||
level: logLevel,
|
level: logLevel,
|
||||||
prefix: false,
|
prefix: false,
|
||||||
message: `${bgGreen(
|
message: `${bgGreen(
|
||||||
black(` optimizing ${staticImages.size} image${staticImages.size > 1 ? 's' : ''} `)
|
black(
|
||||||
|
` optimizing ${staticImages.size} image${
|
||||||
|
staticImages.size > 1 ? 's' : ''
|
||||||
|
} in batches of ${cpuCount} `
|
||||||
|
)
|
||||||
)}`,
|
)}`,
|
||||||
});
|
});
|
||||||
|
|
||||||
const inputFiles = new Set<string>();
|
const inputFiles = new Set<string>();
|
||||||
|
|
||||||
// process transforms one original image file at a time
|
async function processStaticImage([src, transformsMap]: [
|
||||||
for (let [src, transformsMap] of staticImages) {
|
string,
|
||||||
|
Map<string, TransformOptions>
|
||||||
|
]): Promise<void> {
|
||||||
let inputFile: string | undefined = undefined;
|
let inputFile: string | undefined = undefined;
|
||||||
let inputBuffer: Buffer | undefined = undefined;
|
let inputBuffer: Buffer | undefined = undefined;
|
||||||
|
|
||||||
|
@ -60,15 +69,15 @@ export async function ssgBuild({ loader, staticImages, config, outDir, logLevel
|
||||||
if (!inputBuffer) {
|
if (!inputBuffer) {
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
warn({ level: logLevel, message: `"${src}" image could not be fetched` });
|
warn({ level: logLevel, message: `"${src}" image could not be fetched` });
|
||||||
continue;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const transforms = Array.from(transformsMap.entries());
|
const transforms = Array.from(transformsMap.entries());
|
||||||
|
|
||||||
debug({ level: logLevel, prefix: false, message: `${green('▶')} ${src}` });
|
debug({ level: logLevel, prefix: false, message: `${green('▶')} transforming ${src}` });
|
||||||
let timeStart = performance.now();
|
let timeStart = performance.now();
|
||||||
|
|
||||||
// process each transformed versiono of the
|
// process each transformed version
|
||||||
for (const [filename, transform] of transforms) {
|
for (const [filename, transform] of transforms) {
|
||||||
timeStart = performance.now();
|
timeStart = performance.now();
|
||||||
let outputFile: string;
|
let outputFile: string;
|
||||||
|
@ -92,11 +101,14 @@ export async function ssgBuild({ loader, staticImages, config, outDir, logLevel
|
||||||
debug({
|
debug({
|
||||||
level: logLevel,
|
level: logLevel,
|
||||||
prefix: false,
|
prefix: false,
|
||||||
message: ` ${cyan('└─')} ${dim(pathRelative)} ${dim(timeIncrease)}`,
|
message: ` ${cyan('created')} ${dim(pathRelative)} ${dim(timeIncrease)}`,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// transform each original image file in batches
|
||||||
|
await doWork(cpuCount, staticImages, processStaticImage);
|
||||||
|
|
||||||
info({
|
info({
|
||||||
level: logLevel,
|
level: logLevel,
|
||||||
prefix: false,
|
prefix: false,
|
||||||
|
|
|
@ -2214,6 +2214,7 @@ importers:
|
||||||
|
|
||||||
packages/integrations/image:
|
packages/integrations/image:
|
||||||
specifiers:
|
specifiers:
|
||||||
|
'@altano/tiny-async-pool': ^1.0.2
|
||||||
'@types/sharp': ^0.30.5
|
'@types/sharp': ^0.30.5
|
||||||
astro: workspace:*
|
astro: workspace:*
|
||||||
astro-scripts: workspace:*
|
astro-scripts: workspace:*
|
||||||
|
@ -2223,6 +2224,7 @@ importers:
|
||||||
mime: ^3.0.0
|
mime: ^3.0.0
|
||||||
sharp: ^0.30.6
|
sharp: ^0.30.6
|
||||||
dependencies:
|
dependencies:
|
||||||
|
'@altano/tiny-async-pool': 1.0.2
|
||||||
image-size: 1.0.2
|
image-size: 1.0.2
|
||||||
magic-string: 0.25.9
|
magic-string: 0.25.9
|
||||||
mime: 3.0.0
|
mime: 3.0.0
|
||||||
|
@ -3155,6 +3157,10 @@ packages:
|
||||||
'@algolia/requester-common': 4.14.2
|
'@algolia/requester-common': 4.14.2
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/@altano/tiny-async-pool/1.0.2:
|
||||||
|
resolution: {integrity: sha512-qQzaI0TBUPdpjZ3qo5b2ziQY9MSNpbziH2ZrE5lvtUZL+kn9GwVuVJwoOubaoNkeDB+rqEefnpu1k+oMpOCYiw==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@ampproject/remapping/2.2.0:
|
/@ampproject/remapping/2.2.0:
|
||||||
resolution: {integrity: sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==}
|
resolution: {integrity: sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==}
|
||||||
engines: {node: '>=6.0.0'}
|
engines: {node: '>=6.0.0'}
|
||||||
|
|
Loading…
Reference in a new issue