@monkeyplus/flow 6.0.8 → 6.0.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -10,13 +10,17 @@ import { resetFlowImageRuntimeState } from "./runtime/server.mjs";
10
10
  function withoutTrailingSlash(value) {
11
11
  return value.replace(/\/+$/, "");
12
12
  }
13
- function resolveStrapiDomains(flowConfig, dirImages) {
13
+ function resolveStrapiUrl(flowConfig) {
14
14
  const strapi = flowConfig.strapi;
15
- if (!strapi || typeof strapi.url !== "string" || !strapi.url) {
15
+ return typeof strapi?.url === "string" && strapi.url ? withoutTrailingSlash(strapi.url) : void 0;
16
+ }
17
+ function resolveStrapiDomains(flowConfig, dirImages) {
18
+ const strapiUrl = resolveStrapiUrl(flowConfig);
19
+ if (!strapiUrl) {
16
20
  return {};
17
21
  }
18
22
  try {
19
- const url = new URL(strapi.url);
23
+ const url = new URL(strapiUrl);
20
24
  const target = dirImages;
21
25
  const values = /* @__PURE__ */ new Set([
22
26
  withoutTrailingSlash(url.origin),
@@ -79,6 +83,7 @@ export default defineFlowModule({
79
83
  presets: {}
80
84
  },
81
85
  setup(options, context) {
86
+ const strapiURL = resolveStrapiUrl(context.flowConfig);
82
87
  const resolvedDomains = {
83
88
  ...resolveStrapiDomains(context.flowConfig, options.dirImages),
84
89
  ...options.domains || {}
@@ -97,6 +102,7 @@ export default defineFlowModule({
97
102
  dirRenames: renameDir,
98
103
  dirFiles: options.dirFiles,
99
104
  buildBatchSize: options.buildBatchSize,
105
+ strapiURL,
100
106
  publicDir,
101
107
  outputDir: resolve(context.projectRoot, ".output/public"),
102
108
  generatedManifestPath,
@@ -1,6 +1,7 @@
1
1
  import type { FlowImageOptions, FlowImagesState, GeneratedImageEntry, GetImageFunction } from './types.ts';
2
2
  export declare function createImageResolver(imagesOptions: FlowImageOptions, stateImages: FlowImagesState, runtime?: {
3
3
  generateOutput?: boolean;
4
+ strapiURL?: string;
4
5
  onGenerate?: (image: GeneratedImageEntry) => void;
5
6
  }): {
6
7
  getImage: GetImageFunction;
@@ -1,5 +1,6 @@
1
1
  import { encodeParam, encodePath, joinURL } from "ufo";
2
2
  import { getNormalName, getPreset, guessExt, parseSize } from "./helpers.mjs";
3
+ const STRAPI_SOURCE_PREFIX = "strapi:";
3
4
  const modifierKeyMap = {
4
5
  background: "b",
5
6
  fit: "fit",
@@ -30,6 +31,18 @@ function resolveIpxUrl(src, modifiers = {}, baseURL = "/_ipx") {
30
31
  function isRemoteUrl(value) {
31
32
  return value.startsWith("http://") || value.startsWith("https://");
32
33
  }
34
+ function isStrapiSource(value) {
35
+ return value.startsWith(STRAPI_SOURCE_PREFIX);
36
+ }
37
+ function withLeadingSlash(value) {
38
+ return value.startsWith("/") ? value : `/${value}`;
39
+ }
40
+ function withoutTrailingSlash(value) {
41
+ return value.replace(/\/+$/, "");
42
+ }
43
+ function getStrapiSourcePath(value) {
44
+ return withLeadingSlash(value.slice(STRAPI_SOURCE_PREFIX.length));
45
+ }
33
46
  function normalizeDirImages(dirImages) {
34
47
  return dirImages.replace(/^\/+/, "").split("/")[0] || "images";
35
48
  }
@@ -123,8 +136,14 @@ export function createImageResolver(imagesOptions, stateImages, runtime = {}) {
123
136
  url: input
124
137
  };
125
138
  }
126
- if (!input.startsWith("/") && !input.startsWith("https://") && !input.startsWith("http://")) {
127
- input = joinURL(imagesOptions.dirImages, input);
139
+ const isStrapi = isStrapiSource(input);
140
+ const logicalInput = isStrapi ? getStrapiSourcePath(input) : input;
141
+ let sourceInput = logicalInput;
142
+ if (isStrapi && runtime.strapiURL) {
143
+ sourceInput = `${withoutTrailingSlash(runtime.strapiURL)}${logicalInput}`;
144
+ }
145
+ if (!isStrapi && !sourceInput.startsWith("/") && !sourceInput.startsWith("https://") && !sourceInput.startsWith("http://")) {
146
+ sourceInput = joinURL(imagesOptions.dirImages, sourceInput);
128
147
  }
129
148
  const expectedFormat = resolvedOptions.modifiers?.format;
130
149
  if (resolvedOptions.modifiers?.width) {
@@ -133,18 +152,19 @@ export function createImageResolver(imagesOptions, stateImages, runtime = {}) {
133
152
  if (resolvedOptions.modifiers?.height) {
134
153
  resolvedOptions.modifiers.height = parseSize(resolvedOptions.modifiers.height);
135
154
  }
136
- const image = resolveIpxUrl(input, resolvedOptions.modifiers || {}, imagesOptions.baseURL || "/_ipx");
155
+ const image = resolveIpxUrl(sourceInput, resolvedOptions.modifiers || {}, imagesOptions.baseURL || "/_ipx");
137
156
  image.format = image.format || expectedFormat || "";
138
- image.src = input;
139
- image.ext = image.format && `.${image.format}` || guessExt(input);
140
- let baseDir = getBaseDir(input, imagesOptions.dirImages);
141
- const originalExt = guessExt(input);
142
- let renamedImage = stateImages.all[input]?.rename;
157
+ image.src = sourceInput;
158
+ image.ext = image.format && `.${image.format}` || guessExt(logicalInput);
159
+ let baseDir = isStrapi ? normalizeDirImages(imagesOptions.dirImages) : getBaseDir(sourceInput, imagesOptions.dirImages);
160
+ const originalExt = guessExt(logicalInput);
161
+ let renamedImage = stateImages.all[logicalInput]?.rename;
143
162
  if (!renamedImage && imagesOptions.domains) {
144
- renamedImage = resolveRemoteRename(input, imagesOptions.domains);
163
+ renamedImage = resolveRemoteRename(sourceInput, imagesOptions.domains);
145
164
  }
146
- const replacedPath = decodeURIComponent(resolveRenamePath(renamedImage || input, resolvedOptions.rename));
147
- if (isRemoteUrl(input) && replacedPath.startsWith("/")) {
165
+ const resolvedPathInput = renamedImage || (isStrapi ? joinURL(imagesOptions.dirImages, logicalInput.replace(/^\/+/, "")) : logicalInput);
166
+ const replacedPath = decodeURIComponent(resolveRenamePath(resolvedPathInput, resolvedOptions.rename));
167
+ if (!isStrapi && isRemoteUrl(sourceInput) && replacedPath.startsWith("/")) {
148
168
  baseDir = getBaseDir(replacedPath, imagesOptions.dirImages);
149
169
  }
150
170
  const modifierSegment = getModifierSegment(image.modifiers);
@@ -166,7 +186,7 @@ export function createImageResolver(imagesOptions, stateImages, runtime = {}) {
166
186
  }
167
187
  const src = runtime.generateOutput && image.generate ? image.generate : image.url;
168
188
  if (resolvedOptions._meta) {
169
- const meta = { ...stateImages.all[input] || { name: input, alt: void 0, title: void 0 } };
189
+ const meta = { ...stateImages.all[logicalInput] || { name: logicalInput, alt: void 0, title: void 0 } };
170
190
  if (!meta.alt) {
171
191
  meta.alt = getNormalName(meta.name);
172
192
  }
@@ -1,3 +1,5 @@
1
+ import type { FlowImageBootPayload } from '../../../src/runtime/boot.ts';
1
2
  import type { FlowImageRuntimeUtils, FlowImagesRuntimeConfig } from './types.ts';
3
+ export declare function getFlowImageBootPayload(config?: FlowImagesRuntimeConfig | undefined): FlowImageBootPayload | undefined;
2
4
  export declare function getFlowImageRuntimeUtils(config?: FlowImagesRuntimeConfig | undefined): FlowImageRuntimeUtils | undefined;
3
5
  export declare function resetFlowImageRuntimeState(): void;
@@ -28,6 +28,17 @@ function getFlowImagesRuntimeConfig() {
28
28
  return getEnvFlowImagesRuntimeConfig();
29
29
  }
30
30
  }
31
+ export function getFlowImageBootPayload(config = getFlowImagesRuntimeConfig()) {
32
+ if (!config) {
33
+ return void 0;
34
+ }
35
+ const renameSources = [config.dirRenames, config.publicDir].filter(Boolean);
36
+ return {
37
+ all: loadImageRenames(renameSources),
38
+ options: { ...config.options },
39
+ generateOutput: !!config.generate
40
+ };
41
+ }
31
42
  export function getFlowImageRuntimeUtils(config = getFlowImagesRuntimeConfig()) {
32
43
  if (!config) {
33
44
  return void 0;
@@ -44,6 +55,7 @@ export function getFlowImageRuntimeUtils(config = getFlowImagesRuntimeConfig())
44
55
  };
45
56
  const resolver = createImageResolver(config.options, images, {
46
57
  generateOutput: config.generate,
58
+ strapiURL: config.strapiURL,
47
59
  onGenerate(image) {
48
60
  if (!config.generatedManifestPath) {
49
61
  return;
@@ -63,6 +63,7 @@ export interface FlowImagesRuntimeConfig {
63
63
  dirRenames: string;
64
64
  dirFiles: string[];
65
65
  buildBatchSize?: number;
66
+ strapiURL?: string;
66
67
  publicDir: string;
67
68
  outputDir: string;
68
69
  generatedManifestPath: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@monkeyplus/flow",
3
- "version": "6.0.8",
3
+ "version": "6.0.10",
4
4
  "description": "@monkeyplus/flow package-first runtime with Vite, Nitro, Vue and a workspace playground.",
5
5
  "license": "MIT",
6
6
  "publishConfig": {
@@ -5,7 +5,7 @@ import bases from "virtual:flow/bases";
5
5
  import layouts from "virtual:flow/layouts";
6
6
  import templates from "virtual:flow/templates";
7
7
  import { createSSRApp, defineComponent, h } from "vue";
8
- import { getFlowImageRuntimeUtils } from "../../modules/images/runtime/server.mjs";
8
+ import { getFlowImageBootPayload, getFlowImageRuntimeUtils } from "../../modules/images/runtime/server.mjs";
9
9
  import { installFlowVuePlugins } from "../../src/runtime/vue";
10
10
  import { getUrl, getUrls } from "./pages.mjs";
11
11
  function escapeHtml(value) {
@@ -152,7 +152,8 @@ export async function renderDocument(page, clientAssets) {
152
152
  template: page.definition.view.template,
153
153
  title: fallbackTitle,
154
154
  locale: page.locale,
155
- mode
155
+ mode,
156
+ images: getFlowImageBootPayload()
156
157
  };
157
158
  const rendered = await renderBody(page);
158
159
  const body = stripVueFragmentMarkers(rendered.body);
@@ -1,4 +1,10 @@
1
+ import type { FlowImageMeta, FlowImageOptions } from '../../modules/images/runtime/types.ts';
1
2
  import type { FlowHydrationMode, FlowLocale } from './pages';
3
+ export interface FlowImageBootPayload {
4
+ all: Record<string, FlowImageMeta>;
5
+ options: FlowImageOptions;
6
+ generateOutput: boolean;
7
+ }
2
8
  export interface FlowBootPayload {
3
9
  path: string;
4
10
  bundle: string;
@@ -6,4 +12,5 @@ export interface FlowBootPayload {
6
12
  title: string;
7
13
  locale: FlowLocale;
8
14
  mode: FlowHydrationMode;
15
+ images?: FlowImageBootPayload;
9
16
  }
@@ -7,6 +7,7 @@ declare const _default: import("vue").DefineComponent<import("vue").ExtractPropT
7
7
  eWidth: (StringConstructor | NumberConstructor)[];
8
8
  eHeight: (StringConstructor | NumberConstructor)[];
9
9
  sync: BooleanConstructor;
10
+ strappi: BooleanConstructor;
10
11
  thumb: (StringConstructor | BooleanConstructor)[];
11
12
  thumbnail: {
12
13
  type: (StringConstructor | BooleanConstructor)[];
@@ -91,6 +92,7 @@ declare const _default: import("vue").DefineComponent<import("vue").ExtractPropT
91
92
  eWidth: (StringConstructor | NumberConstructor)[];
92
93
  eHeight: (StringConstructor | NumberConstructor)[];
93
94
  sync: BooleanConstructor;
95
+ strappi: BooleanConstructor;
94
96
  thumb: (StringConstructor | BooleanConstructor)[];
95
97
  thumbnail: {
96
98
  type: (StringConstructor | BooleanConstructor)[];
@@ -173,16 +175,17 @@ declare const _default: import("vue").DefineComponent<import("vue").ExtractPropT
173
175
  preset: string;
174
176
  modifiers: Record<string, any>;
175
177
  sizes: string | Record<string, any>;
178
+ background: string;
179
+ quality: string | number;
180
+ strappi: boolean;
176
181
  alt: string;
177
182
  referrerpolicy: string;
178
183
  usemap: string;
179
184
  longdesc: string;
180
185
  ismap: boolean;
181
186
  loading: string;
182
- quality: string | number;
183
- background: string;
184
- title: string;
185
187
  sync: boolean;
186
188
  thumbnail: string | boolean;
189
+ title: string;
187
190
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
188
191
  export default _default;
@@ -32,6 +32,7 @@ export default defineComponent({
32
32
  eWidth: [String, Number],
33
33
  eHeight: [String, Number],
34
34
  sync: Boolean,
35
+ strappi: Boolean,
35
36
  thumb: [Boolean, String],
36
37
  thumbnail: { type: [Boolean, String], default: void 0 },
37
38
  format: { type: String, default: void 0 },
@@ -59,7 +60,7 @@ export default defineComponent({
59
60
  loading: { type: String, default: void 0 }
60
61
  },
61
62
  setup(props, { attrs }) {
62
- const { imageUtils, image, nImgAttrs, nModifiers, nOption } = useImage(props);
63
+ const { imageUtils, image, resolvedSrc, nImgAttrs, nModifiers, nOption } = useImage(props);
63
64
  const options = computed(() => imageUtils.getImageOptions?.() || {
64
65
  lazy: true,
65
66
  screens: {},
@@ -72,7 +73,7 @@ export default defineComponent({
72
73
  if (!props.sizes || !imageUtils.getImage?.getSizes) {
73
74
  return void 0;
74
75
  }
75
- return imageUtils.getImage.getSizes(props.src, {
76
+ return imageUtils.getImage.getSizes(resolvedSrc.value, {
76
77
  ...nOption.value,
77
78
  sizes: props.sizes,
78
79
  modifiers: {
@@ -97,13 +98,13 @@ export default defineComponent({
97
98
  });
98
99
  const nSrc = computed(() => {
99
100
  const normal = nSizes.value?.src || resolveImageSource(
100
- imageUtils.getImage?.(props.src, nModifiers.value, nOption.value),
101
- props.src
101
+ imageUtils.getImage?.(resolvedSrc.value, nModifiers.value, nOption.value),
102
+ resolvedSrc.value
102
103
  );
103
104
  const thumb = resolveThumbnailValue(props.thumbnail, props.thumb);
104
105
  const thumbnail = typeof thumb === "string" ? thumb : thumb ? resolveImageSource(
105
- imageUtils.getImage?.(props.src, { quality: 10, width: 60 }, nOption.value),
106
- props.src
106
+ imageUtils.getImage?.(resolvedSrc.value, { quality: 10, width: 60 }, nOption.value),
107
+ resolvedSrc.value
107
108
  ) : void 0;
108
109
  return {
109
110
  normal,
@@ -116,7 +117,7 @@ export default defineComponent({
116
117
  return h("img", {
117
118
  ...attrs,
118
119
  ...nAttrs.value,
119
- "src": isRuntimeLambda() ? props.src : compatibilityThumb || nSrc.value.normal,
120
+ "src": isRuntimeLambda() ? resolvedSrc.value : compatibilityThumb || nSrc.value.normal,
120
121
  "data-src": compatibilityThumb ? nSrc.value.normal : void 0,
121
122
  "data-thumb": compatibilityThumb,
122
123
  "alt": props.alt || image.value.alt,
@@ -124,7 +125,7 @@ export default defineComponent({
124
125
  "class": compatibilityThumb ? [attrs.class, "lazyload"] : attrs.class,
125
126
  "width": props.eWidth || nAttrs.value.width,
126
127
  "height": props.eHeight || nAttrs.value.height,
127
- "x-src": getLocalSource(props.src)
128
+ "x-src": getLocalSource(resolvedSrc.value)
128
129
  });
129
130
  };
130
131
  }
@@ -4,6 +4,7 @@ declare const _default: import("vue").DefineComponent<import("vue").ExtractPropT
4
4
  required: true;
5
5
  };
6
6
  rename: StringConstructor;
7
+ strappi: BooleanConstructor;
7
8
  thumb: (StringConstructor | BooleanConstructor)[];
8
9
  thumbnail: {
9
10
  type: (StringConstructor | BooleanConstructor)[];
@@ -93,6 +94,7 @@ declare const _default: import("vue").DefineComponent<import("vue").ExtractPropT
93
94
  required: true;
94
95
  };
95
96
  rename: StringConstructor;
97
+ strappi: BooleanConstructor;
96
98
  thumb: (StringConstructor | BooleanConstructor)[];
97
99
  thumbnail: {
98
100
  type: (StringConstructor | BooleanConstructor)[];
@@ -183,17 +185,18 @@ declare const _default: import("vue").DefineComponent<import("vue").ExtractPropT
183
185
  preset: string;
184
186
  modifiers: Record<string, any>;
185
187
  sizes: string | Record<string, any>;
188
+ background: string;
189
+ quality: string | number;
190
+ strappi: boolean;
186
191
  alt: string;
187
192
  referrerpolicy: string;
188
193
  usemap: string;
189
194
  longdesc: string;
190
195
  ismap: boolean;
191
196
  loading: string;
192
- quality: string | number;
193
- background: string;
194
- title: string;
195
197
  sync: boolean;
196
198
  thumbnail: string | boolean;
199
+ title: string;
197
200
  legacyFormat: string;
198
201
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
199
202
  export default _default;
@@ -20,6 +20,7 @@ export default defineComponent({
20
20
  required: true
21
21
  },
22
22
  rename: String,
23
+ strappi: Boolean,
23
24
  thumb: [Boolean, String],
24
25
  thumbnail: { type: [Boolean, String], default: void 0 },
25
26
  classImg: String,
@@ -52,7 +53,7 @@ export default defineComponent({
52
53
  legacyFormat: { type: String, default: null }
53
54
  },
54
55
  setup(props, { attrs }) {
55
- const { imageUtils, image, nImgAttrs, nModifiers, nOption } = useImage(props);
56
+ const { imageUtils, image, resolvedSrc, nImgAttrs, nModifiers, nOption } = useImage(props);
56
57
  const options = computed(() => imageUtils.getImageOptions?.() || {
57
58
  lazy: true,
58
59
  screens: {},
@@ -61,7 +62,7 @@ export default defineComponent({
61
62
  baseURL: "/_ipx",
62
63
  dirImages: "/images"
63
64
  });
64
- const originalFormat = () => getFileExtension(props.src);
65
+ const originalFormat = () => getFileExtension(resolvedSrc.value);
65
66
  const isTransparent = () => ["png", "webp", "gif"].includes(originalFormat());
66
67
  const nFormat = () => {
67
68
  if (props.format) {
@@ -84,11 +85,11 @@ export default defineComponent({
84
85
  };
85
86
  const nSources = computed(() => {
86
87
  if (nFormat() === "svg" || !imageUtils.getImage?.getSizes) {
87
- return [{ src: props.src, srcset: props.src }];
88
+ return [{ src: resolvedSrc.value, srcset: resolvedSrc.value }];
88
89
  }
89
90
  const formats = nLegacyFormat() !== nFormat() ? [nLegacyFormat(), nFormat()] : [nFormat()];
90
91
  return formats.map((format) => {
91
- const result = imageUtils.getImage.getSizes(props.src, {
92
+ const result = imageUtils.getImage.getSizes(resolvedSrc.value, {
92
93
  ...nOption.value,
93
94
  modifiers: {
94
95
  ...nModifiers.value,
@@ -112,11 +113,11 @@ export default defineComponent({
112
113
  if (!thumb) {
113
114
  return void 0;
114
115
  }
115
- const thumbnail = imageUtils.getImage?.(props.src, {
116
+ const thumbnail = imageUtils.getImage?.(resolvedSrc.value, {
116
117
  quality: 10,
117
118
  width: 60
118
119
  }, nOption.value);
119
- return typeof thumbnail === "string" ? thumbnail : props.src;
120
+ return typeof thumbnail === "string" ? thumbnail : resolvedSrc.value;
120
121
  });
121
122
  useLazySizes(() => !isRuntimeLambda() && !!nThumbnail.value);
122
123
  return () => {
@@ -124,15 +125,15 @@ export default defineComponent({
124
125
  return h("img", {
125
126
  ...attrs,
126
127
  ...nImgAttrs.value,
127
- "src": props.src,
128
+ "src": resolvedSrc.value,
128
129
  "alt": props.alt || image.value.alt,
129
130
  "title": props.title || image.value.title,
130
131
  "width": props.eWidth || nImgAttrs.value.width,
131
132
  "height": props.eHeight || nImgAttrs.value.height,
132
- "x-src": getLocalSource(props.src)
133
+ "x-src": getLocalSource(resolvedSrc.value)
133
134
  });
134
135
  }
135
- const primarySource = nSources.value[0] || { src: props.src, srcset: props.src };
136
+ const primarySource = nSources.value[0] || { src: resolvedSrc.value, srcset: resolvedSrc.value };
136
137
  const fallbackSource = nSources.value[1];
137
138
  const compatibilityThumb = nThumbnail.value;
138
139
  const sourceSrcsetProp = compatibilityThumb ? "data-srcset" : "srcset";
@@ -152,7 +153,7 @@ export default defineComponent({
152
153
  "width": props.eWidth || nImgAttrs.value.width,
153
154
  "height": props.eHeight || nImgAttrs.value.height,
154
155
  "class": compatibilityThumb ? [attrs.class, "lazyload", props.classImg] : [attrs.class, props.classImg],
155
- "x-src": getLocalSource(props.src)
156
+ "x-src": getLocalSource(resolvedSrc.value)
156
157
  };
157
158
  if (options.value.lazy && !props.sync && !imgAttrs.loading) {
158
159
  imgAttrs.loading = "lazy";
@@ -1,4 +1,5 @@
1
1
  import type { FlowImageMeta, FlowImageOptions, GetImageFunction } from '../../../modules/images/runtime/types.ts';
2
+ import type { FlowBootPayload } from '../boot.ts';
2
3
  export interface InjectedImageUtils {
3
4
  getImage?: GetImageFunction;
4
5
  getImageMeta?: (src: string) => FlowImageMeta | undefined;
@@ -6,9 +7,11 @@ export interface InjectedImageUtils {
6
7
  }
7
8
  export declare function useInjectedImageUtils(): InjectedImageUtils;
8
9
  export declare function useLazySizes(enabled: () => unknown): void;
10
+ export declare function createBootImageUtils(boot?: FlowBootPayload): InjectedImageUtils;
9
11
  export declare function useImage(props: Record<string, any>): {
10
12
  imageUtils: InjectedImageUtils;
11
13
  image: import("vue").ComputedRef<FlowImageMeta>;
14
+ resolvedSrc: import("vue").ComputedRef<string>;
12
15
  nImgAttrs: import("vue").ComputedRef<{
13
16
  width: number | undefined;
14
17
  height: number | undefined;
@@ -1,6 +1,6 @@
1
- import { computed, inject } from "vue";
2
- import { watchEffect } from "vue";
1
+ import { computed, inject, watchEffect } from "vue";
3
2
  import { getNormalName, parseSize } from "../../../modules/images/runtime/helpers.mjs";
3
+ import { createImageResolver } from "../../../modules/images/runtime/image.mjs";
4
4
  let lazySizesLoadPromise;
5
5
  function loadLazySizes() {
6
6
  if (lazySizesLoadPromise) {
@@ -20,8 +20,43 @@ export function useLazySizes(enabled) {
20
20
  void loadLazySizes();
21
21
  });
22
22
  }
23
+ function isAbsoluteImageUrl(value) {
24
+ return /^https?:\/\//i.test(value) || value.startsWith("data:");
25
+ }
26
+ function withLeadingSlash(value) {
27
+ return value.startsWith("/") ? value : `/${value}`;
28
+ }
29
+ function resolveStrapiImageSrc(src, strappi) {
30
+ if (!strappi || !src || isAbsoluteImageUrl(src)) {
31
+ return src;
32
+ }
33
+ return `strapi:${withLeadingSlash(src)}`;
34
+ }
35
+ export function createBootImageUtils(boot) {
36
+ const snapshot = boot?.images;
37
+ if (!snapshot) {
38
+ return {};
39
+ }
40
+ const stateImages = {
41
+ all: snapshot.all || {},
42
+ generate: {}
43
+ };
44
+ const resolver = createImageResolver(snapshot.options, stateImages, {
45
+ generateOutput: snapshot.generateOutput
46
+ });
47
+ return {
48
+ getImage: resolver.getImage,
49
+ getImageMeta(src) {
50
+ return stateImages.all[src];
51
+ },
52
+ getImageOptions() {
53
+ return { ...snapshot.options };
54
+ }
55
+ };
56
+ }
23
57
  export function useImage(props) {
24
58
  const imageUtils = useInjectedImageUtils();
59
+ const resolvedSrc = computed(() => resolveStrapiImageSrc(props.src, props.strappi));
25
60
  const nImgAttrs = computed(() => ({
26
61
  width: parseSize(props.width),
27
62
  height: parseSize(props.height),
@@ -48,7 +83,7 @@ export function useImage(props) {
48
83
  }));
49
84
  const image = computed(() => {
50
85
  const meta = {
51
- ...imageUtils.getImageMeta?.(props.src) || { name: props.src }
86
+ ...imageUtils.getImageMeta?.(resolvedSrc.value) || { name: resolvedSrc.value }
52
87
  };
53
88
  if (!meta.alt) {
54
89
  meta.alt = getNormalName(meta.name);
@@ -61,6 +96,7 @@ export function useImage(props) {
61
96
  return {
62
97
  imageUtils,
63
98
  image,
99
+ resolvedSrc,
64
100
  nImgAttrs,
65
101
  nModifiers,
66
102
  nOption
@@ -1,5 +1,6 @@
1
1
  import islands from "virtual:flow/islands";
2
2
  import { createSSRApp } from "vue";
3
+ import { createBootImageUtils } from "./components/image-shared.mjs";
3
4
  import { getClientHead } from "./head.mjs";
4
5
  import { installFlowVuePlugins } from "./vue.mjs";
5
6
  function parseIslandProps(value) {
@@ -39,7 +40,9 @@ async function hydrateIsland(element, boot) {
39
40
  return;
40
41
  }
41
42
  const app = createSSRApp(mod.default, props);
43
+ const imageUtils = createBootImageUtils(boot);
42
44
  app.use(getClientHead());
45
+ app.provide("utils", imageUtils);
43
46
  installFlowVuePlugins(app);
44
47
  app.mount(element);
45
48
  element.dataset.flowIslandHydrated = "true";