The editor opens twice
You add a catalogue panel that can be shown and hidden. Each opening installs new listeners. After three openings, one click sends three requests. This is a lifecycle problem, not a pricing problem.
Make mounting return cleanup. Keep element creation, event registration and async ownership understandable. The small example below assumes the form exists and loader is your catalogue loader. Adapt it to the actual events your panel owns.
export function mountCatalogue(form, loader) {
const onSubmit = (event) => {
event.preventDefault();
void loader.load('/api/products');
};
form.addEventListener('submit', onSubmit);
return () => {
form.removeEventListener('submit', onSubmit);
loader.dispose();
};
}
Call the returned function before removing that view. Do not use this catalogue form listener on the quote form: separate forms express separate actions. If your page never mounts/unmounts panels, keep one startup binding; do not add a lifecycle framework for an imaginary requirement.
What tools would buy us
Native modules already give explicit imports. Our manual static map is small but becomes inconvenient as files grow. A development server or bundler could resolve modules and refresh the page. A type checker could catch mismatched object shapes during development. A formatter could reduce style debates. None of these tools decides whether a stale confirmation is acceptable.
Before adding a dependency, write its job, the problem observed, and how you would notice that it stopped doing its job. Keep source files separate from generated output. Document the command that starts development and the command that produces deployable output, if you introduce a build.
Browser APIs versus server APIs
document belongs to the browser environment; node:fs belongs to Node. A pure module can run in both if its dependencies permit it. A bundler does not make a server secret safe to ship to a browser. Keep configuration intended for the server outside public files.
The course baseline deliberately runs without installing a framework. You may explore a tool in a separate branch, but the required project remains runnable through npm start and npm test with its documented Node prerequisite.
Verify cleanup
Mount, submit once, clean up, mount again, submit once. Count two requests in total. Resolve an old request after cleanup: it must not update the retired view. Repeat the exercise with the storage watcher if you made it view-scoped.
Deliver a README explaining startup, tests, module boundaries, data reset and known limits. A project is easier to trust when another person can reproduce its behavior without asking its author what to click.