Skip to content

@W-20784635@ Support adding base paths to shopper facing URLs#3615

Merged
vcua-mobify merged 11 commits intofeature/productize-path-prefixesfrom
vc/app-base-path
Jan 30, 2026
Merged

@W-20784635@ Support adding base paths to shopper facing URLs#3615
vcua-mobify merged 11 commits intofeature/productize-path-prefixesfrom
vc/app-base-path

Conversation

@vcua-mobify
Copy link
Contributor

@vcua-mobify vcua-mobify commented Jan 28, 2026

Previously, the base path feature only applied to routes defined in the Express app (ie. routes defined in ssr.js, proxies, bundle assets).

This PR expands the base path feature by allowing projects to also add the base path to routes defined in React Router (ie. routes defined in routes.jsx, such as /category or /product).

This PR adds a feature toggle so that projects can decide whether the base path only applies to Express routes or both Express and React Router routes.

Note: the same base path used by Express routes will be applied to React Router routes. This implementation intentionally does not provide a mechanism for setting the React Router routes to have a different base path from Express routes.
You cannot have www.example.com/shop/category/.. (React Router route) if you have www.example.com/store/mobify/proxy/.. (Express route)

Testing the feature:
Base paths on both Express and React Router routes

  1. Set a base path in the config file (config.ssrParameters.envBasePath) (You can set this to /test because our default SLAS client is already configured to accept redirect_uris with /test)
  2. Set config.app.showBasePath to true (this is the feature toggle that tells the app to include base paths to React Router routes)
  3. Start the app
  4. Verify that pages load and that links are working (ensure we are getting the correct site id and locale into SCAPI calls, etc.)
  5. Verify that page urls and links include the base path (check the product tile, navigation, etc.)
  6. Verify that locale changing works

Base paths on only Express routes. No base path on React Router routes

  1. Disable the feature toggle and restart your app
  2. Verify that the base path is still added to express routes (ie. /mobify/proxy or /callback)
  3. Verify that page urls and links do not include the base path (check the product tile, navigation, etc.)
  4. Verify that locale changing works

Generator

  1. Generate the app
  2. Verify the generated app's config has the showBasePath field
  3. Verify the app starts up

@cc-prodsec
Copy link
Collaborator

cc-prodsec commented Jan 28, 2026

Snyk checks have passed. No issues have been found so far.

Status Scanner Critical High Medium Low Total (0)
Open Source Security 0 0 0 0 0 issues
Licenses 0 0 0 0 0 issues

💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse.

Copy link
Contributor Author

@vcua-mobify vcua-mobify left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added comments to explain and highlight some of the key changes in this PR

return (
<ServerContext.Provider value={{req, res}}>
<Router location={location} context={routerContext}>
<Router location={location} context={routerContext} basename={routerBasename}>
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding the basename prop here and in main.jsx automatically adds the base path to almost all URLs.
This includes links that use the Link component and places where we use history to navigate.

This basename prop does not apply to places where we update window.location directly, hence other changes in this PR.

// Add base path for locale selection URLs since we update window.location directly
// bypassing React Router
const basePath = getRouterBasePath()
return basePath ? `${basePath}${newUrl}` : newUrl
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As noted in the comments, this function is used to generate links that update windows.location directly. Since this bypasses react router, we need to manually apply the base path.

const basePath = getRouterBasePath()
if (basePath && pathname.startsWith(basePath)) {
pathname = pathname.substring(basePath.length)
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code handles removing the base path from the path before we start doing pattern matching for multi-site.

I think this is a simple way to ensure adding a router base path does not break our existing multi-site implementation but I'm open to suggestions for other approaches.

site: 'path',
locale: 'path',
showDefaults: true,
showBasePath: false,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New config property that, if not defined, will default to false so this should not break existing project configs.

export const getRouterBasePath = () => {
const config = getConfig()
const showBasePath = config?.app?.url?.showBasePath === true
return showBasePath ? getEnvBasePath() : ''
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This utility function exists to support the feature toggle since calling getEnvBasePath directly bypasses the toggle.

I opted to separate this from getEnvBasePath to support cases where a project wants the base path only on express routes. For example, suppose a project wants to have www.example.com/emea/mobify/proxy/... (envBasePath: /emea) along with shopper facing urls like www.example.com/gb/category/.. or www.example.com/fr/product/.. where gb and fr are site aliases in our existing multi-site implementation and /emea is a base path for a target MRT environment. Without this separation, shopper facing urls would be www.example.com/emea/gb/category/...

Note that to support the above scenario, projects would need a CDN to route requests with /emea, /gb, /fr to the same MRT environment.

@vcua-mobify vcua-mobify marked this pull request as ready for review January 28, 2026 22:04
@vcua-mobify vcua-mobify requested a review from a team as a code owner January 28, 2026 22:04
/* eslint-disable @typescript-eslint/no-var-requires */
const {
getParamsFromPath: getParamsFromPathFresh
} = require('@salesforce/retail-react-app/app/utils/site-utils')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to re-import this file? How come other tests does not have to do this?

const basePath = '/test-base'
// Re-require modules to get fresh imports with mocks
// This is because these modules are first imported at module load time before mocks were set
// and have references to the original functions.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this is true because we are mocking getConfig as usual within other tests, what makes this one different?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comment with the rest of require statement


// Add base path for locale selection URLs since we update window.location directly
// bypassing React Router
const basePath = getRouterBasePath()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we call this func twice, can we call it at the top and use for bother removal and re-add here

@vcua-mobify vcua-mobify requested a review from alexvuong January 30, 2026 20:03
location: {
...location,
search: ''
href={`${appOrigin}${getRouterBasePath()}${getPathWithLocale(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: please break this down to a variable

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!

@vcua-mobify vcua-mobify merged commit 23bfeba into feature/productize-path-prefixes Jan 30, 2026
42 checks passed
@vcua-mobify vcua-mobify deleted the vc/app-base-path branch January 30, 2026 21:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants