Skip to content

Frameworks

Each loader is a thin adapter over @truocloud/img — the same URL builder, so every framework emits byte-identical URLs and shares CDN cache entries.

Terminal window
npm install @truocloud/img-next
next.config.js
module.exports = {
images: {
loader: "custom",
loaderFile: "./node_modules/@truocloud/img-next/loader.js",
deviceSizes: [640, 828, 1200, 1600, 2048],
},
};
.env
NEXT_PUBLIC_TRUO_IMG_PID=acme

That is the whole setup — <Image> works unchanged.

deviceSizes is trimmed from the default eight for the reason described in the ladder.

Next only walks deviceSizes when the image has a sizes prop. Without one it emits a 1x/2x density pair around the declared width — which is fine, but it is not the responsive ladder, and it surprises people.

Terminal window
npm install @truocloud/img-nuxt
nuxt.config.ts
export default defineNuxtConfig({
modules: ["@nuxt/image"],
image: {
providers: {
truocloud: { provider: "@truocloud/img-nuxt", options: { pid: "acme" } },
},
provider: "truocloud",
screens: { xs: 640, sm: 828, md: 1200, lg: 1600, xl: 2048 },
},
});
<NuxtImg src="/uploads/photo.jpg" width="800" format="auto" />
Terminal window
npm install @truocloud/img-angular
import { provideTruoImageLoader } from "@truocloud/img-angular";
bootstrapApplication(AppComponent, {
providers: [provideTruoImageLoader("https://img.truo.cloud/i/acme")],
});
<img ngSrc="uploads/photo.jpg" width="800" height="600" priority />

The signature mirrors Angular’s own provideImageKitLoader, so swapping providers is a one-line change. Anything the directive does not model goes through loaderParams:

<img ngSrc="hero.jpg" width="1200" height="600"
[loaderParams]="{ transform: { fit: 'cover', gravity: 'attention' } }" />

Through unpic, which detects img.truo.cloud and transforms the URL for you:

import { Image } from "@unpic/react";
<Image src="https://img.truo.cloud/i/acme/uploads/photo.jpg" layout="constrained" width={800} height={600} />

A custom domain does not autodetect — /i/ is too generic a path to claim globally — so pass cdn="truocloud" explicitly if you use one.

Every loader defaults to format: "auto". If your images sit behind a third-party CDN that ignores Vary on images, pin it instead:

createTruoLoader({ pid: "acme", format: "webp" }) // Next
{ options: { pid: "acme", format: "webp" } } // Nuxt
provideTruoImageLoader(endpoint, { format: "webp" }) // Angular

The reasoning is in format negotiation.