Skip to content

Commit 9857f47

Browse files
lbwexleramcclain
andauthored
Add webpack dev server proxy to Grails backend (#63)
Closes #62 Companion [PR in hoist-react](xh/hoist-react#4313) for `WebSocketService` compatibility (merged in xh/hoist-react@708b904) ## Test plan - [ ] Start toolbox with `yarn start` — verify startup log shows proxy target, client apps load, API calls succeed through `/api/...`, no CORS errors - [ ] Check Network tab shows same-origin requests to `localhost:3000/api/...` - [ ] Verify deep client routes (e.g. `/app/grids`) still work via `historyApiFallback` - [ ] Test with explicit `baseUrl: '//localhost:8080/'` override to confirm old behavior still works 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Anselm McClain <atm@xh.io>
1 parent 274d127 commit 9857f47

2 files changed

Lines changed: 29 additions & 2 deletions

File tree

CHANGELOG.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,17 @@
11
# Changelog
22

3+
## v12.0.0 - 2026-03-31
4+
5+
### 💥 Breaking Changes - requires hoist-react v83.0.2 or higher.
6+
7+
* The webpack dev server now proxies API requests to the Grails backend, serving client resources
8+
and API responses from the same port. The default `baseUrl` in dev mode changed from the
9+
cross-origin `//devHost:devGrailsPort/` to `/api/` (matching production). Requests to `/api/...`
10+
are proxied to Grails with the prefix stripped. This mirrors the production nginx setup, avoids
11+
CORS issues, and simplifies local development. Apps with an explicit `baseUrl` are unaffected.
12+
Requires `@xh/hoist` v84+ for WebSocket compatibility.
13+
14+
315
## v11.2.0 - 2026-03-27
416

517
### ⚙️ Technical

configureWebpack.js

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ try {
6161
* @param {Object} [env.resolveAliases] - object mapping for custom webpack module resolution.
6262
* When inlineHoist=true, a mapping between @xh/hoist and the local path will be added.
6363
* @param {string} [env.baseUrl] - root path prepended to all relative URLs called via FetchService. Defaults to
64-
* `/api/` in production mode to work with proxy-based deployments and to `$devHost:$devGrailsPort` in dev mode.
64+
* `/api/`, a root path that will cause the request to be proxied to the Grails backend at `devHost:devGrailsPort`.
6565
* @param {string[]} [env.babelIncludePaths] - additional paths to pass Babel for transpiling via settings shared with
6666
* app-level and @xh/hoist code. Intended for custom packages.
6767
* @param {string[]} [env.babelExcludePaths] - paths to exclude from Babel transpiling. An example use would be a local
@@ -127,7 +127,7 @@ async function configureWebpack(env) {
127127
devGrailsPort = env.devGrailsPort || 8080,
128128
devWebpackPort = env.devWebpackPort || 3000,
129129
devServerOptions = env.devServerOptions || {},
130-
baseUrl = env.baseUrl || (prodBuild ? '/api/' : `//${devHost}:${devGrailsPort}/`),
130+
baseUrl = env.baseUrl || '/api/',
131131
babelIncludePaths = env.babelIncludePaths || [],
132132
babelExcludePaths = env.babelExcludePaths || [],
133133
contextRoot = env.contextRoot || '/',
@@ -738,6 +738,21 @@ async function configureWebpack(env) {
738738
};
739739
})
740740
},
741+
// Proxy API requests to the Grails backend, mirroring the production nginx setup.
742+
// Only needed when baseUrl is a relative path (default '/api/') — if baseUrl is
743+
// an absolute URL, the app will call the remote server directly.
744+
proxy: baseUrl.startsWith('/')
745+
? [
746+
{
747+
context: baseUrl.slice(0, -1),
748+
target: `http://${devHost}:${devGrailsPort}`,
749+
pathRewrite: {[`^${baseUrl.slice(0, -1)}`]: ''},
750+
changeOrigin: true,
751+
secure: false,
752+
ws: true
753+
}
754+
]
755+
: [],
741756
...devServerOptions
742757
}
743758
};

0 commit comments

Comments
 (0)