Configuration API Challenges in Browser Environments for SPA Applications
π οΈ Description
I've been experimenting with the configuration approach outlined in the https://logtape.org/manual/config and encountered some challenges when implementing in browser environments.
While the current configuration method works well in Node.js environments, it presents difficulties in browser-based Single Page Applications (SPAs) where we typically need a singleton pattern that can be initialized at any application lifecycle stage without relying on top-level await syntax, which isn't supported in browsers.
π Expected Behavior
Ideally, the configuration system would: β’ Support seamless initialization in browser environments
β’ Allow singleton pattern implementation without top-level await
β’ Maintain compatibility with library development best practices
β’ Provide a clean API for use within class constructors
π Actual Behavior
Currently, when implementing a logger for a library in browser environments, I'm forced to use configureSync within class constructors, which contradicts the recommended practices in the https://logtape.org/manual/library.
π» Environment
β’ Environment: Browser (SPA applications)
β’ Use Case: Library development
β’ Constraint: No top-level await support
π§© Code Example
class Demo {
private logger = getLogger(["Root"]);
constructor(options) {
// ... some code
configureSync({
reset: true,
sinks: {
console: getConsoleSink({ nonBlocking: true })
},
loggers: [
{
category: "IMSDK",
sinks: ["console"],
lowestLevel: options.debug ? "debug" : "info"
}
]
});
}
public someMethod() {
this.logger.debug("someMethod :>> ", () => ({ demo: "foo" }));
}
}
π‘ Suggested Improvement
Would it be possible to provide an alternative configuration method that:
- Supports browser environments without requiring top-level await
- Allows proper singleton initialization for SPAs
- Maintains alignment with library development best practices
- Provides a clean abstraction for library authors
π€ Additional Context
I understand this might be a design trade-off, but I believe improving browser support would make the library more accessible for client-side applications and library developers.
Thank you for raising this issue! I understand your concern about the configuration challenges in browser/SPA environments.
The core philosophy
LogTape is designed as a logging library for librariesβthe key principle is that libraries should never call configure()/configureSync(). Configuration is always the responsibility of the application developer, not the library author.
The real issue
Looking at your example code:
class Demo { // This appears to be library code
constructor(options) {
configureSync({ ... }); // β Libraries shouldn't do this
}
}
This violates LogTape's design principle. Libraries should only use getLogger(), never configure.
Solutions for browser/SPA
For application developers, here are the correct patterns:
1. Configure at app entry point (recommended)
// main.js - Application entry point
import { configureSync } from "@logtape/logtape";
// Configure once at startup
configureSync({ ... });
// Then start your app
import("./app").then(({ App }) => new App());
2. Using ES module initialization
// setup.js
configureSync({ ... });
// main.js
import "./setup"; // Ensures configuration runs first
import { App } from "./App";
3. With frameworks
// React example
configureSync({ ... }); // Before React initialization
createRoot(container).render(<App />);
// Vue example
configureSync({ ... }); // Before Vue initialization
createApp(App).mount('#app');
Why this works
- Modern bundlers handle module initialization order correctly
- SPA entry points already support synchronous setup code
- No need for top-level await in browsers
Conclusion
The issue isn't really about browser limitations or the need for a new API. It's about following the correct pattern: configure once in your application, never in libraries. The browser environment already provides adequate mechanisms for this.
That said, I agree the documentation could be improved with more browser/SPA-specific examples to make these patterns clearer.
Thank you for your detailed response and for emphasizing the core design principles of LogTape. I appreciate your commitment to improving the documentation with more browser/SPA-specific examples, which will certainly help clarify the intended usage patterns.
I understand that libraries should avoid calling configure()or configureSync()and instead leave configuration to application developers. However, in practice, when working in browser environments and managing complex dependency trees (such as when a library and an application both depend on LogTape), version mismatches and maintenance overhead can become challenging. For example, if multiple versions of LogTape are nested within dependencies, it could lead to inconsistent behavior or increased effort in ensuring compatibility.
While I acknowledge the solutions you provided for application developers (e.g., configuring at the entry point), I still believe there might be opportunities to further streamline the browser development experience. For instance, exploring patterns like singleton-based initialization or environment-aware defaults could reduce the mental burden on developers while adhering to your philosophy.
At this stage, I will adjust my code according to the design philosophy of the logtape.
But from my perspective as a user, if possible, the less cognitive burden the better.