This Astro integration downloads Sanity File Assets to your project's public/ directory on build which makes these files available in your dist/ directory without the Sanity CDN.
First, install the package using your package manager, for example:
npm install astro-sanity-assetsThen, apply the integration to your Astro config file using the integrations property:
import { defineConfig } from "astro/config";
import downloadSanityAssets from "astro-sanity-assets";
export default defineConfig({
// ...
integrations: [
downloadSanityAssets({
// see Configuration section below
}),
],
});The configuration expects a Sanity client config as used for @sanity/client as well as the GROQ query to retrieve your files from Sanity and a directory name to use for your files inside the public/ folder.
import { defineConfig } from "astro/config";
import downloadSanityAssets from "astro-sanity-assets";
export default defineConfig({
// ...
integrations: [
downloadSanityAssets({
projectId: "<YOUR-PROJECT-ID>",
dataset: "<YOUR-DATASET-NAME>",
query: `*[_type == "download"].file.asset->`,
directory: "directory",
}),
],
});The plugin run on every Astro build, retrieve the list of files and will download them to public/<directory>. So in the example above all attachments from the file field in download documents will be downloaded to public/downloads and therefore land in the final dist/downloads folder.
If the specified directory does not exist in the public/ folder, the plugin will create the folder and delete it after the build, so that only the dist/ folder will contain the files after the build is done. The folder will not be deleted, if it already existed when the build was started or if you set the keepDirectory option to true.
Any GROQ query that will return an array of Sanity Asset objects as returned by the File field. The only required fields are assetId, extension and url. You may also use a totally different query and tweak the data by using the handler function.
If the file assets provide a sha1hash that matches the one of an already downloaded file, the file download will be skipped.
The files by default will be named <assetId>.<extension>.
Sometimes you may want to use a query that does not return Sanity Assets and therefore have to tweak the query result a bit. For example:
import { defineConfig } from "astro/config";
import downloadSanityAssets, { type FileAssetType } from "astro-sanity-assets";
export default defineConfig({
// ...
integrations: [
downloadSanityAssets<FileAssetType>({
projectId: "<YOUR-PROJECT-ID>",
dataset: "<YOUR-DATASET-NAME>",
query: `*[_type == "fileType" && mimeType == "video/mp4"]`,
directory: "videos",
handler: (file) =>
file.url && file.originalFilename
? {
url: file.url, // URL of the file to download
filename: file.originalFilename, // local filename
sha1hash: file.sha1hash, // sha1 hash of file
}
: undefined,
}),
],
});The handler function receives every item from the array returned by the query and must return an object containing the url to download and the local filename to use inside the directory. If the file should be skipped just return undefined or null.
If you provide a callback function to the mapContent option, you can edit the file contents before the file is written to disk. For example:
export default defineConfig({
// ...
integrations: [
downloadSanityAssets({
// ...other options
directory: "remote",
query: `*[_type == "client" && defined(logo)].logo.asset->`,
mapContent: (buffer) => {
const svg = buffer.toString("utf-8");
// replace all reds with white in the SVG
return Buffer.from(svg.replace("#f00", "#fff"), "utf-8");
},
}),
],
});You can use the local files however you like. Since they are downloaded at start of the build process they are available early on. For example, you could check if the file exists locally like so:
---
import fs from "fs";
import { resolve } from "path";
import type { SanityFileAsset } from "@types/sanity.types";
interface Props {
title: string;
file: SanityFileAsset;
}
const { file } = Astro.props;
const src = `/downloads/${file.originalFilename}`;
const filePath = resolve("./public/downloads", file.originalFilename);
if (!fs.existsSync(filePath)) {
return null;
}
---
<a href={src}>{title}</a>Copyright © kolossal. Released under MIT License.