Recommended pattern for splitting a large plugin UI across multiple JS/CSS files? #1668
Replies: 1 comment
|
Hi @nara-falconeer, Good question — there are two patterns supported today that should fit what you're describing. Neither is auto-magic at the framework level, but both are in our published example plugins, so we know they work end-to-end. Pattern 1: split JS/CSS into separate files, serve each from its own SimpleAPI routeThis is the closest analogue to "static-asset endpoints in a plugin package." You add one class MyWebApp(SimpleAPI):
PREFIX = "/app"
@api.get("/")
def page(self) -> list[Response | Effect]:
return [HTMLResponse(render_to_string("static/app.html", context), status_code=HTTPStatus.OK)]
@api.get("/main.js")
def main_js(self) -> list[Response | Effect]:
return [Response(
render_to_string("static/main.js").encode(),
status_code=HTTPStatus.OK,
content_type="text/javascript",
)]
@api.get("/styles.css")
def styles_css(self) -> list[Response | Effect]:
return [Response(
render_to_string("static/styles.css").encode(),
status_code=HTTPStatus.OK,
content_type="text/css",
)]The HTML then references them as relative URLs, just like normal static assets: <link rel="stylesheet" href="styles.css">
<script type="text/javascript" src="main.js"></script>Working examples in the canvas-plugins repo:
Nothing stops you from extending this to as many files as you need — You can also break a single big JS file into ES modules and load them with Sharing across pluginsSimpleAPI routes are mounted at the absolute path Pattern 2: bundle with Vite (or your tool of choice), ship a single inlined templateIf you want the full JS toolchain — TypeScript, linting, unit tests, HMR during dev, tree-shaking — the
You keep multi-file source code, full toolchain, and unit-testable JS — but ship one template at runtime. This addresses every cost you listed (navigation, reuse, tooling, debugging, concurrent work). Replace On your three questions, directly
Let me know if either of those patterns gets you unblocked, or if there's a specific shape of "shared across plugins" that doesn't fit the URL-reference approach above. |
Uh oh!
There was an error while loading. Please reload this page.
We're building a plugin with a substantial in-chart UI (multi-step flows, panel layouts, modals).
The pattern we know is: Application handler → LaunchModalEffect → SimpleAPI route that renders a single HTML template via render_to_string, with all JS and CSS inline.
That's fine for small UIs. We're now past 4,000 lines of inline JS in one template, and the cost compounds:
Things we looked for and didn't find:
Questions:
All reactions