Frontend Development 16 min read

Designing a Secure Mini‑Program Engine: From Single‑Thread to Dual‑Thread Architecture with Vue

This article chronicles the architectural evolution of a web‑based mini‑program engine, detailing the challenges of sandboxing Vue, restricting unsafe tags, handling performance and native capability limits, and ultimately adopting a dual‑thread model to achieve security and control while preserving developer experience.

360 Tech Engineering
360 Tech Engineering
360 Tech Engineering
Designing a Secure Mini‑Program Engine: From Single‑Thread to Dual‑Thread Architecture with Vue

The author recounts the initial decision to treat the mini‑program as a single‑page application (SPA) running in a browser environment, aiming to let developers write mini‑programs using Vue with a Web‑like experience.

Because the platform must forbid unsafe elements such as <iframe> and <a> , as well as direct DOM manipulation and dangerous APIs, the first technical problem was how to block these tags in Vue templates, which required a modification of Vue's rendering layer.

1.1 Modifying Vue

Two common approaches were considered: polyfilling Vue APIs or forking Vue. Both have drawbacks, so the author chose a third method: installing Vue in node_modules , aliasing it via Webpack, and copying the parts to be changed into the project for direct edits.

The Webpack alias configuration is illustrated below:

const path = require('path')
module.exports = {
  'vue$': path.resolve(__dirname, '../src/web/entry-runtime-with-compiler'),
  compiler: 'vue/src/compiler',
  core: 'vue/src/core',
  shared: 'vue/src/shared',
  web: path.resolve(__dirname, '../src/web'),
  weex: 'vue/src/platforms/weex',
  server: 'vue/src/server',
  sfc: 'vue/src/sfc'
}

By aliasing vue$ to a custom entry, imports of Vue either resolve to the original package (for unchanged parts) or to the modified files in the project.

1.2 Tag Blacklist

During DOM creation Vue’s tagName is checked against a blacklist; if a prohibited tag is found, a warning is issued. This approach, however, only deters well‑behaved developers.

1.3 Encountered Issues

Even with the blacklist, developers can still execute arbitrary JavaScript, manipulate the DOM, and use dangerous BOM APIs, so the author explored sandboxing the user code.

2. Moving to a Dual‑Thread Model

By executing user code (and Vue) inside a Web Worker (or hidden iframe), a master‑slave architecture is created: the Master runs in the sandbox, emits high‑level UI commands, and the Slave thread applies those commands to the real DOM.

This design introduces two major challenges: performance overhead from massive cross‑thread messaging during large UI updates, and limited native capabilities because official components must also run inside the sandbox.

2.1 Performance

When the UI undergoes extensive changes, the Logic thread sends thousands of messages (create element, insert, bind events, etc.), causing noticeable latency despite the UI thread being idle.

2.2 Native Capability Limitations

Since official components must be registered inside the sandboxed Vue instance, they cannot directly access native APIs, making features like video or audio components difficult to implement.

To mitigate this, the author considered a hybrid approach where sandboxed components forward data to the UI thread, which then renders the real native component, but this adds complexity and workload.

3. Returning to Single‑Thread with ShadowDOM

Due to time constraints and risk, the project temporarily reverted to a single‑thread model, using a closed‑mode ShadowDOM to lock the body and prevent direct DOM manipulation while still allowing free JavaScript execution.

Dangerous BOM APIs are disabled, but the open nature of JavaScript still poses security concerns.

4. Final Shift Back to Dual‑Thread

The author concluded that a dual‑thread architecture is the correct direction: place user code and part of the framework in a lightweight Logic thread, keep most UI work and native components in the UI thread, and communicate via lightweight data messages, thereby solving both performance and native capability issues.

With this arrangement, heavy UI updates no longer flood the message channel, and native components run unimpeded, achieving the desired security and control.

5. Cross‑Platform Reflections

Most mini‑program frameworks are essentially web‑based translators; true cross‑platform solutions could either standardize rendering engines (e.g., Flutter) or establish common specifications (e.g., a W3C mini‑program standard).

The author lists key points from the emerging mini‑program whitepaper, such as a standardized .ma package format, unified URI schemes, and widget specifications.

6. Conclusion

The article provides a comprehensive view of the decisions, trade‑offs, and lessons learned while building a secure, performant mini‑program engine, emphasizing that security and governance are the core motivations behind the dual‑thread model.

PerformanceMiniProgramVuesecuritySandboxthreading
360 Tech Engineering
Written by

360 Tech Engineering

Official tech channel of 360, building the most professional technology aggregation platform for the brand.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.