Why Atom Fell and How Figma’s Plugin Sandbox Redefines Web Editor Architecture
This article examines the decline of traditional web editors like Atom, compares them with VS Code, explores Figma’s JavaScript‑based plugin system and its sandbox mechanisms—including Realm, Duktape, and Web Workers—while discussing broader JavaScript sandboxing techniques and CSS isolation strategies for modern front‑end applications.
Modern Text Editor Rise and Fall
Since the maturation of web technologies, large console projects such as Alibaba Cloud and Tencent Cloud have become increasingly complex, making maintenance, release, and cost control difficult. In this context, micro‑frontends emerged, but the article uses them only as a hook to discuss broader web‑application challenges.
Modern Text Editor Decline
After Microsoft acquired GitHub in 2018, Atom became a frequent target of jokes. VS Code has become the default editor for front‑end engineers, outperforming Atom in performance (both are Electron‑based) and plugin ecosystem—VS Code surpassed 10 000 plugins while Atom remains around 8 000. The LSP/DAP protocols further cement VS Code’s dominance.
Discussions on Zhihu highlight Atom’s slowness, largely caused by its overly permissive plugin architecture, which exposes UI components (FileTree, Tab bar, Settings) to third‑party plugins, creating security and performance issues. VS Code’s plugins run in Node.js with a much more closed UI API.
Because VS Code’s UI is relatively closed, developers sometimes resort to forcibly modifying VS Code’s installation files (e.g., the VS Code Background plugin changes CSS, while the VSC Netease Music plugin replaces the missing FFmpeg library in the Electron bundle), which can break the editor and require reinstallations.
Beyond Editors – Figma
Figma is an online collaborative UI design tool that recently launched its plugin system. Plugins are built with JavaScript/TypeScript and Webpack, lowering the development barrier. Over 300 plugins have been created, ranging from graphic resources to 3D model import.
<code>.</code><code>├── README.md</code><code>├── figma.d.ts</code><code>├── manifest.json</code><code>├── package-lock.json</code><code>├── package.json</code><code>├── src</code><code>│ ├── code.ts</code><code>│ ├── logo.svg</code><code>│ ├── ui.css</code><code>│ ├── ui.html</code><code>│ └── ui.tsx</code><code>├── tsconfig.json</code><code>└── webpack.config.js</code>The
manifest.jsondefines the plugin entry points:
<code>{</code><code> "name": "React Sample",</code><code> "id": "738168449509241862",</code><code> "api": "1.0.0",</code><code> "main": "dist/code.js",</code><code> "ui": "dist/ui.html"</code><code>}</code>The
mainpart runs the plugin logic, while
uiis an HTML fragment rendered in an iframe, preventing CSS leakage. When a plugin is installed, its JavaScript runs inside a sandboxed iframe, and the UI iframe isolates styles from the host application.
How Figma’s Plugin System Works
Figma creates a minimal JavaScript execution environment for the
mainentry that runs on the browser’s main thread, restricting access to global browser APIs. The UI part consists of a single HTML snippet rendered in a popup.
Initially Figma tried an iframe‑based sandbox, but communication via
postMessagerequired all API calls to be async, which was unfriendly to designers and introduced performance overhead for large documents. To improve security while staying on the main thread, Figma adopted a stage‑2 Realm API draft that creates a separate global object for plugins.
<code>let g = window; // outer global</code><code>let r = new Realm(); // root realm</code><code></code><code>let f = r.evaluate("(function() { return 17 })");</code><code>f() === 17 // true</code><code>Reflect.getPrototypeOf(f) === g.Function.prototype // false</code><code>Reflect.getPrototypeOf(f) === r.globalThis.Function.prototype // true</code>Realm can also be implemented with
withand
Proxy, a pattern popular in the community.
<code>const whitelist = {</code><code> window: undefined,</code><code> document: undefined,</code><code> console: window.console,</code><code>};</code><code></code><code>const scopeProxy = new Proxy(whitelist, {</code><code> get(target, prop) {</code><code> if (prop in target) {</code><code> return target[prop];</code><code> }</code><code> return undefined;</code><code> }</code><code>});</code><code></code><code>with (scopeProxy) {</code><code> eval("console.log(document.write)"); // Cannot read property 'write' of undefined!</code><code> eval("console.log('hello')"); // hello</code><code>}</code>To safely expose whitelisted APIs, each API can be wrapped inside the Realm context, preventing prototype‑chain leaks.
<code>const safeLogFactory = realm.evaluate(`</code><code>(function safeLogFactory(unsafeLog) {</code><code> return function safeLog(...args) {</code><code> unsafeLog(...args);</code><code> }</code><code>})`);</code><code></code><code>const safeLog = safeLogFactory(console.log);</code>Figma also embeds the Duktape JavaScript engine (a C++‑implemented interpreter) compiled to WebAssembly. Plugin code runs inside Duktape, allowing a controlled set of APIs without exposing the host’s global objects.
Figma retains the original iframe option, letting plugins create their own iframes and communicate with the sandbox via
postMessage.
Key Requirements for Plugin Sandboxes
JavaScript code sandbox that gives the host application control over third‑party code.
Strong CSS isolation to prevent style leakage.
JavaScript Sandbox
Common approaches include:
Iframe sandbox with the
sandboxattribute.
Using language features such as
with,
Realm, or
Proxyto mask global objects and enforce a whitelist.
Embedding a separate JavaScript engine (e.g., Duktape) compiled to WebAssembly.
Running code in Web Workers and proxying DOM APIs (e.g., worker‑dom, preact‑worker‑demo).
These solutions each have trade‑offs in performance, security, and developer ergonomics.
CSS Scope
Isolation techniques include:
Rendering plugin UI in an iframe (full style isolation at the cost of performance).
CSS Modules that hash class names during build.
Web Components with Shadow DOM, which prevents external styles from affecting the plugin and vice‑versa.
Conclusion
This article listed the challenges faced by large‑scale web applications such as editors and design tools when introducing plugin architectures, and surveyed community solutions like iframe sandboxing, Realm, Web Workers, Duktape, and Shadow DOM. Each approach has its own strengths and weaknesses, and as web applications grow more complex, standardized plugin mechanisms will become increasingly important.
Taobao Frontend Technology
The frontend landscape is constantly evolving, with rapid innovations across familiar languages. Like us, your understanding of the frontend is continually refreshed. Join us on Taobao, a vibrant, all‑encompassing platform, to uncover limitless potential.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.