import { Ketcher, StandaloneStructServiceProvider } from "ketcher-standalone";
import { Editor } from "ketcher-react";
import "ketcher-react/dist/index.css";
my final bundle increases by about 13 MB, which is a lot. I tried to optimize via CDN, but it didn't work because the ketcher-standalone and ketcher-react libraries loaded from CDN use CommonJS syntax (exports, module.exports), which is not supported in browsers. How can i solve this problem?
This is working example of ketcher:
/* eslint-disable @typescript-eslint/no-explicit-any */
import { useEffect, useState } from "react";
import { Ketcher, StandaloneStructServiceProvider } from "ketcher-standalone";
import { Editor } from "ketcher-react";
import "ketcher-react/dist/index.css";
import { Button } from "components/UI/button";
import { ModalComponent } from "components/UI/modal/ModalComponent";
import "./style.scss";
// Initialize the structServiceProvider for Ketcher (standalone version)
const structServiceProvider = new StandaloneStructServiceProvider();
interface ModalProps {
onOk: (smiles: any) => void;
onCancel: (e: React.MouseEvent) => void;
defaultSmilesValue: string;
isModalOpen: boolean;
isLoading: boolean;
}
export const ModalContentDrawer: React.FC<ModalProps> = ({
onOk,
onCancel,
defaultSmilesValue,
isModalOpen,
isLoading,
}) => {
const [hasError, setHasError] = useState(false);
const [errorMessage, setErrorMessage] = useState("");
const [isKetcherInitialized, setIsKetcherInitialized] = useState(false); // Track Ketcher initialization
const [ketcherInstance, setKetcherInstance] = useState<Ketcher | null>(null); // Store Ketcher instance
// Используйте useEffect для управления жизненным циклом Ketcher
useEffect(() => {
if (
ketcherInstance &&
isKetcherInitialized &&
defaultSmilesValue &&
isModalOpen
) {
try {
ketcherInstance.setMolecule(defaultSmilesValue);
} catch (error) {
console.error("Failed to set SMILES:", error);
setHasError(true);
setErrorMessage("Error setting molecule in Ketcher.");
}
}
}, [defaultSmilesValue, isKetcherInitialized, ketcherInstance, isModalOpen]);
const handleSubmit = async () => {
if (!isKetcherInitialized) {
setErrorMessage("Ketcher is not fully initialized.");
return;
}
if (ketcherInstance) {
try {
// Optionally validate molecule before getting SMILES
const isMoleculeValid = ketcherInstance.getSmiles(); // Ensure there is a valid structure
if (!isMoleculeValid) {
throw new Error("Molecule is invalid or empty.");
}
const smiles = await ketcherInstance.getSmiles();
onOk(smiles);
} catch (error: unknown) {
const errMessage = (error as Error).message;
console.error("Error getting SMILES:", errMessage);
if (errMessage.includes("Unexpected end of JSON input")) {
setErrorMessage(
"Error retrieving SMILES: Invalid or incomplete molecular structure."
);
} else {
setErrorMessage("Failed to retrieve SMILES. Please try again.");
}
setHasError(true);
}
}
};
return (
<ModalComponent
modalTitle={"Structure"}
isModalOpen={isModalOpen}
onOk={onOk}
onCancel={onCancel}
width={930}
>
<div className="modal-drawer-container">
<Editor
buttons={{
sgroup: { hidden: true },
images: { hidden: true },
text: { hidden: true },
}}
staticResourcesUrl={process.env.PUBLIC_URL ?? "./"}
structServiceProvider={structServiceProvider as any}
errorHandler={(message: string | Error) => {
console.error("Error in Ketcher:", message);
setHasError(true);
setErrorMessage(
typeof message === "string" ? message : message.toString()
);
}}
onInit={(ketcher: Ketcher) => {
// Assign Ketcher instance to window for KetcherLogger to use
window.ketcher = ketcher;
if (!ketcherInstance) {
// Проверяем, был ли уже инициализирован Ketcher
setKetcherInstance(ketcher); // Set Ketcher instance in state
setIsKetcherInitialized(true); // Mark Ketcher as initialized
try {
ketcher.setMolecule(defaultSmilesValue); // Set the default SMILES after initialization
} catch (error) {
console.error("Error initializing Ketcher with SMILES:", error);
setHasError(true);
setErrorMessage("Error initializing molecule in Ketcher.");
}
}
}}
/>
{hasError && <div className="error-message">{errorMessage}</div>}
<div className="modal-footer">
<Button onClick={handleSubmit} isLoading={isLoading}>
Confirm
</Button>
<Button onClick={onCancel} type="secondary">
Cancel
</Button>
</div>
</div>
</ModalComponent>
);
};
Background
When adding libraries:
my final bundle increases by about 13 MB, which is a lot. I tried to optimize via CDN, but it didn't work because the ketcher-standalone and ketcher-react libraries loaded from CDN use CommonJS syntax (exports, module.exports), which is not supported in browsers. How can i solve this problem?
This is working example of ketcher: