@salesforce/storefront-next-dev 1.1.0-alpha.0 → 1.1.0-alpha.2
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/dist/commands/create-storefront.js +37 -6
- package/dist/dependency-utils.js +56 -4
- package/dist/entry/server.d.ts +1 -1
- package/dist/entry/server.js +62 -21
- package/dist/entry/server.js.map +1 -1
- package/dist/index.d.ts +58 -27
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +107 -105
- package/dist/index.js.map +1 -1
- package/dist/logger.js +1 -1
- package/dist/manage-extensions.js +1 -1
- package/dist/mrt/ssr.mjs +48 -48
- package/dist/mrt/ssr.mjs.map +1 -1
- package/dist/mrt/streamingHandler.mjs +57 -57
- package/dist/mrt/streamingHandler.mjs.map +1 -1
- package/dist/server.js +74 -28
- package/package.json +10 -8
package/dist/index.js
CHANGED
|
@@ -5,7 +5,7 @@ import { createRequire } from "module";
|
|
|
5
5
|
import path$1, { dirname, join, relative, resolve as resolve$1 } from "path";
|
|
6
6
|
import { fileURLToPath } from "url";
|
|
7
7
|
import { parse } from "@babel/parser";
|
|
8
|
-
import {
|
|
8
|
+
import { isArrayPattern, isClassDeclaration, isExportSpecifier, isFunctionDeclaration, isIdentifier, isJSXAttribute, isJSXElement, isJSXFragment, isJSXIdentifier, isMemberExpression, isObjectPattern, isObjectProperty, isRestElement, isVariableDeclaration, jsxClosingElement, jsxClosingFragment, jsxElement, jsxFragment, jsxIdentifier, jsxOpeningElement, jsxOpeningFragment, jsxText } from "@babel/types";
|
|
9
9
|
import { generate } from "@babel/generator";
|
|
10
10
|
import traverseModule from "@babel/traverse";
|
|
11
11
|
import { existsSync, readFileSync, writeFileSync } from "fs";
|
|
@@ -15,6 +15,7 @@ import fs$1, { existsSync as existsSync$1, readFileSync as readFileSync$1 } from
|
|
|
15
15
|
import { deadCodeElimination, findReferencedIdentifiers } from "babel-dead-code-elimination";
|
|
16
16
|
import httpProxy from "http-proxy";
|
|
17
17
|
import { brotliDecompressSync, gunzipSync, inflateSync } from "zlib";
|
|
18
|
+
import { extractPrefixParamValues, stripPathPrefix } from "@salesforce/storefront-next-runtime/site-context";
|
|
18
19
|
|
|
19
20
|
//#region src/utils/logger.ts
|
|
20
21
|
const LEVEL_PRIORITY = {
|
|
@@ -368,7 +369,7 @@ const patchReactRouterPlugin = () => {
|
|
|
368
369
|
|
|
369
370
|
//#endregion
|
|
370
371
|
//#region src/extensibility/target-utils.ts
|
|
371
|
-
const traverse$
|
|
372
|
+
const traverse$1 = traverseModule.default || traverseModule;
|
|
372
373
|
const TARGET_COMPONENT_TAG = "UITarget";
|
|
373
374
|
const TARGET_PROVIDERS_TAG = "UITargetProviders";
|
|
374
375
|
const TARGET_ID_ATTRIBUTE = "targetId";
|
|
@@ -443,7 +444,7 @@ function runReplacementPass(ast, tagName, targetRegistry = null, contextProvider
|
|
|
443
444
|
if (replacedId) targetIdsReplaced.add(replacedId);
|
|
444
445
|
} else if (contextProviders) findAndReplaceProviders(pathToReplace, contextProviders);
|
|
445
446
|
};
|
|
446
|
-
traverse$
|
|
447
|
+
traverse$1(ast, {
|
|
447
448
|
VariableDeclaration(nodePath) {
|
|
448
449
|
const declarationPaths = nodePath.get("declarations");
|
|
449
450
|
const declarationsArray = Array.isArray(declarationPaths) ? declarationPaths : [declarationPaths];
|
|
@@ -496,7 +497,7 @@ function transformTargets(code, targetRegistry, contextProviders) {
|
|
|
496
497
|
});
|
|
497
498
|
if (TARGET_COMPONENT_JSX_RE.test(code)) {
|
|
498
499
|
const replacementImportStatements = buildReplacementImportStatements(runReplacementPass(ast, TARGET_COMPONENT_TAG, targetRegistry, null), targetRegistry);
|
|
499
|
-
traverse$
|
|
500
|
+
traverse$1(ast, { ImportDeclaration(nodePath) {
|
|
500
501
|
if (nodePath.node.source.value === "@/targets/ui-target") nodePath.replaceWith(jsxText(replacementImportStatements));
|
|
501
502
|
} });
|
|
502
503
|
}
|
|
@@ -504,7 +505,7 @@ function transformTargets(code, targetRegistry, contextProviders) {
|
|
|
504
505
|
const importStatements = /* @__PURE__ */ new Set();
|
|
505
506
|
for (const contextProvider of contextProviders) importStatements.add(`import ${contextProvider.componentName} from '@/${contextProvider.path.replace(".tsx", "")}';`);
|
|
506
507
|
const replacementImportStatements = Array.from(importStatements).join("\n");
|
|
507
|
-
traverse$
|
|
508
|
+
traverse$1(ast, { ImportDeclaration(nodePath) {
|
|
508
509
|
if (nodePath.node.source.value === "@/targets/ui-target-providers") nodePath.replaceWith(jsxText(replacementImportStatements));
|
|
509
510
|
} });
|
|
510
511
|
runReplacementPass(ast, TARGET_PROVIDERS_TAG, null, contextProviders);
|
|
@@ -607,7 +608,6 @@ function buildTargetRegistry(rootDir, options = {}) {
|
|
|
607
608
|
};
|
|
608
609
|
}
|
|
609
610
|
const TARGET_ID_PATTERN = /<UITarget[\s][^>]*targetId=["']([^"']+)["']/g;
|
|
610
|
-
const EXCLUDED_DIRS = new Set(["ui-target-dev-mode", "ui-target-smoke-test"]);
|
|
611
611
|
/**
|
|
612
612
|
* Recursively collect all UITarget IDs declared in template source files.
|
|
613
613
|
* Excludes extension directories so only "real" UITarget placements are counted.
|
|
@@ -619,7 +619,7 @@ function collectUITargetIds(sourceDir) {
|
|
|
619
619
|
for (const entry of entries) {
|
|
620
620
|
const fullPath = path$1.join(dir, entry.name);
|
|
621
621
|
if (entry.isDirectory()) {
|
|
622
|
-
if (entry.name === "extensions"
|
|
622
|
+
if (entry.name === "extensions") continue;
|
|
623
623
|
walk(fullPath);
|
|
624
624
|
} else if (entry.isFile() && /\.(tsx?|jsx?)$/.test(entry.name) && !/\.test\.(tsx?|jsx?)$/.test(entry.name)) {
|
|
625
625
|
const content = fs.readFileSync(fullPath, "utf-8");
|
|
@@ -670,7 +670,6 @@ function transformTargetPlaceholderPlugin() {
|
|
|
670
670
|
}
|
|
671
671
|
},
|
|
672
672
|
transform(code, id) {
|
|
673
|
-
if (process.env.VITE_UI_TARGET_DEV_MODE === "true") return null;
|
|
674
673
|
try {
|
|
675
674
|
const transformedCode = transformTargets(code, componentRegistry, contextProviders);
|
|
676
675
|
if (transformedCode) return {
|
|
@@ -1438,7 +1437,7 @@ export * from ${importPath};
|
|
|
1438
1437
|
export default _composed.default;
|
|
1439
1438
|
export const handleDataRequest = _composed.handleDataRequest;
|
|
1440
1439
|
export const handleError = _composed.handleError;
|
|
1441
|
-
export const
|
|
1440
|
+
export const instrumentations = _composed.instrumentations;
|
|
1442
1441
|
export const streamTimeout = _composed.streamTimeout;
|
|
1443
1442
|
`.trim();
|
|
1444
1443
|
}
|
|
@@ -1583,7 +1582,7 @@ const workspacePlugin = () => {
|
|
|
1583
1582
|
|
|
1584
1583
|
//#endregion
|
|
1585
1584
|
//#region src/plugins/componentLoaders.ts
|
|
1586
|
-
const traverse
|
|
1585
|
+
const traverse = traverseModule.default || traverseModule;
|
|
1587
1586
|
const generate$1 = generate.default || generate;
|
|
1588
1587
|
/**
|
|
1589
1588
|
* Names of exports to strip per environment.
|
|
@@ -1613,7 +1612,7 @@ function hasExportCandidate(code, names) {
|
|
|
1613
1612
|
*/
|
|
1614
1613
|
function hasComponentDecorator(ast) {
|
|
1615
1614
|
let found = false;
|
|
1616
|
-
traverse
|
|
1615
|
+
traverse(ast, { ClassDeclaration(path$2) {
|
|
1617
1616
|
const decorators = path$2.node.decorators;
|
|
1618
1617
|
if (!decorators) return;
|
|
1619
1618
|
for (const decorator of decorators) if (decorator.expression.type === "CallExpression" && isIdentifier(decorator.expression.callee) && decorator.expression.callee.name === "Component") {
|
|
@@ -1660,7 +1659,7 @@ function stripExports(code, exportsToStrip, preParsedAst) {
|
|
|
1660
1659
|
let changed = false;
|
|
1661
1660
|
const previouslyReferencedIdentifiers = findReferencedIdentifiers(ast);
|
|
1662
1661
|
const removedExportLocalNames = /* @__PURE__ */ new Set();
|
|
1663
|
-
traverse
|
|
1662
|
+
traverse(ast, { ExportNamedDeclaration(path$2) {
|
|
1664
1663
|
const { declaration, specifiers } = path$2.node;
|
|
1665
1664
|
if (declaration && isVariableDeclaration(declaration)) {
|
|
1666
1665
|
const remaining = declaration.declarations.filter((decl) => {
|
|
@@ -1718,7 +1717,7 @@ function stripExports(code, exportsToStrip, preParsedAst) {
|
|
|
1718
1717
|
}
|
|
1719
1718
|
}
|
|
1720
1719
|
} });
|
|
1721
|
-
if (changed) traverse
|
|
1720
|
+
if (changed) traverse(ast, { ExpressionStatement(path$2) {
|
|
1722
1721
|
if (!path$2.parentPath?.isProgram()) return;
|
|
1723
1722
|
if (path$2.node.expression.type === "AssignmentExpression") {
|
|
1724
1723
|
const left = path$2.node.expression.left;
|
|
@@ -2037,93 +2036,19 @@ function storefrontNextTargets(config = {}) {
|
|
|
2037
2036
|
|
|
2038
2037
|
//#endregion
|
|
2039
2038
|
//#region src/plugins/uiTargetDevMode.ts
|
|
2040
|
-
const traverse = traverseModule.default || traverseModule;
|
|
2041
|
-
const UI_TARGET_JSX_RE = /<UITarget[\s/>]/;
|
|
2042
2039
|
/**
|
|
2043
|
-
*
|
|
2040
|
+
* @deprecated This plugin has been removed. It was an internal-only debugging aid
|
|
2041
|
+
* that could cause build failures when extensions were trimmed. The export is kept
|
|
2042
|
+
* as a no-op for backward compatibility and will be removed in v2.
|
|
2044
2043
|
*
|
|
2045
|
-
*
|
|
2046
|
-
*
|
|
2044
|
+
* **Migration:** Remove any `uiTargetDevMode()` plugin from your `vite.config.ts`,
|
|
2045
|
+
* delete `vite-plugins/ui-target-dev-mode.ts` if it exists, and remove the plugin
|
|
2046
|
+
* from the Vite plugins array.
|
|
2047
2047
|
*
|
|
2048
|
-
* @
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
* </UITarget>
|
|
2053
|
-
*
|
|
2054
|
-
* // Transformed in DEV mode:
|
|
2055
|
-
* <UITargetDevMarker
|
|
2056
|
-
* targetId="pdp.loyalty.badge"
|
|
2057
|
-
* __file__="/src/components/product.tsx"
|
|
2058
|
-
* __hasChildren__={true}
|
|
2059
|
-
* >
|
|
2060
|
-
* <Widget />
|
|
2061
|
-
* </UITargetDevMarker>
|
|
2062
|
-
*/
|
|
2063
|
-
function uiTargetDevModePlugin(config = {}) {
|
|
2064
|
-
if (process.env.NODE_ENV === "production") return { name: "storefront-next:ui-target-dev-mode-noop" };
|
|
2065
|
-
if (!(config.enabled ?? process.env.VITE_UI_TARGET_DEV_MODE === "true")) return { name: "storefront-next:ui-target-dev-mode-disabled" };
|
|
2066
|
-
logger.info("🎯 UITarget Dev Mode enabled");
|
|
2067
|
-
if (config.filterCategory) logger.info(` Filtering to category: ${config.filterCategory} (build-time)`);
|
|
2068
|
-
return {
|
|
2069
|
-
name: "storefront-next:ui-target-dev-mode",
|
|
2070
|
-
enforce: "pre",
|
|
2071
|
-
transform(code, id) {
|
|
2072
|
-
if (!id.match(/\.(tsx|jsx)$/)) return null;
|
|
2073
|
-
if (id.includes("node_modules")) return null;
|
|
2074
|
-
if (id.includes("/targets/ui-target.tsx")) return null;
|
|
2075
|
-
if (!UI_TARGET_JSX_RE.test(code) || !code.includes("from '@/targets/ui-target'")) return null;
|
|
2076
|
-
try {
|
|
2077
|
-
const ast = parse(code, {
|
|
2078
|
-
sourceType: "module",
|
|
2079
|
-
plugins: [
|
|
2080
|
-
"typescript",
|
|
2081
|
-
"jsx",
|
|
2082
|
-
"decorators-legacy"
|
|
2083
|
-
]
|
|
2084
|
-
});
|
|
2085
|
-
let hasTransforms = false;
|
|
2086
|
-
const targetIds = [];
|
|
2087
|
-
traverse(ast, { JSXElement(path$2) {
|
|
2088
|
-
const openingElement = path$2.node.openingElement;
|
|
2089
|
-
if (!isJSXIdentifier(openingElement.name) || openingElement.name.name !== "UITarget") return;
|
|
2090
|
-
const targetIdAttr = openingElement.attributes.find((attr) => isJSXAttribute(attr) && isJSXIdentifier(attr.name) && attr.name.name === "targetId");
|
|
2091
|
-
if (!targetIdAttr) {
|
|
2092
|
-
logger.warn(`UITarget without targetId in ${id}`);
|
|
2093
|
-
return;
|
|
2094
|
-
}
|
|
2095
|
-
const targetId = isStringLiteral(targetIdAttr.value) ? targetIdAttr.value.value : null;
|
|
2096
|
-
if (!targetId) {
|
|
2097
|
-
logger.warn(`UITarget with non-string targetId in ${id}`);
|
|
2098
|
-
return;
|
|
2099
|
-
}
|
|
2100
|
-
if (config.filterCategory && !targetId.startsWith(`${config.filterCategory}.`)) return;
|
|
2101
|
-
const hasChildren = path$2.node.children.length > 0;
|
|
2102
|
-
openingElement.name = jsxIdentifier("UITargetDevMarker");
|
|
2103
|
-
if (path$2.node.closingElement) path$2.node.closingElement.name = jsxIdentifier("UITargetDevMarker");
|
|
2104
|
-
const hint = config.hintMap?.[targetId];
|
|
2105
|
-
openingElement.attributes.push(jsxAttribute(jsxIdentifier("__file__"), stringLiteral(id)), jsxAttribute(jsxIdentifier("__hasChildren__"), jsxExpressionContainer(booleanLiteral(hasChildren))), ...hint ? [jsxAttribute(jsxIdentifier("__hint__"), stringLiteral(hint))] : []);
|
|
2106
|
-
hasTransforms = true;
|
|
2107
|
-
targetIds.push(targetId);
|
|
2108
|
-
} });
|
|
2109
|
-
if (!hasTransforms) return null;
|
|
2110
|
-
const devMarkerImport = importDeclaration([importSpecifier(identifier("UITargetDevMarker"), identifier("UITargetDevMarker"))], stringLiteral("@/lib/ui-target-dev-mode/marker"));
|
|
2111
|
-
ast.program.body.unshift(devMarkerImport);
|
|
2112
|
-
const output = generate(ast, {
|
|
2113
|
-
retainLines: true,
|
|
2114
|
-
compact: false
|
|
2115
|
-
}, code);
|
|
2116
|
-
logger.debug(`Transformed ${targetIds.length} targets in ${id.split("/").pop()}`);
|
|
2117
|
-
return {
|
|
2118
|
-
code: output.code,
|
|
2119
|
-
map: output.map
|
|
2120
|
-
};
|
|
2121
|
-
} catch (error) {
|
|
2122
|
-
logger.error(`Failed to transform UITarget in ${id}:`, error);
|
|
2123
|
-
return null;
|
|
2124
|
-
}
|
|
2125
|
-
}
|
|
2126
|
-
};
|
|
2048
|
+
* @returns A no-op Vite plugin
|
|
2049
|
+
*/
|
|
2050
|
+
function uiTargetDevModePlugin(_config) {
|
|
2051
|
+
return { name: "storefront-next:ui-target-dev-mode-deprecated-noop" };
|
|
2127
2052
|
}
|
|
2128
2053
|
|
|
2129
2054
|
//#endregion
|
|
@@ -2228,6 +2153,82 @@ function escapeRegExp(str) {
|
|
|
2228
2153
|
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
2229
2154
|
}
|
|
2230
2155
|
/**
|
|
2156
|
+
* Resolve a captured prefix segment to its canonical-cased alias, case-insensitively.
|
|
2157
|
+
* Returns the matching entry from `aliases` (preserving the catalog's casing) so the value
|
|
2158
|
+
* forwarded to SFRA is always the expected canonical form, or `undefined` when the segment
|
|
2159
|
+
* isn't a known site/locale identifier.
|
|
2160
|
+
*/
|
|
2161
|
+
function matchAlias(segment, aliases) {
|
|
2162
|
+
if (segment === void 0) return void 0;
|
|
2163
|
+
const lower = segment.toLowerCase();
|
|
2164
|
+
return aliases.find((alias) => alias.toLowerCase() === lower);
|
|
2165
|
+
}
|
|
2166
|
+
/**
|
|
2167
|
+
* Rewrite an incoming proxy pathname to the SFRA `/s/{siteId}/{locale}/…` shape.
|
|
2168
|
+
*
|
|
2169
|
+
* This is the OOTB path transform. It is `url.prefix`-aware: when `urlPrefix` is set
|
|
2170
|
+
* it strips the configured prefix to recover the bare functional path AND reuses the
|
|
2171
|
+
* site/locale the path already carried — so a prefixed request like `/uk/cart` becomes
|
|
2172
|
+
* `/s/{siteId}/uk/cart` rather than the double-stacked `/s/{siteId}/{locale}/uk/cart`.
|
|
2173
|
+
*
|
|
2174
|
+
* It handles every standard prefix shape uniformly:
|
|
2175
|
+
* - no prefix (`''`/`/`): `/cart` → `/s/{site}/{locale}/cart`
|
|
2176
|
+
* - `/:localeId`: `/uk/cart` → `/s/{site}/uk/cart`
|
|
2177
|
+
* - `/:siteId/:localeId`: `/global/uk/cart` → `/s/global/uk/cart`
|
|
2178
|
+
*
|
|
2179
|
+
* Disambiguation: a captured prefix segment is only treated as a site/locale when it is
|
|
2180
|
+
* a known identifier (`siteAliases`/`localeAliases`). This stops a bare path like `/cart`
|
|
2181
|
+
* under a `/:localeId` prefix — which is structurally indistinguishable from a locale
|
|
2182
|
+
* home `/uk` — from being mis-stripped (here `cart` isn't a known locale, so the whole
|
|
2183
|
+
* path is treated as the bare functional path and decorated with the `defaultSiteId`/
|
|
2184
|
+
* `defaultLocale` fallbacks). When a prefix segment IS a known site/locale, that value is
|
|
2185
|
+
* passed straight through as the SFRA path segment; SFRA resolves both the BM site-path
|
|
2186
|
+
* alias (`uk`) and the canonical id (`en-GB`).
|
|
2187
|
+
*
|
|
2188
|
+
* Paths already in SFCC shape (`/s/…`, `/on/demandware.…`) are returned unchanged — the
|
|
2189
|
+
* caller is expected to skip them, but this stays defensive.
|
|
2190
|
+
*
|
|
2191
|
+
* Pure function (query string handled by the caller) so it's unit-testable in isolation.
|
|
2192
|
+
*
|
|
2193
|
+
* @param pathname - Incoming pathname on the proxy (no query string).
|
|
2194
|
+
* @param opts.defaultSiteId - Site to use when the path doesn't carry one.
|
|
2195
|
+
* @param opts.defaultLocale - Locale to use when the path doesn't carry one.
|
|
2196
|
+
* @param opts.urlPrefix - The storefront's `url.prefix` (e.g. `'/:siteId/:localeId'`).
|
|
2197
|
+
* @param opts.localeAliases - Known locale ids + aliases.
|
|
2198
|
+
* @param opts.siteAliases - Known site ids + aliases.
|
|
2199
|
+
*/
|
|
2200
|
+
function rewriteToSfraPath(pathname, opts) {
|
|
2201
|
+
const { defaultSiteId, defaultLocale, urlPrefix, localeAliases = [], siteAliases = [] } = opts;
|
|
2202
|
+
if (pathname.startsWith("/s/") || pathname.startsWith("/on/demandware.")) return pathname;
|
|
2203
|
+
let site = defaultSiteId;
|
|
2204
|
+
let locale = defaultLocale;
|
|
2205
|
+
let barePath = pathname;
|
|
2206
|
+
let localeFromPath = false;
|
|
2207
|
+
if (urlPrefix && urlPrefix !== "/") {
|
|
2208
|
+
const captured = extractPrefixParamValues({
|
|
2209
|
+
pathname,
|
|
2210
|
+
prefix: urlPrefix
|
|
2211
|
+
});
|
|
2212
|
+
const matchedSite = "siteId" in captured ? matchAlias(captured.siteId, siteAliases) : void 0;
|
|
2213
|
+
const matchedLocale = "localeId" in captured ? matchAlias(captured.localeId, localeAliases) : void 0;
|
|
2214
|
+
const siteOk = !("siteId" in captured) || matchedSite !== void 0;
|
|
2215
|
+
const localeOk = !("localeId" in captured) || matchedLocale !== void 0;
|
|
2216
|
+
if (Object.keys(captured).length > 0 && siteOk && localeOk) {
|
|
2217
|
+
if (matchedSite) site = matchedSite;
|
|
2218
|
+
if (matchedLocale) {
|
|
2219
|
+
locale = matchedLocale;
|
|
2220
|
+
localeFromPath = true;
|
|
2221
|
+
}
|
|
2222
|
+
barePath = stripPathPrefix({
|
|
2223
|
+
pathname,
|
|
2224
|
+
prefix: urlPrefix
|
|
2225
|
+
}) || "/";
|
|
2226
|
+
}
|
|
2227
|
+
}
|
|
2228
|
+
if (barePath === "/") return localeFromPath ? `/s/${site}/${locale}/` : `/s/${site}`;
|
|
2229
|
+
return `/s/${site}/${locale}${barePath}`;
|
|
2230
|
+
}
|
|
2231
|
+
/**
|
|
2231
2232
|
* Rewrite an SFCC Location header so the user stays on the proxy origin AND so
|
|
2232
2233
|
* any query params from the original request survive an SFCC redirect.
|
|
2233
2234
|
*
|
|
@@ -2303,7 +2304,8 @@ function hybridProxyPlugin(options) {
|
|
|
2303
2304
|
logger.debug(`Hybrid proxy routing rules: ${options.routingRules.slice(0, 100)}...`);
|
|
2304
2305
|
const locale = options.locale || "default";
|
|
2305
2306
|
const defaultSiteId = options.defaultSiteId;
|
|
2306
|
-
|
|
2307
|
+
const { urlPrefix, localeAliases, siteAliases, rewritePath } = options;
|
|
2308
|
+
logger.debug(urlPrefix ? `Hybrid proxy path transformation: url.prefix=${urlPrefix} → /s/${defaultSiteId}/{locale}/{bare path}` : `Hybrid proxy path transformation: / → /s/${defaultSiteId}, /path → /s/${defaultSiteId}/${locale}/path`);
|
|
2307
2309
|
const targetOriginPattern = new RegExp(escapeRegExp(options.targetOrigin), "g");
|
|
2308
2310
|
const proxy = httpProxy.createProxyServer({
|
|
2309
2311
|
changeOrigin: true,
|
|
@@ -2315,13 +2317,13 @@ function hybridProxyPlugin(options) {
|
|
|
2315
2317
|
const pathname = url.pathname;
|
|
2316
2318
|
if (!pathname.startsWith("/s/") && !pathname.startsWith("/on/demandware.")) {
|
|
2317
2319
|
const originalPath = proxyReq.path;
|
|
2318
|
-
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2320
|
+
proxyReq.path = `${rewritePath?.(pathname) ?? null ?? rewriteToSfraPath(pathname, {
|
|
2321
|
+
defaultSiteId,
|
|
2322
|
+
defaultLocale: locale,
|
|
2323
|
+
urlPrefix,
|
|
2324
|
+
localeAliases,
|
|
2325
|
+
siteAliases
|
|
2326
|
+
})}${url.search}`;
|
|
2325
2327
|
logger.debug(`Hybrid proxy path rewrite: ${originalPath} → ${proxyReq.path}`);
|
|
2326
2328
|
}
|
|
2327
2329
|
});
|