-
Notifications
You must be signed in to change notification settings - Fork 2.5k
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
SVG Icon causing Uncaught Error: Cannot initialize 'routeModules'.
#3015
Comments
Please post the error stack if possible; it might hint us what's going on. Feel free to edit-out the paths/sensitive data. I would like to help but I'm in a peculiar situation: you admit it can't be recreated on a fresh install and I don't have access to your project so I can't recreate... |
Sure let me know how else I can help to track this down
|
Check the https://remix.run/docs/en/v1/pages/gotchas#server-code-in-client-bundles — something within |
How did it go? Any luck troubleshooting? |
@afk-mario I have encountered the same issue and the problem was having statements outside actions, something @revelt So, this will error:
...while this won't:
|
Thanks for the pointers @revelt @ibreslauer I'm gonna spend today debugging this and come back with more info later |
I have isolated the issue to I have tried rendering an empty reach dialog and this happens, I tried to render the same children outside of the dialog and the error doesn't happen. Also this worked fine until I added a This is my Dialog component: import PropTypes from "prop-types";
import classNames from "classnames";
import { DialogOverlay, DialogContent } from "@reach/dialog";
import Header from "./header";
import Content from "./content";
import Footer from "./footer";
import { statuses, themes, classNamePrefix } from "./constants";
/**
* @param {Object} props
* @param {string} [props.className=] - Custom class name
* @param {string} [props.theme=light] - [light, dark]
* @param {string} [props.status=normal] - [normal, danger]
* @param {Object} [props.isOpen=] - Boolean to open and close the modal
* @param {Object} [props.onDismiss=] - What will happen when the user press ESC (close the modal)
* @param {Object} [props.dangerouslyBypassFocusLock=] - Should be false always, unless you know what you are doing
*/
function Modal({
theme,
status,
isOpen,
onDismiss,
children,
className,
...rest
}) {
const customClassName = classNames(`${classNamePrefix}-container`, className);
return (
<DialogOverlay
className={`${classNamePrefix}-backdrop`}
isOpen={isOpen}
onDismiss={onDismiss}
data-theme={theme}
data-status={status}
>
<DialogContent className={customClassName} {...rest}>
{children}
</DialogContent>
</DialogOverlay>
);
}
Modal.propTypes = {
status: PropTypes.oneOf(statuses),
theme: PropTypes.oneOf(themes),
className: PropTypes.string,
children: PropTypes.node.isRequired,
isOpen: PropTypes.bool,
onDismiss: PropTypes.func.isRequired,
};
Modal.defaultProps = {
className: null,
status: "normal",
theme: "light",
isOpen: false,
};
Modal.Header = Header;
Modal.Content = Content;
Modal.Footer = Footer;
export default Modal; |
I have been debugging this for the last couple of days. I figured out that the issue happens only when two specific component share the same Dialog component. I still don't understand how the modal logic + a react-icon in a different file = to server code leaking to the client. I'm going to try to explain the components.
It looks something like this: // page.jsx
function Page({ className, children }) {
const customClassName = classnames("page", className);
const isConnected = useIsConnected();
return (
<>
<SiteHeader>
{isConnected ? <User className="site-header-action" /> : null}
{!isConnected ? <ConnectModal className="site-header-action" /> : null}
</SiteHeader>
<main className={customClassName}>{children}</main>
</>
);
} // connect-modal.jsx
import { useState, useCallback, useEffect } from "react";
import { CgEthernet } from "react-icons/cg";
import { getEnv } from "~/utils/env";
import { useisConnected } from "~/hooks/use-is-connected";
import Modal from "~/components/modal";
import LoginForm from "~/containers/login-form";
function ConnectModal({ className }) {
const { REMIX_APP_NETWORK_ID: networkId } = getEnv();
const [isOpen, setIsOpen] = useState();
const open = useCallback(() => setIsOpen(true), [setIsOpen]);
const close = useCallback(() => setIsOpen(false), [setIsOpen]);
const isConnected = useisConnected();
useEffect(() => {
if (isConnected && isOpen) {
close();
}
}, [isConnected, isOpen, close]);
return (
<>
<button
className={`connect-modal-button ${className}`}
type="button"
onClick={open}
>
Connect
</button>
<Modal
isOpen={isOpen}
onDismiss={close}
aria-label="Connect Modal"
theme="dark"
>
<Modal.Header
title="Connect"
onDismiss={close}
icon={CgEthernet}
/>
<LoginForm networkId={networkId} />
<Modal.Footer>
<button className="button" type="button" onClick={close}>
Close
</button>
</Modal.Footer>
</Modal>
</>
);
}
export default ConnectModal; And the // product-delete-modal.jsx
import { useFetcher } from "@remix-run/react";
import { useEffect } from "react";
import { CgTrash } from "react-icons/cg";
import Modal from "~/components/modal";
function ProductDeleteModal({ id, name, isOpen, onDismiss }) {
const fetcher = useFetcher();
const mutate = () => {
fetcher.submit(null, {
method: "post",
action: `/admin/product/${id}/delete`,
});
};
useEffect(() => {
if (fetcher.type === "done" && fetcher.data.ok) {
onDismiss();
}
}, [fetcher, onDismiss]);
return (
<Modal
isOpen={isOpen}
onDismiss={onDismiss}
aria-label="Product Delete modal"
theme="dark"
>
<Modal.Header title={`Delete ${name}`} icon={CgTrash} />
<p>Are you sure you want to delete {name}?</p>
<p>
This action <strong>cannot</strong> be undone.
</p>
<Modal.Footer>
<button className="button" type="button" onClick={onDismiss}>
Cancel
</button>
<button
className="button"
type="button"
onClick={mutate}
disabled={fetcher.state !== "idle"}
>
{fetcher.state !== "idle" ? "..." : "Delete"}
</button>
</Modal.Footer>
</Modal>
);
}
export default ProductDeleteModal; My current solution was to use my normal After this I was able to add the I guess there is something in the logic of the connect modal or the delete product modal that's is causing the leakage but the current error message is not really helpful. |
What is in this file?
The error message is pretty descriptive and is likely calling out the root cause.
You are likely calling a node API somewhere in your client code. The ‘getEnv’ seems suspicious. You might want to try renaming the file to ‘env.server.ts’ to tell Remix not to include it in the client bundle. |
I think it would be helpful to get the function or code that it's getting leaked from the back-end.
Was my first suspicion as well, removed all the getEnv calls and still got the error. What I don't understand is how a SVG icon component is related to leaked front-end/back-end code |
It would be a very opportunistic shortcut, but what if you took the SVG source of the icon, placed it into your ad-hoc component, and then attributed the icon creators somewhere? I'm just introducing a possible option — that's what I'd do if I were stuck — I'd lift the raw SVG and mention it somewhere in root readme and call it a day? |
I'm triggering this error by adding the class,
Making almost any change makes it work again. Even as simple as adding a comment Update: In this case, it ended up being a cache name collision in the browser. The file |
Also experiencing this issue, the problem is that nobody in the team can reproduce it except random occurrences between deploys to prod. It works just fine after refreshing. Our suspect is cache conflict as well, but what concerns me is why this error leaks from the Edit: we use Cloudflare cache |
I think this is related to #2987 as I'm getting that error after updating |
It is related to #2987 ! I minified the code and it's working now! |
Closed in favor of #2987 |
For me this happens if I do this: import { db } from "../../../common/src/utils/db.server"; But everything works if I do this: import { db } from "~/utils/db.server";` The |
What version of Remix are you using?
1.4.3
Steps to Reproduce
Can't reproduce on a clean install but happens whenever I use a ReactIcon component, nothing else changes in the application.
Expected Behavior
To render the application without server code
Actual Behavior
The app crashes
The text was updated successfully, but these errors were encountered: