refactor: hardcode asset and upload path in builder (#4579)

We hardcoded asset base url in image loader.
Though locally different one is not resolved properly. So aligned local
and deployed image paths with /cgi/asset/ everywhere. Images are now
uploaded to public/cgi/asset locally.
This commit is contained in:
Bogdan Chadkin authored and GitHub committed 2024-12-13 23:18:22 +07:00
1 parent 4034b401c3
commit 302f5daa7f
11 files changed
+27 -92

No files matched your search

-4
View File
@@ -11,10 +11,6 @@ DEV_LOGIN=true
# Restrictions
MAX_ASSETS_PER_PROJECT=50
# relative to current working directory
FILE_UPLOAD_PATH="public/s/uploads"
ASSET_BASE_URL=/s/uploads/
POSTGREST_URL=http://localhost:3000
# JWT token, decode using jwt.io. Encoded with PGRST_JWT_SECRET from docker-compose.yml
POSTGREST_API_KEY="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImttZHBpeHpvcWlpcmJtcGRpcHB5Iiwicm9sZSI6ImFub24iLCJpYXQiOjE2NjYzMzY0MjgsImV4cCI6MTk4MTkxMjQyOH0.jjeYvTDrWP9pV7dfZr6fptualNQ3aR13kuPhvT25Sso"
+1
View File
@@ -8,4 +8,5 @@
/api/index.js.map
/api/_assets
/public/s/uploads
/public/cgi/asset
+7 -21
View File
@@ -3,7 +3,6 @@ import { ErrorBoundary, type FallbackProps } from "react-error-boundary";
import { useStore } from "@nanostores/react";
import type { Instances } from "@webstudio-is/sdk";
import {
type Params,
type Components,
coreMetas,
corePropsMetas,
@@ -49,6 +48,7 @@ import {
$isDesignMode,
$isContentMode,
subscribeModifierKeys,
assetBaseUrl,
} from "~/shared/nano-states";
import { useDragAndDrop } from "./shared/use-drag-drop";
import {
@@ -64,7 +64,6 @@ import { useMount } from "~/shared/hook-utils/use-mount";
import { subscribeInterceptedEvents } from "./interceptor";
import { subscribeCommands } from "~/canvas/shared/commands";
import { updateCollaborativeInstanceRect } from "./collaborative-instance";
import { $params } from "./stores";
import { initCanvasApi } from "~/shared/canvas-api";
import { subscribeFontLoadingDone } from "./shared/font-weight-support";
import { useDebounceEffect } from "~/shared/hook-utils/use-debounce-effect";
@@ -95,11 +94,7 @@ const FallbackComponent = ({ error, resetErrorBoundary }: FallbackProps) => {
);
};
const useElementsTree = (
components: Components,
instances: Instances,
params: Params
) => {
const useElementsTree = (components: Components, instances: Instances) => {
const page = useStore($selectedPage);
const isPreviewMode = useStore($isPreviewMode);
const rootInstanceId = page?.rootInstanceId ?? "";
@@ -119,7 +114,7 @@ const useElementsTree = (
<ReactSdkContext.Provider
value={{
renderer: isPreviewMode ? "preview" : "canvas",
assetBaseUrl: params.assetBaseUrl,
assetBaseUrl,
imageLoader: wsImageLoader,
resources: {},
}}
@@ -135,7 +130,7 @@ const useElementsTree = (
})}
</ReactSdkContext.Provider>
);
}, [params, instances, rootInstanceId, components, isPreviewMode]);
}, [instances, rootInstanceId, components, isPreviewMode]);
};
const DesignMode = () => {
@@ -215,11 +210,7 @@ const ContentEditMode = () => {
return null;
};
type CanvasProps = {
params: Params;
};
export const Canvas = ({ params }: CanvasProps) => {
export const Canvas = () => {
useCanvasStore();
const isDesignMode = useStore($isDesignMode);
const isContentMode = useStore($isContentMode);
@@ -254,11 +245,6 @@ export const Canvas = ({ params }: CanvasProps) => {
});
});
useMount(() => {
// required to compute asset and page props for rendering
$params.set(params);
});
useMount(initCanvasApi);
useLayoutEffect(() => {
@@ -299,7 +285,7 @@ export const Canvas = ({ params }: CanvasProps) => {
const components = useStore($registeredComponents);
const instances = useStore($instances);
const elements = useElementsTree(components, instances, params);
const elements = useElementsTree(components, instances);
const [isInitialized, setInitialized] = useState(false);
useEffect(() => {
@@ -312,7 +298,7 @@ export const Canvas = ({ params }: CanvasProps) => {
return (
<>
<GlobalStyles params={params} />
<GlobalStyles />
{/* catch all errors in rendered components */}
<ErrorBoundary FallbackComponent={FallbackComponent}>
{elements}
+7 -7
View File
@@ -14,7 +14,6 @@ import {
addGlobalRules,
createImageValueTransformer,
descendantComponent,
type Params,
rootComponent,
} from "@webstudio-is/react-sdk";
import {
@@ -33,9 +32,10 @@ import {
$selectedStyleState,
$styleSourceSelections,
$styles,
assetBaseUrl,
} from "~/shared/nano-states";
import { setDifference } from "~/shared/shim";
import { $ephemeralStyles, $params } from "../stores";
import { $ephemeralStyles } from "../stores";
import { canvasApi } from "~/shared/canvas-api";
import { $selectedInstance, $selectedPage } from "~/shared/awareness";
import { findAllEditableInstanceSelector } from "~/shared/instance-utils";
@@ -225,9 +225,9 @@ const subscribeContentEditModeHelperStyles = () => {
// keep stable transformValue in store
// to preserve cache in css engine
const $transformValue = computed([$assets, $params], (assets, params) =>
const $transformValue = computed($assets, (assets) =>
createImageValueTransformer(assets, {
assetBaseUrl: params?.assetBaseUrl ?? "",
assetBaseUrl,
})
);
@@ -428,7 +428,7 @@ export const manageDesignModeStyles = ({ signal }: { signal: AbortSignal }) => {
});
};
export const GlobalStyles = ({ params }: { params: Params }) => {
export const GlobalStyles = () => {
const assets = useStore($assets);
const metas = useStore($registeredComponentMetas);
@@ -436,10 +436,10 @@ export const GlobalStyles = ({ params }: { params: Params }) => {
fontsAndDefaultsSheet.clear();
addGlobalRules(fontsAndDefaultsSheet, {
assets,
assetBaseUrl: params.assetBaseUrl,
assetBaseUrl,
});
fontsAndDefaultsSheet.render();
}, [assets, params.assetBaseUrl]);
}, [assets]);
useLayoutEffect(() => {
presetSheet.clear();
-3
View File
@@ -1,7 +1,4 @@
import { atom } from "nanostores";
import type { StyleDecl } from "@webstudio-is/sdk";
import type { Params } from "@webstudio-is/react-sdk";
export const $ephemeralStyles = atom<Array<StyleDecl>>([]);
export const $params = atom<undefined | Params>();
-16
View File
@@ -23,22 +23,6 @@ const env = {
// Assets
MAX_UPLOAD_SIZE: process.env.MAX_UPLOAD_SIZE,
MAX_ASSETS_PER_PROJECT: process.env.MAX_ASSETS_PER_PROJECT,
/**
* Base url or base path for any asset with ending slash.
* Possible values are
* /s/uploads/
* /cgi/asset/
* https://assets-dev.webstudio.is/
* https://assets.webstudio.is/
*/
ASSET_BASE_URL:
process.env.ASSET_BASE_URL ??
process.env.ASSET_CDN_URL ??
process.env.ASSET_PUBLIC_PATH ??
"/cgi/asset/",
// Local assets
FILE_UPLOAD_PATH: process.env.FILE_UPLOAD_PATH,
// Remote assets
S3_ENDPOINT: process.env.S3_ENDPOINT,
+2 -11
View File
@@ -1,9 +1,6 @@
import { lazy } from "react";
import { type LoaderFunctionArgs } from "@remix-run/server-runtime";
import { useLoaderData } from "@remix-run/react";
import type { Params } from "@webstudio-is/react-sdk";
import { Body } from "@webstudio-is/sdk-components-react-remix";
import env from "~/env/env.server";
import { isCanvas } from "~/shared/router-utils";
import { ClientOnly } from "~/shared/client-only";
export { ErrorBoundary } from "~/shared/error/error-boundary";
@@ -14,12 +11,7 @@ export const loader = async ({ request }: LoaderFunctionArgs) => {
status: 404,
});
}
const params: Params = {
assetBaseUrl: env.ASSET_BASE_URL,
};
return { params };
return {};
};
const Canvas = lazy(async () => {
@@ -28,10 +20,9 @@ const Canvas = lazy(async () => {
});
const CanvasRoute = () => {
const { params } = useLoaderData<typeof loader>();
return (
<ClientOnly fallback={<Body />}>
<Canvas params={params} />
<Canvas />
</ClientOnly>
);
};
+1 -4
View File
@@ -6,6 +6,7 @@ import type { LoaderFunctionArgs } from "@remix-run/server-runtime";
import { wsImageLoader } from "@webstudio-is/image";
import env from "~/env/env.server";
import { getImageNameAndType } from "~/builder/shared/assets/asset-utils";
import { fileUploadPath } from "~/shared/asset-client";
const ImageParams = z.object({
width: z.string().transform((value) => Math.round(parseFloat(value))),
@@ -101,14 +102,10 @@ export const loader = async ({ request }: LoaderFunctionArgs) => {
return responseWHeaders;
}
if (env.FILE_UPLOAD_PATH === undefined) {
throw Error("FILE_UPLOAD_PATH is not provided");
}
// support absolute urls locally
if (URL.canParse(name)) {
return fetch(name);
}
const fileUploadPath = env.FILE_UPLOAD_PATH;
const filePath = join(process.cwd(), fileUploadPath, name);
if (existsSync(filePath) === false) {
+2 -1
View File
@@ -6,6 +6,8 @@ import {
} from "@webstudio-is/asset-uploader/index.server";
import env from "~/env/env.server";
export const fileUploadPath = "public/cgi/asset";
export const createAssetClient = () => {
const maxUploadSize = MaxSize.parse(env.MAX_UPLOAD_SIZE);
if (
@@ -25,7 +27,6 @@ export const createAssetClient = () => {
maxUploadSize,
});
} else {
const fileUploadPath = env.FILE_UPLOAD_PATH ?? "public/s/uploads";
return createFsClient({
maxUploadSize,
fileDirectory: path.join(process.cwd(), fileUploadPath),
@@ -15,7 +15,6 @@ import {
} from "./props";
import { $pages } from "./pages";
import { $assets, $dataSources, $props, $resources } from "./misc";
import { $params } from "~/canvas/stores";
import { $dataSourceVariables, $resourceValues } from "./variables";
import { $awareness } from "../awareness";
@@ -206,11 +205,10 @@ test("generate action prop callbacks", () => {
cleanStores($propValuesByInstanceSelector);
});
test("resolve asset prop values when params is provided", () => {
test("resolve asset prop values", () => {
setBoxInstance("box");
selectPageRoot("box");
$dataSources.set(new Map());
$params.set(undefined);
$assets.set(
toMap([
{
@@ -237,29 +235,21 @@ test("resolve asset prop values when params is provided", () => {
},
])
);
expect(
$propValuesByInstanceSelector.get().get(JSON.stringify(["box"]))
).toEqual(new Map());
$params.set({
assetBaseUrl: "/asset/",
});
expect(
$propValuesByInstanceSelector.get().get(JSON.stringify(["box"]))
).toEqual(
new Map<string, unknown>([
["$webstudio$canvasOnly$assetId", "assetId"],
["myAsset", "/asset/my-file.jpg"],
["myAsset", "/cgi/asset/my-file.jpg"],
])
);
cleanStores($propValuesByInstanceSelector);
});
test("resolve page prop values when params is provided", () => {
test("resolve page prop values", () => {
setBoxInstance("box");
selectPageRoot("box");
$params.set(undefined);
$dataSources.set(new Map());
$props.set(
toMap([
@@ -272,13 +262,6 @@ test("resolve page prop values when params is provided", () => {
},
])
);
expect(
$propValuesByInstanceSelector.get().get(JSON.stringify(["box"]))
).toEqual(new Map());
$params.set({
assetBaseUrl: "/asset/",
});
expect(
$propValuesByInstanceSelector.get().get(JSON.stringify(["box"]))
).toEqual(new Map<string, unknown>([["myPage", "/"]]));
+4 -5
View File
@@ -37,7 +37,6 @@ import {
} from "./misc";
import { $pages } from "./pages";
import type { InstanceSelector } from "../tree-utils";
import { $params } from "~/canvas/stores";
import { restResourcesLoader } from "../router-utils";
import {
$dataSourceVariables,
@@ -49,6 +48,8 @@ import { uploadingFileDataToAsset } from "~/builder/shared/assets/asset-utils";
import { fetch } from "~/shared/fetch.client";
import { $selectedPage, getInstanceKey } from "../awareness";
export const assetBaseUrl = "/cgi/asset/";
export const getIndexedInstanceId = (
instanceId: Instance["id"],
index: number
@@ -291,7 +292,6 @@ export const $propValuesByInstanceSelector = computed(
$props,
$selectedPage,
$unscopedVariableValues,
$params,
$pages,
$assets,
$uploadingFilesDataStore,
@@ -301,7 +301,6 @@ export const $propValuesByInstanceSelector = computed(
props,
page,
unscopedVariableValues,
params,
pages,
assets,
uploadingFilesDataStore
@@ -311,7 +310,7 @@ export const $propValuesByInstanceSelector = computed(
let propsList = Array.from(props.values());
// ignore asset and page props when params is not provided
if (params && pages) {
if (pages) {
const uploadingImageAssets = uploadingFilesDataStore
.map(uploadingFileDataToAsset)
.filter(<T>(value: T): value is NonNullable<T> => value !== undefined)
@@ -320,7 +319,7 @@ export const $propValuesByInstanceSelector = computed(
// use whole props list to let access hash props from other pages and instances
propsList = normalizeProps({
props: propsList,
assetBaseUrl: params.assetBaseUrl,
assetBaseUrl,
assets,
uploadingImageAssets,
pages,