-
Notifications
You must be signed in to change notification settings - Fork 149
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Client side JavaScript does not work on app proxy pages #436
Comments
@paulomarg @lizkenyon Would be awesome if you could confirm whether there's a way to load client side JS on app proxy pages, as it would be quite useful for us 🙏 |
@lizkenyon Any update here? |
Hey, sorry for the delay in responding - currently, JS won't load in proxies because remix will attempt to load the JS assets from I'm looking into a way of forcing the URL in those requests to the app's URL, but haven't found one yet. I believe you might be able to load javascript if you use a liquid response (using the I'll circle back if I figure out a different way to get that to work! |
@paulomarg Thanks for the update. Would be awesome to get this working out of the box with Remix. I'll test out the liquid helper and see how that goes. |
I also just ran into this issue with the /build directory not loading in the client with app proxy. I've tried a few things but no luck.. Attempt 1 Attempt 2
I'm not sure if this would still be an issue if I got around the CORS errors with attempt 1? @paulomarg if you have any thoughts on this / if I'm just wasting my time please let me know!! UpdateAttempt 3 This is a pretty disappointing and renders remix relatively useless for building user facing apps through app proxies, aside from authentication. Update 2I tested including javascript inside the liquid() helper and that does work. Returning a full webpage of liquid inside a string with javascript is much uglier than working with remix components and jsx though. Would be amazing if there is a workaround to get hydration working with the proxy! |
Hey @matthaake, those are the same things I tried as well, and I think the only way to make that work would be to write a custom Remix server. I believe we'd be able to set the CORS headers for asset requests to make them work if we set up an express server with That would be useful as documentation in any case, IMO. I'm not sure when I'll have time to prototype that, but if you have a chance to and reach something that works, we could figure out the best way of including it in the template. The only downside to doing that is that Remix is in the process of moving over to Vite as a server, which means this would need to be adapted to the vite server when it becomes stable and we start using it in the template. Thank you so much for trying things and for sharing them with us, it's much appreciated! |
Just a quick update: now that the template is running on Vite, I was able to get this to almost work by adding this to my export default defineConfig({
base: process.env.SHOPIFY_APP_URL || "/",
// ...
}); This way, we're forcing the assets to load with the full URL, but there is still one issue with Remix: this raises a hydration error, unless the path in the proxy matches the one in the app exactly. For instance, if you configure your proxy at With that config, if you visit |
Awesome, thank you for looking into this! |
Same here, I'm trying out the new Remix template, did the same thing how it written in the article https://shopify.dev/docs/apps/getting-started/build-qr-code-app?framework=remix But I have 404 error on public pages for JS and CSS files because of relative path is wrong (that works through proxy) @brophdawg11 This looks urgent here, because it's not working solution right on the documentation. I see your answer remix-run/remix#6785 (comment) But I didn't understand how to use this. |
Any progress with the findings? We have tried all above suggestions but couldn't able to accomplish the needs. I'm following up. |
Hey, thanks for pinging here. Unfortunately, Remix doesn't support URL rewrites, which makes proxies hard to work with. However, we just introduced some components that should hopefully make it easier to create proxies - more info in this comment: Shopify/shopify-app-js#455 (comment) Note that this comes with a few caveats, but please try it out after the next release! |
Has anyone now a running example on production? This really gives me headaches.. |
I was able to at least proxy the assets to the correct proxied app url with the help of a express server upfront, but then Remix errors with |
Yes @patrick-schneider-latori , unfortunately because of the lack of rewrite support, you'll run into that issue. Right now, you have to do 2 things:
Hope this helps! |
Thanks for the explanation @paulomarg – let me replay your recommendation, so that all the other people here around understand what you are recommending. Start fresh install Then I go into the Remix import { authenticate } from "../shopify.server";
import { useEffect } from "react";
export const loader = async ({ request }) => {
await authenticate.public.appProxy(request);
return null;
};
export default function App() {
useEffect(() => {
console.log('it works');
}, []);
return (
<div>
hello my-proxy
</div>
);
} The When I now head to So I need now to tell the dev server to take this url and forward it also to the correct Remix file. So I open now
When I now head to So I can check this as solved. Now I try to do the same on production mode. Let's assume the production deployment will resolve on the domain "https://example.ngrok.io". I update my urls on the I install the Shopify app in my production store, opening the app also in the Shopify dashboard to get a fresh offline token in the database. Then I reopen the endpoint again on So I install Express and create a new server.js entry file (using the official example from https://github.com/remix-run/remix/blob/main/templates/express/server.js) and tweaking it a little bit so that I get the following result: import { createRequestHandler } from "@remix-run/express";
import { installGlobals } from "@remix-run/node";
import express from "express";
import { createProxyMiddleware } from 'http-proxy-middleware';
import cors from "cors";
installGlobals();
const viteDevServer =
process.env.NODE_ENV === "production"
? undefined
: await import("vite").then((vite) =>
vite.createServer({
server: { middlewareMode: true },
})
);
const remixHandler = createRequestHandler({
build: viteDevServer
? () => viteDevServer.ssrLoadModule("virtual:remix/server-build")
: await import("./build/server/index.js"),
});
const app = express();
app.disable("x-powered-by");
app.use(cors());
if (viteDevServer) {
app.use(viteDevServer.middlewares);
} else {
app.use(
"/assets",
express.static(
"build/client/assets",
{
immutable: true,
maxAge: "1y",
}
)
);
}
app.use(
express.static(
"build/client", {
maxAge: "1h"
}
)
);
app.use(
'/hello/',
createProxyMiddleware({
target: process.env.SHOPIFY_APP_URL + '/apps/my-proxy/hello',
changeOrigin: true,
}),
);
app.all("*", remixHandler);
const port = process.env.PORT || 3000;
app.listen(port, () =>
console.log(`Express server listening at http://localhost:${port}`)
); I also adjust my start script in
And the
I found out, that the environment variable The direction of the assets also has to be changed, so that the proxy can also take care about them on request. And here is the result: This took my now more than three full days of work to get somehow working. What a waste of time for something which should normally be handled by Remix/Shopify automatically. Hopefully this information helps a lot more people around here to get this app proxy working. |
I would like to add one thing here. You can adjust the app.use(
createProxyMiddleware({
target: process.env.SHOPIFY_APP_URL,
changeOrigin: true,
pathFilter: '/hello/',
pathRewrite: function (path, req) {
return path.replace('/hello/', '/apps/my-proxy/hello/')
}
}),
); So any of the following urls are possible:
|
Thanks for expanding on this, I appreciate the extra context for other folks coming in. I agree that right now there is some awkwardness in setting this up, but unfortunately without URL rewrites there's not a lot we can do (without custom servers), as this very much is a rewrite. Hopefully we'll be able to solve this problem more elegantly in the future. That being said, we've also added some components specifically for app proxies (see We've also recently put out a wiki page on using a custom server in the template. Hopefully these will help others get started with proxies quicker. Since you recently went through a similar process, do you see anything missing in these docs that you think we ought to add? Maybe something that goes from the wiki custom server to one that supports a proxy? |
Since I believe we addressed the original issue here with the new components and fixes, I'm going to close this issue. Please create a new one if you still run into problems. |
Thanks @paulomarg. Looking forward to testing the new components and fixes out. |
I'm looking for this for a long time, thanks. |
@paulomarg I tested this with a very simple reactive page, but it does not work because there are still cors errors loading the javascript files. The page renders, but I cannot get any reactivity.
In the console I get Is it possible to add CORS headers from the server that comes out of the box, or do we still need to set up a custom server even with the |
I added your route to a brand new app and pointed a proxy to it, and I didn't get any such errors 🤔
For me, I could simplify that page to import { authenticate } from "~/shopify.server";
import { AppProxyProvider } from "@shopify/shopify-app-remix/react";
import type { LoaderFunctionArgs } from "@remix-run/node";
import { json } from "@remix-run/node";
import { useLoaderData } from "@remix-run/react";
import { useState } from "react";
export async function loader({ request }: LoaderFunctionArgs) {
await authenticate.public.appProxy(request);
return json({ appUrl: process.env.SHOPIFY_APP_URL! });
}
export default function App() {
const { appUrl } = useLoaderData<typeof loader>();
const [count, setCount] = useState(0);
return (
<AppProxyProvider appUrl={appUrl}>
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>Click me</button>
</div>
</AppProxyProvider>
);
} and it still worked. |
@paulomarg I'm getting it to work when returning content-type html. But running into issues with the liquid response. If I just return But I need to use jsx components. How can I do that? I also tried |
Issue summary
If I create a route in the Remix app with a basic loader and a React component to render as the page content, the page renders properly, but no client side JS works. I tried adding the Scripts component to my route, but no luck.
Perhaps the Remix app doesn't support rendering pages like this?
For example:
Expected behavior
Ideally, rendering an app proxy page in the context of the theme by setting
Content-Type: application/liquid
for the route would work.Actual behavior
The page is rendered, but client side JS is not included, so it's not really useful.
Steps to reproduce the problem
The text was updated successfully, but these errors were encountered: