Jelajahi Sumber

feat(asset-server-plugin): Allow assetUrlPrefix to be a function

Closes #766
Michael Bromley 4 tahun lalu
induk
melakukan
10eb014301

+ 22 - 0
packages/asset-server-plugin/src/common.ts

@@ -0,0 +1,22 @@
+import { REQUEST_CONTEXT_KEY } from '@vendure/core/dist/common/constants';
+import { Request } from 'express';
+
+import { AssetServerOptions } from './types';
+
+export function getAssetUrlPrefixFn(options: AssetServerOptions) {
+    const { assetUrlPrefix, route } = options;
+    if (assetUrlPrefix == null) {
+        return (request: Request, identifier: string) =>
+            `${request.protocol}://${request.get('host')}/${route}/`;
+    }
+    if (typeof assetUrlPrefix === 'string') {
+        return (...args: any[]) => assetUrlPrefix;
+    }
+    if (typeof assetUrlPrefix === 'function') {
+        return (request: Request, identifier: string) => {
+            const ctx = (request as any)[REQUEST_CONTEXT_KEY];
+            return assetUrlPrefix(ctx, identifier);
+        };
+    }
+    throw new Error(`The assetUrlPrefix option was of an unexpected type: ${JSON.stringify(assetUrlPrefix)}`);
+}

+ 3 - 1
packages/asset-server-plugin/src/default-asset-storage-strategy-factory.ts

@@ -1,5 +1,6 @@
 import { Request } from 'express';
 
+import { getAssetUrlPrefixFn } from './common';
 import { LocalAssetStorageStrategy } from './local-asset-storage-strategy';
 import { AssetServerOptions } from './types';
 
@@ -8,11 +9,12 @@ import { AssetServerOptions } from './types';
  */
 export function defaultAssetStorageStrategyFactory(options: AssetServerOptions) {
     const { assetUrlPrefix, assetUploadDir, route } = options;
+    const prefixFn = getAssetUrlPrefixFn(options);
     const toAbsoluteUrlFn = (request: Request, identifier: string): string => {
         if (!identifier) {
             return '';
         }
-        const prefix = assetUrlPrefix || `${request.protocol}://${request.get('host')}/${route}/`;
+        const prefix = prefixFn(request, identifier);
         return identifier.startsWith(prefix) ? identifier : `${prefix}${identifier}`;
     };
     return new LocalAssetStorageStrategy(assetUploadDir, toAbsoluteUrlFn);

+ 3 - 1
packages/asset-server-plugin/src/s3-asset-storage-strategy.ts

@@ -3,6 +3,7 @@ import { Request } from 'express';
 import * as path from 'path';
 import { Readable, Stream } from 'stream';
 
+import { getAssetUrlPrefixFn } from './common';
 import { loggerCtx } from './constants';
 import { AssetServerOptions } from './types';
 
@@ -94,11 +95,12 @@ export interface S3Config {
 export function configureS3AssetStorage(s3Config: S3Config) {
     return (options: AssetServerOptions) => {
         const { assetUrlPrefix, route } = options;
+        const prefixFn = getAssetUrlPrefixFn(options);
         const toAbsoluteUrlFn = (request: Request, identifier: string): string => {
             if (!identifier) {
                 return '';
             }
-            const prefix = assetUrlPrefix || `${request.protocol}://${request.get('host')}/${route}/`;
+            const prefix = prefixFn(request, identifier);
             return identifier.startsWith(prefix) ? identifier : `${prefix}${identifier}`;
         };
         return new S3AssetStorageStrategy(s3Config, toAbsoluteUrlFn);

+ 5 - 3
packages/asset-server-plugin/src/types.ts

@@ -1,4 +1,4 @@
-import { AssetNamingStrategy, AssetStorageStrategy } from '@vendure/core';
+import { AssetNamingStrategy, AssetStorageStrategy, RequestContext } from '@vendure/core';
 
 /**
  * @description
@@ -56,13 +56,15 @@ export interface AssetServerOptions {
     assetUploadDir: string; // TODO: this is strategy-specific and should be moved out of the global options
     /**
      * @description
-     * The complete URL prefix of the asset files. For example, "https://demo.vendure.io/assets/"
+     * The complete URL prefix of the asset files. For example, "https://demo.vendure.io/assets/". A
+     * function can also be provided to handle more complex cases, such as serving multiple domains
+     * from a single server. In this case, the function should return a string url prefix.
      *
      * If not provided, the plugin will attempt to guess based off the incoming
      * request and the configured route. However, in all but the simplest cases,
      * this guess may not yield correct results.
      */
-    assetUrlPrefix?: string;
+    assetUrlPrefix?: string | ((ctx: RequestContext, identifier: string) => string);
     /**
      * @description
      * The max width in pixels of a generated preview image.