4.2 Plugin Architecture
The plugin architecture of Kolibri Sync builds directly upon the technical foundations outlined in the Plugins API Chapter. As discussed, Figma plugins operate under a constrained architecture with separate contexts for UI and logic. Instead of following Figma’s recommended setup, which relies on npm and TypeScript. In the following sections, we describe how our structure is more suitable for the scope of Kolibri Sync.
Avoiding NPM
Our approach avoids npm entirely. This is because npm-based projects often include a large number of dependencies as well as an unnecessarily high overhead. Security is another concern. Since npm installs packages and their dependencies automatically, it becomes difficult to fully trace what is included in the build. This can introduce potential vulnerabilities. Managing package versions is also error-prone, especially when dependencies update or break compatibility.
Plain JavaScript and Bundling with Bun
All of our code is written in plain JavaScript without external dependencies. As our plugin grew and the codebase became more modular, we needed a bundling strategy that complied with Figma’s single-file constraint. We chose Bun, a fast and minimal JavaScript runtime bundler. This decision both avoids npm dependency and removes the need for a TypeScript compiler.
With Bun, we could bundle our main plugin logic into a single output file using a simple bun build ./src/main.js --outfile=./dist/code.js --watch command.
Custom Bash Script for UI.html
While Bun can generate separate JavaScript and CSS bundles, it does not support inlining both outputs into a single HTML file. Since Figma requires a complete ui.html file without external references, we used a small Bash script to combine the bundled ui.js and styles.css into the HTML template.
Manifest Configuration
After generating both ui.html and main.js inside the dist folder (see Figure 41), we reference them as entry points in the manifest.json. With this struThis tells Figma which files to load for the plugin’s interface and logic.

{
"name": "Kolibri Sync",
"id": "1480934590279253791",
"api": "1.0.0",
"main": "dist/code.js",
"ui": "dist/ui.html",
"menu": [
{ "name": "Open Kolibri Sync", "command": "open-plugin" },
{ "name": "Run All Tests", "command": "run-api-tests" }
],
"capabilities": [],
"documentAccess": "dynamic-page",
"editorType": [
"figma"
],
"networkAccess": {
"allowedDomains": ["none"]
}
}With this setup, our plugin architecture remains lightweight, dependency-free, and maintainable, while still supporting a modular development process and aligning with Figma's architectural requirements.
Testing Approach
To test our functions, we leveraged Kolibri’s existing testing framework to write unit tests. This approach allowed us to quickly create and execute tests, while collecting the results in an HTML report.
Testing Figma API calls, however, posed a unique challenge. While the Kolibri test framework proved extremely useful for testing pure JavaScript functions, it was not suitable for API-related tests. Mock testing was avoided because it cannot fully replicate the plugin’s runtime environment, and Figma API calls only function when executed inside Figma’s sandbox environment.
To address this, we built a lightweight in-plugin test framework to execute integration-style API tests directly within Figma. This allowed us to verify operations such as creating variable collections, appending components, and generating color variants in a live environment.
For rendering test results, we used the postMessage API to send results from the main plugin code to the UI. We also defined a distinct figma.command (run-api-tests) to trigger the tests before the UI was displayed. This separation ensured that the main plugin logic remained independent from the testing logic. See Figure 43 for the test report of our integration tests.


With this setup, we were able to test both the plugin’s pure JavaScript logic and its real Figma API interactions in realistic conditions. This dual approach ensured broad test coverage while keeping the testing process efficient, helping us quickly identify errors, uncover gaps in the code, and investigate issues with minimal overhead.
Last updated