mirror of
https://github.com/withastro/astro.git
synced 2025-02-03 22:29:08 -05:00
refactor(assets): Move generation logic out of internal.ts (#7102)
This commit is contained in:
parent
6cbe5e7472
commit
4516d7b22c
4 changed files with 133 additions and 125 deletions
5
.changeset/brown-goats-serve.md
Normal file
5
.changeset/brown-goats-serve.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
'astro': patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Fix image services not being usable on Edge runtimes
|
126
packages/astro/src/assets/generate.ts
Normal file
126
packages/astro/src/assets/generate.ts
Normal file
|
@ -0,0 +1,126 @@
|
||||||
|
import fs from 'node:fs';
|
||||||
|
import { basename, join } from 'node:path/posix';
|
||||||
|
import type { StaticBuildOptions } from '../core/build/types.js';
|
||||||
|
import { warn } from '../core/logger/core.js';
|
||||||
|
import { prependForwardSlash } from '../core/path.js';
|
||||||
|
import { getConfiguredImageService, isESMImportedImage } from './internal.js';
|
||||||
|
import type { LocalImageService } from './services/service.js';
|
||||||
|
import type { ImageTransform } from './types.js';
|
||||||
|
|
||||||
|
interface GenerationDataUncached {
|
||||||
|
cached: false;
|
||||||
|
weight: {
|
||||||
|
before: number;
|
||||||
|
after: number;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface GenerationDataCached {
|
||||||
|
cached: true;
|
||||||
|
}
|
||||||
|
|
||||||
|
type GenerationData = GenerationDataUncached | GenerationDataCached;
|
||||||
|
|
||||||
|
export async function generateImage(
|
||||||
|
buildOpts: StaticBuildOptions,
|
||||||
|
options: ImageTransform,
|
||||||
|
filepath: string
|
||||||
|
): Promise<GenerationData | undefined> {
|
||||||
|
if (!isESMImportedImage(options.src)) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
let useCache = true;
|
||||||
|
const assetsCacheDir = new URL('assets/', buildOpts.settings.config.cacheDir);
|
||||||
|
|
||||||
|
// Ensure that the cache directory exists
|
||||||
|
try {
|
||||||
|
await fs.promises.mkdir(assetsCacheDir, { recursive: true });
|
||||||
|
} catch (err) {
|
||||||
|
warn(
|
||||||
|
buildOpts.logging,
|
||||||
|
'astro:assets',
|
||||||
|
`An error was encountered while creating the cache directory. Proceeding without caching. Error: ${err}`
|
||||||
|
);
|
||||||
|
useCache = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let serverRoot: URL, clientRoot: URL;
|
||||||
|
if (buildOpts.settings.config.output === 'server') {
|
||||||
|
serverRoot = buildOpts.settings.config.build.server;
|
||||||
|
clientRoot = buildOpts.settings.config.build.client;
|
||||||
|
} else {
|
||||||
|
serverRoot = buildOpts.settings.config.outDir;
|
||||||
|
clientRoot = buildOpts.settings.config.outDir;
|
||||||
|
}
|
||||||
|
|
||||||
|
const finalFileURL = new URL('.' + filepath, clientRoot);
|
||||||
|
const finalFolderURL = new URL('./', finalFileURL);
|
||||||
|
const cachedFileURL = new URL(basename(filepath), assetsCacheDir);
|
||||||
|
|
||||||
|
try {
|
||||||
|
await fs.promises.copyFile(cachedFileURL, finalFileURL);
|
||||||
|
|
||||||
|
return {
|
||||||
|
cached: true,
|
||||||
|
};
|
||||||
|
} catch (e) {
|
||||||
|
// no-op
|
||||||
|
}
|
||||||
|
|
||||||
|
// The original file's path (the `src` attribute of the ESM imported image passed by the user)
|
||||||
|
const originalImagePath = options.src.src;
|
||||||
|
|
||||||
|
const fileData = await fs.promises.readFile(
|
||||||
|
new URL(
|
||||||
|
'.' +
|
||||||
|
prependForwardSlash(
|
||||||
|
join(buildOpts.settings.config.build.assets, basename(originalImagePath))
|
||||||
|
),
|
||||||
|
serverRoot
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
const imageService = (await getConfiguredImageService()) as LocalImageService;
|
||||||
|
const resultData = await imageService.transform(
|
||||||
|
fileData,
|
||||||
|
{ ...options, src: originalImagePath },
|
||||||
|
buildOpts.settings.config.image.service.config
|
||||||
|
);
|
||||||
|
|
||||||
|
await fs.promises.mkdir(finalFolderURL, { recursive: true });
|
||||||
|
|
||||||
|
if (useCache) {
|
||||||
|
try {
|
||||||
|
await fs.promises.writeFile(cachedFileURL, resultData.data);
|
||||||
|
await fs.promises.copyFile(cachedFileURL, finalFileURL);
|
||||||
|
} catch (e) {
|
||||||
|
warn(
|
||||||
|
buildOpts.logging,
|
||||||
|
'astro:assets',
|
||||||
|
`An error was encountered while creating the cache directory. Proceeding without caching. Error: ${e}`
|
||||||
|
);
|
||||||
|
await fs.promises.writeFile(finalFileURL, resultData.data);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
await fs.promises.writeFile(finalFileURL, resultData.data);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
cached: false,
|
||||||
|
weight: {
|
||||||
|
before: Math.trunc(fileData.byteLength / 1024),
|
||||||
|
after: Math.trunc(resultData.data.byteLength / 1024),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getStaticImageList(): Iterable<
|
||||||
|
[string, { path: string; options: ImageTransform }]
|
||||||
|
> {
|
||||||
|
if (!globalThis?.astroAsset?.staticImages) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
return globalThis.astroAsset.staticImages?.entries();
|
||||||
|
}
|
|
@ -1,10 +1,5 @@
|
||||||
import fs from 'node:fs';
|
|
||||||
import { basename, join } from 'node:path/posix';
|
|
||||||
import type { StaticBuildOptions } from '../core/build/types.js';
|
|
||||||
import { AstroError, AstroErrorData } from '../core/errors/index.js';
|
import { AstroError, AstroErrorData } from '../core/errors/index.js';
|
||||||
import { warn } from '../core/logger/core.js';
|
import { isLocalService, type ImageService } from './services/service.js';
|
||||||
import { prependForwardSlash } from '../core/path.js';
|
|
||||||
import { isLocalService, type ImageService, type LocalImageService } from './services/service.js';
|
|
||||||
import type { GetImageResult, ImageMetadata, ImageTransform } from './types.js';
|
import type { GetImageResult, ImageMetadata, ImageTransform } from './types.js';
|
||||||
|
|
||||||
export function isESMImportedImage(src: ImageMetadata | string): src is ImageMetadata {
|
export function isESMImportedImage(src: ImageMetadata | string): src is ImageMetadata {
|
||||||
|
@ -63,121 +58,3 @@ export async function getImage(
|
||||||
: {},
|
: {},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getStaticImageList(): Iterable<
|
|
||||||
[string, { path: string; options: ImageTransform }]
|
|
||||||
> {
|
|
||||||
if (!globalThis?.astroAsset?.staticImages) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
return globalThis.astroAsset.staticImages?.entries();
|
|
||||||
}
|
|
||||||
|
|
||||||
interface GenerationDataUncached {
|
|
||||||
cached: false;
|
|
||||||
weight: {
|
|
||||||
before: number;
|
|
||||||
after: number;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
interface GenerationDataCached {
|
|
||||||
cached: true;
|
|
||||||
}
|
|
||||||
|
|
||||||
type GenerationData = GenerationDataUncached | GenerationDataCached;
|
|
||||||
|
|
||||||
export async function generateImage(
|
|
||||||
buildOpts: StaticBuildOptions,
|
|
||||||
options: ImageTransform,
|
|
||||||
filepath: string
|
|
||||||
): Promise<GenerationData | undefined> {
|
|
||||||
if (!isESMImportedImage(options.src)) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
let useCache = true;
|
|
||||||
const assetsCacheDir = new URL('assets/', buildOpts.settings.config.cacheDir);
|
|
||||||
|
|
||||||
// Ensure that the cache directory exists
|
|
||||||
try {
|
|
||||||
await fs.promises.mkdir(assetsCacheDir, { recursive: true });
|
|
||||||
} catch (err) {
|
|
||||||
warn(
|
|
||||||
buildOpts.logging,
|
|
||||||
'astro:assets',
|
|
||||||
`An error was encountered while creating the cache directory. Proceeding without caching. Error: ${err}`
|
|
||||||
);
|
|
||||||
useCache = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
let serverRoot: URL, clientRoot: URL;
|
|
||||||
if (buildOpts.settings.config.output === 'server') {
|
|
||||||
serverRoot = buildOpts.settings.config.build.server;
|
|
||||||
clientRoot = buildOpts.settings.config.build.client;
|
|
||||||
} else {
|
|
||||||
serverRoot = buildOpts.settings.config.outDir;
|
|
||||||
clientRoot = buildOpts.settings.config.outDir;
|
|
||||||
}
|
|
||||||
|
|
||||||
const finalFileURL = new URL('.' + filepath, clientRoot);
|
|
||||||
const finalFolderURL = new URL('./', finalFileURL);
|
|
||||||
const cachedFileURL = new URL(basename(filepath), assetsCacheDir);
|
|
||||||
|
|
||||||
try {
|
|
||||||
await fs.promises.copyFile(cachedFileURL, finalFileURL);
|
|
||||||
|
|
||||||
return {
|
|
||||||
cached: true,
|
|
||||||
};
|
|
||||||
} catch (e) {
|
|
||||||
// no-op
|
|
||||||
}
|
|
||||||
|
|
||||||
// The original file's path (the `src` attribute of the ESM imported image passed by the user)
|
|
||||||
const originalImagePath = options.src.src;
|
|
||||||
|
|
||||||
const fileData = await fs.promises.readFile(
|
|
||||||
new URL(
|
|
||||||
'.' +
|
|
||||||
prependForwardSlash(
|
|
||||||
join(buildOpts.settings.config.build.assets, basename(originalImagePath))
|
|
||||||
),
|
|
||||||
serverRoot
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
const imageService = (await getConfiguredImageService()) as LocalImageService;
|
|
||||||
const resultData = await imageService.transform(
|
|
||||||
fileData,
|
|
||||||
{ ...options, src: originalImagePath },
|
|
||||||
buildOpts.settings.config.image.service.config
|
|
||||||
);
|
|
||||||
|
|
||||||
await fs.promises.mkdir(finalFolderURL, { recursive: true });
|
|
||||||
|
|
||||||
if (useCache) {
|
|
||||||
try {
|
|
||||||
await fs.promises.writeFile(cachedFileURL, resultData.data);
|
|
||||||
await fs.promises.copyFile(cachedFileURL, finalFileURL);
|
|
||||||
} catch (e) {
|
|
||||||
warn(
|
|
||||||
buildOpts.logging,
|
|
||||||
'astro:assets',
|
|
||||||
`An error was encountered while creating the cache directory. Proceeding without caching. Error: ${e}`
|
|
||||||
);
|
|
||||||
await fs.promises.writeFile(finalFileURL, resultData.data);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
await fs.promises.writeFile(finalFileURL, resultData.data);
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
cached: false,
|
|
||||||
weight: {
|
|
||||||
before: Math.trunc(fileData.byteLength / 1024),
|
|
||||||
after: Math.trunc(resultData.data.byteLength / 1024),
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
|
@ -19,7 +19,7 @@ import type {
|
||||||
import {
|
import {
|
||||||
generateImage as generateImageInternal,
|
generateImage as generateImageInternal,
|
||||||
getStaticImageList,
|
getStaticImageList,
|
||||||
} from '../../assets/internal.js';
|
} from '../../assets/generate.js';
|
||||||
import { hasPrerenderedPages, type BuildInternals } from '../../core/build/internal.js';
|
import { hasPrerenderedPages, type BuildInternals } from '../../core/build/internal.js';
|
||||||
import {
|
import {
|
||||||
prependForwardSlash,
|
prependForwardSlash,
|
||||||
|
|
Loading…
Add table
Reference in a new issue