Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow loading images from /public #54

Merged
merged 8 commits into from
May 18, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
node_modules
astroViteConfigs.js
demo/dist
1 change: 1 addition & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
pnpm-lock.yaml
demo/dist
Binary file added demo/public/images/public.jpeg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
14 changes: 11 additions & 3 deletions demo/src/pages/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,20 +49,28 @@ The `placeholder` property tells the image what to show while loading.

## Internal Image

The following is an example of a reference to an internal image.
The following is an example of a reference to an internal image in the `src` directory (`../images/elva-800w.jpg`).

![A father holding his beloved daughter in his arms](../images//elva-800w.jpg)
![A father holding his beloved daughter in his arms](../images/elva-800w.jpg)

<hr />

## External Image

The following is an example of a reference to an external image.
The following is an example of a reference to an external image (`https://picsum.photos/1024/768`).

![A random image](https://picsum.photos/1024/768)

<hr />

## Image in /public

This image is in the public directory (`/images/public.jpeg`).

![A random image](/images/public.jpeg)

<hr />

## Learn More

You can optionally configure many more things!
Expand Down
4 changes: 4 additions & 0 deletions packages/astro-imagetools/.npmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
*.test.ts
test-fixtures
astroViteConfigs.js
vitest.config.ts
3 changes: 2 additions & 1 deletion packages/astro-imagetools/api/utils/getProcessedImage.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
supportedImageTypes,
} from "../../utils/runtimeChecks.js";
import { fileURLToPath } from "node:url";
import { getSrcPath } from "./getSrcPath.js";

const { getImageDetails } = await (sharp
? import("./imagetools.js")
Expand Down Expand Up @@ -93,7 +94,7 @@ export default async (src, transformConfigs) => {
const path = src.replace(/\\/g, `/`);

const { image, imageWidth, imageHeight, imageFormat } = await getImageDetails(
`./${src}`,
getSrcPath(src),
width,
height,
aspect
Expand Down
30 changes: 30 additions & 0 deletions packages/astro-imagetools/api/utils/getSrcPath.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import fs from "fs";
import path from "path";

// To strip off params when checking for file on disk.
const paramPattern = /\?.*/;

const { default: astroViteConfigs } = await import("../../astroViteConfigs.js");

/**
* getSrcPath allows the use of `src` attributes relative to either the public folder or project root.
*
* It first checks to see if the src is a file relative to the project root.
* If the file isn't found, it will look in the public folder.
* Finally, if it still can't be found, the original input will be returned.
*/
export function getSrcPath(src) {
// If this is already resolved to a file, return it.
if (fs.existsSync(src.replace(paramPattern, ""))) return src;

const rootPath = path.join(astroViteConfigs.rootDir, src);
const rootTest = rootPath.replace(paramPattern, "");
if (fs.existsSync(rootTest)) return rootPath;

const publicPath = path.join(astroViteConfigs.publicDir, src);
const publicTest = publicPath.replace(paramPattern, "");
if (fs.existsSync(publicTest)) return publicPath;

// Fallback
return src;
}
67 changes: 67 additions & 0 deletions packages/astro-imagetools/api/utils/getSrcPath.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import path from "node:path";
import { describe, expect, it, afterAll, vi } from "vitest";
import { getSrcPath } from "./getSrcPath";

vi.mock("../../astroViteConfigs.js", () => {
return {
default: {
rootDir: buildPath(),
// Custom publicDir
publicDir: buildPath("out"),
},
};
});

/**
* Build an absolute path to the target in the fixture directory
*/
function buildPath(target = "") {
return path.resolve(__dirname, "../../test-fixtures/getSrcPath", target);
}

describe("getLinkElement", () => {
afterAll(() => {
vi.unmock("../../astroViteConfigs.js");
});

it("finds a file in the root of the project", () => {
const result = getSrcPath("root.jpeg");
expect(result).toBe(buildPath("root.jpeg"));
});

it("finds a file in the public folder", () => {
const result = getSrcPath("out.jpeg");
expect(result).toBe(buildPath("out/out.jpeg"));
});

it("returns an absolute path unchanged, if it exists", () => {
const result = getSrcPath(buildPath("out/out.jpeg"));
expect(result).toBe(buildPath("out/out.jpeg"));
});

it("handles query parameters", () => {
const result = getSrcPath("root.jpeg?w=200");
expect(result).toBe(buildPath("root.jpeg?w=200"));
});

it("handles query parameters for public-resolved files", () => {
const result = getSrcPath("out.jpeg?w=200");
expect(result).toBe(buildPath("out/out.jpeg?w=200"));
});

it("returns the original input if the file is not found", () => {
const result = getSrcPath(
"https://cdn.nedis.com/images/products_high_res/TVRC2080BK_P30.JPG"
);
expect(result).toBe(
"https://cdn.nedis.com/images/products_high_res/TVRC2080BK_P30.JPG"
);
});

it("finds relative paths correctly", () => {
const outResult = getSrcPath("./out/out.jpeg");
const rootResult = getSrcPath("./root.jpeg");
expect(outResult).toBe(buildPath("out/out.jpeg"));
expect(rootResult).toBe(buildPath("root.jpeg"));
});
});
4 changes: 2 additions & 2 deletions packages/astro-imagetools/api/utils/getSrcset.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// @ts-check
import { cwd } from "../../utils/runtimeChecks.js";
import { getSrcPath } from "./getSrcPath";

export default async function getSrcset(src, breakpoints, format, options) {
options = {
Expand All @@ -23,7 +23,7 @@ export default async function getSrcset(src, breakpoints, format, options) {
const id = `${src}?${params.slice(1)}`;

if (process.env.npm_lifecycle_event !== "dev") {
const fullPath = cwd + id;
const fullPath = getSrcPath(id);

const { default: load } = await import("../../plugin/hooks/load.js");

Expand Down
2 changes: 2 additions & 0 deletions packages/astro-imagetools/integration/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ export default {
environment,
isSsrBuild,
projectBase,
publicDir: fileURLToPath(config.publicDir.href),
rootDir: fileURLToPath(config.root.href),
};

await fs.promises.writeFile(
Expand Down
3 changes: 2 additions & 1 deletion packages/astro-imagetools/plugin/hooks/load.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// @ts-check
import path from "node:path";
import objectHash from "object-hash";
import { getSrcPath } from "../../api/utils/getSrcPath.js";
import { getCachedBuffer } from "../utils/cache.js";
import { getAssetPath, getConfigOptions } from "../utils/shared.js";
import { cwd, sharp, supportedImageTypes } from "../../utils/runtimeChecks.js";
Expand Down Expand Up @@ -31,7 +32,7 @@ export default async function load(id) {

const { environment, projectBase, assetFileNames } = astroViteConfigs;

const src = id.startsWith(cwd) ? id : cwd + id;
const src = getSrcPath(id);

const config = Object.fromEntries(searchParams);

Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.