unstable_dev
in v1.16.0 is incompatible with GitHub Codespaces for Web (& other port forwarding)
#6379
Closed
1 task done
Labels
What version of Remix are you using?
v1.16.0
Are all your remix dependencies & dev-dependencies using the same version?
Background
GitHub Codespaces for Web, and other web-based containerised environments, solve the problem of securely accessing other ports by forwarding them to URLs on port 80 that include the original port in the URL.
For example, if I open the following 3 ports as part of my dev process:
http://localhost:3000
: My app (HTTP)http://localhost:3001
: Remix dev server (HTTP)http://localhost:3002
: Remix HMR server (WebSocket)Codespaces will allow me to access them on the following URLs:
https://<CODESPACE-NAME>-3000.preview.app.github.dev
: My app (HTTP)https://<CODESPACE-NAME>-3001.preview.app.github.dev
: Remix dev server (HTTP)https://<CODESPACE-NAME>-3002.preview.app.github.dev
: Remix HMR server (WebSocket)One of the issues with this format is that, codespace-to-codespace, these URLs will vary. Both the
<CODESPACE-NAME>
andpreview.app.github.dev
components of the URL can change. These can be accessed in the Codespaces environment using theCODESPACE_NAME
andGITHUB_CODESPACES_PORT_FORWARDING_DOMAIN
environment variables, as well as theCODESPACES
environment variable, which will betrue
if we’re in a Codespace environment. See more in GitHub’s documentation.The other issue with this format is that you have to visit the URL first to authenticate with it and save the appropriate cookie. Unfortunately, Codespaces doesn’t appropriately forward the
OPTIONS
request for CORS assets (such as those linked via<link rel=modulepreload>
). More on this later.Behaviour in the stable dev server
Pre-HMR, there was no issue. All of my assets were hosted on the port-3000 server, and I would visit
https://<CODESPACE-NAME>-3000.preview.app.github.dev
to access them.Behaviour in the pre-v1.16.0
unstable_dev
serverIn the last version of Remix, I was able to use HMR by hooking up my app’s server (port 3000) with the HMR WebSocket (in this example, port 3002). This doesn’t work under the default templates, because
<LiveReload />
generates a component that looks forhttp://localhost:3002
instead ofhttps://<CODESPACE-NAME>-3002.preview.app.github.dev
. I was able to patch this by writing my own<LiveReload />
component, detailed here.Behaviour in the v1.16.0
unstable_dev
serverThis version of the dev server serves JavaScript & CSS assets at a new url,
http://localhost:3001
, and rewrites the URLs pointing to the app server (port 3000) to the new URL.Unfortunately, this has the same issue as the HMR above, albeit with a less obvious fix. Loading my app through the Codespaces URL (
https://<CODESPACE-NAME>-3000.preview.app.github.dev
) fails to load the CSS & JS, because it’s looking forhttp://localhost:3001
, when it should be looking forhttps://<CODESPACE-NAME>-3001.preview.app.github.dev
.If I set
--http-host <CODESPACE-NAME>-3001.preview.app.github.dev
and--http-port 3001
, then my client looks forhttps://<CODESPACE-NAME>-3001.preview.app.github.dev:3001
, which is also incorrect. If I try to set--http-port 80
, I get anEACCESS
.Issue A: The dev server writes the wrong port on the asset URL
Diagnosis
The issue is that the dev server hosts assets on the same port that it’s trying to rewrite to. The following line is how Remix creates the URLs for the clients to search from:
remix/packages/remix-dev/devServer_unstable/index.ts
Line 24 in f95ff28
Workaround
I can
pnpm patch
the package to make the line into:Issue B: Codespaces blocks the CORS
OPTIONS
request for the JS assetsDiagnosis
After patching Issue A, my browser is able to load the CSS assets, which are behind a
<link rel=stylesheet>
, which doesn’t use CORS. However, I get a tonne of blocked CORS requests for the JS assets, because they’re using<link rel=modulepreload>
.This is because, for a privately-forwarded Codespaces port (i.e. behind authentication), Codespaces 302s to a sign-in link. Unfortunately, this URL doesn’t respond with an
Access-Control-Allow-Origin
header, which causes the browser to block the request. This is discussed further in github/community#15351.Workaround
The only workaround is to set the dev server port (3001) to ‘public visibility’ in Codespaces. This will prevent it from redirecting to the sign-in link, but it exposes all your assets to the clearweb while your server is running. (There might also be some browser flags but I am definitely not risking disabling those).
(If you’re a new Codespaces user seeing this issue for the first time, you’ll also want to implement the HMR workaround)
Why is this an issue?
There is no way to use the dev server, with or without HMR, without patching the package today and exposing your assets to the clearweb. Given that Codespaces for Web (or other similar non-standard setups, c.f. #2859) is fairly niche, I don’t expect this to be a high-priority issue. I’m raising it mainly to document that it exists & that there is a reasonable workaround that requires some user-side maintenance.
Proposed Solutions
I am happy to PR both if the maintainers agree. However, due to Issue B, Codespaces still won’t work out of the box without (a) architectural changes to the dev server or (b) Codespaces-specific code in the Remix codebase. Both seem like bad ideas. Perhaps novice Codespaces users should just revert to running their own build watcher and forgoing HMR?
Issue A (Asset URLs)
The best way to handle this would be to expose separate config options for the hosting & fetching ports. These could then be dynamically computed in
remix.config.js
for Codespaces users. Codespaces users would then be able to dynamically inject their config using the environment variables discussed above.Issue B (CORS)
Ideally, Codespaces fix this upstream. I wonder if the host process could intercept requests on the default server port (ex. 3000) and split them between the managed subprocess and the asset server?
The text was updated successfully, but these errors were encountered: