Frontend¶
Frontend plugins are standalone NPM packages that add new widgets and functionality to the tangram web interface. This system is designed for modularity, allowing you to build and share custom UI components.
1. Project Structure¶
A frontend plugin is a standard TypeScript/Vue project that produces a library build.
my-tangram-frontend-plugin/
├── package.json
├── vite.config.ts
└── src/
├── MyWidget.vue
└── index.ts
2. Plugin Entry Point (index.ts)¶
The main file specified in your package.json must export an install function. This function is the plugin's entry point and receives the TangramApi object, which provides methods for interacting with the core application.
import type { TangramApi } from "@open-aviation/tangram-core/api";
import MyWidget from "./MyWidget.vue";
export function install(api: TangramApi) {
// use the API to register a new widget component.
// the first argument is a unique ID for your widget.
// the second is the Vue component itself.
api.registerWidget("my-widget", MyWidget);
}
The TangramApi provides two main functions:
registerWidget(id: string, component: Component): Makes your component available to the core UI.getVueApp(): App: Provides access to the core Vue application instance for advanced use cases.
3. vite configuration¶
To simplify the build process, tangram provides a shared Vite plugin. This handles the complex configuration needed to build your plugin as a library and generate a plugin.json manifest file.
import { defineConfig } from "vite";
import { tangramPlugin } from "@open-aviation/tangram-core/vite-plugin";
export default defineConfig({
plugins: [tangramPlugin()],
});
This standardized build produces a dist-frontend directory containing your compiled JavaScript and the manifest file. tangram uses this manifest to discover and load your plugin.
4. Building and using your plugin¶
First, build your frontend assets. If you are in the monorepo, pnpm build will handle this.
Next, ensure the generated dist-frontend directory is included in your Python package's wheel. This is typically done in pyproject.toml.
[tool.hatch.build.targets.wheel.force-include]
"dist-frontend" = "my_plugin/dist-frontend"
Configuring vite to output to a subdirectory of your python source (e.g. src/my_plugin/dist-frontend) ensures maturin includes it automatically.
build: {
outDir: path.resolve(__dirname, "./src/my_plugin/dist-frontend"),
}
Finally, install your Python package and enable it in your tangram.toml:
[core]
plugins = ["my_tangram_plugin"]
When tangram serve runs, it will:
- Read the
plugin.jsonmanifest from every enabled plugin at startup. - Amalgamate these into a single cached response for
/manifest.json. - The core web app fetches this single manifest and dynamically loads resources.
sequenceDiagram
participant P as Plugin Module
participant B as Browser
participant S as Tangram Server
B->>S: GET /manifest.json
S-->>B: Respond with {"plugins": {"my_plugin": {"main": "index.js"}}}
B->>S: GET /plugins/my_plugin/index.js
S-->>B: Serve plugin's JS entry point
Note over B, P: Browser executes plugin code
P->>B: install(tangramApi)
Note over B: Plugin registers its widgets