@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.
- package/modules/images/module.mjs +9 -3
- package/modules/images/runtime/image.d.ts +1 -0
- package/modules/images/runtime/image.mjs +32 -12
- package/modules/images/runtime/server.d.ts +2 -0
- package/modules/images/runtime/server.mjs +12 -0
- package/modules/images/runtime/types.d.ts +1 -0
- package/package.json +1 -1
- package/server/lib/render.mjs +3 -2
- package/src/runtime/boot.d.ts +7 -0
- package/src/runtime/components/MkImage.d.ts +6 -3
- package/src/runtime/components/MkImage.mjs +9 -8
- package/src/runtime/components/MkPicture.d.ts +6 -3
- package/src/runtime/components/MkPicture.mjs +11 -10
- package/src/runtime/components/image-shared.d.ts +3 -0
- package/src/runtime/components/image-shared.mjs +39 -3
- package/src/runtime/islands.mjs +3 -0
|
@@ -10,13 +10,17 @@ import { resetFlowImageRuntimeState } from "./runtime/server.mjs";
|
|
|
10
10
|
function withoutTrailingSlash(value) {
|
|
11
11
|
return value.replace(/\/+$/, "");
|
|
12
12
|
}
|
|
13
|
-
function
|
|
13
|
+
function resolveStrapiUrl(flowConfig) {
|
|
14
14
|
const strapi = flowConfig.strapi;
|
|
15
|
-
|
|
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(
|
|
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
|
-
|
|
127
|
-
|
|
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(
|
|
155
|
+
const image = resolveIpxUrl(sourceInput, resolvedOptions.modifiers || {}, imagesOptions.baseURL || "/_ipx");
|
|
137
156
|
image.format = image.format || expectedFormat || "";
|
|
138
|
-
image.src =
|
|
139
|
-
image.ext = image.format && `.${image.format}` || guessExt(
|
|
140
|
-
let baseDir = getBaseDir(
|
|
141
|
-
const originalExt = guessExt(
|
|
142
|
-
let renamedImage = stateImages.all[
|
|
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(
|
|
163
|
+
renamedImage = resolveRemoteRename(sourceInput, imagesOptions.domains);
|
|
145
164
|
}
|
|
146
|
-
const
|
|
147
|
-
|
|
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[
|
|
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;
|
package/package.json
CHANGED
package/server/lib/render.mjs
CHANGED
|
@@ -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);
|
package/src/runtime/boot.d.ts
CHANGED
|
@@ -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(
|
|
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?.(
|
|
101
|
-
|
|
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?.(
|
|
106
|
-
|
|
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() ?
|
|
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(
|
|
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(
|
|
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:
|
|
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(
|
|
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?.(
|
|
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 :
|
|
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":
|
|
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(
|
|
133
|
+
"x-src": getLocalSource(resolvedSrc.value)
|
|
133
134
|
});
|
|
134
135
|
}
|
|
135
|
-
const primarySource = nSources.value[0] || { 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(
|
|
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?.(
|
|
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
|
package/src/runtime/islands.mjs
CHANGED
|
@@ -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";
|