Dimina (星河小程序)

repository·main·Indexed 21 days ago

https://github.com/didi/dimina

A cross-platform mini-program framework that compiles WXML, WXSS, and JS/TS source code into unified resource packages for Android, iOS, Harmony, and Web. It includes the Dimina Mini-program Compiler (DMCC) for transforming source files into runtime outputs and provides platform-specific SDKs, such as the Android SDK utilizing QuickJS and WebView.

Tokens
134.2K
Snippets
445
Records
580
Agent score
73%

What's inside Dimina

  1. What is Dimina (星河小程序)

    main

    Dimina is a cross-platform mini-program framework open-sourced by Didi. It compiles mini-program source code (WXML, WXSS, JavaScript/TypeScript) into unified runtime resource packages that can be loaded by Android, iOS, Harmony, and Web containers.

    Key features include:

    • Embeddable Modules: Existing mini-programs can be embedded into existing Apps as independent modules.
    • Offline Resources: Mini-program packages are provided by the host and stored locally to reduce network dependency.
    • Logic/View Separation: Business logic runs in a separate JS engine or Worker, while the view is rendered by a WebView or Browser.
    • Unified Native Capabilities: Access host capabilities via standard APIs and an extension Bridge without scattering platform-specific logic in business pages.
  2. Overview of Dimina platform runtimes

    main

    Dimina uses a multi-threaded model where business logic and view rendering are separated. The specific engines and containers used depend on the platform:

    PlatformLogic engineView container
    AndroidQuickJSAndroid WebView
    iOSJavaScriptCoreWKWebView
    HarmonyQuickJSHarmony WebView
    WebWeb WorkerBrowser
  3. Understand the compiled output directory structure

    main

    By default, the compiler generates a folder named after the appId inside your target directory.

    Default Structure:

    dist/
      ├─ {appId}/
        ├─ logic.js      # Logic code
        ├─ view.js       # View code
        ├─ style.css     # Styles
        └─ config.json   # Configuration

    Structure with --no-app-id-dir: If you use the --no-app-id-dir flag, the files are placed directly in the target directory without the {appId} subfolder:

    dist/
      ├─ logic.js
      ├─ view.js
      ├─ style.css
      └─ config.json
  4. Understand Dimina Runtime Layers

    main

    The Dimina runtime is divided into four distinct layers. Communication between the Logic and Render layers is not direct; all messages must pass through the Container.

    LayerResponsibilityTypical Implementation
    Service (Logic Layer)App/Page/Component instances, lifecycle, data, and API callsAndroid/Harmony: QuickJS; iOS: JavaScriptCore; Web: Web Worker
    Render (Rendering Layer)Loading views/styles, Vue reactive rendering, DOM events/measurementWebView or Browser with Vue runtime
    ContainerPage stack, message forwarding, resource loading, prewarming, permissions, and platform APIsAndroid, iOS, Harmony SDK, or Web container
    Native (Capability Layer)Camera, Location, Bluetooth, Storage, Network, and Host extensionsPlatform modules and ExtModuleHandler
  5. Debug with vConsole

    main

    The JSSDK includes vConsole and it is statically bundled with pageFrame. It only initializes if an enablement flag is detected in the URL parameters (?vconsole=1).

    How to enable vConsole by platform:

    • Web Container: Always appends ?vconsole=1 when loading pageFrame.
    • Android: Use Dimina.DiminaConfig.Builder().setDebugMode(true).
    • iOS: Use a Debug build or set DMPAppConfig.isDebugMode = true.
    • Harmony: Use a debug HAP or set DMPAppConfig.isDebugMode = true.
  6. Dimina Message Channels: publish vs invoke

    main

    Dimina uses two primary channels for communication between layers via the Container:

    1. publish: Used for forwarding messages between the Logic (Service) and Rendering (Render) layers.
      • Scenarios: setData(), page events, component creation, and state synchronization.
    2. invoke: Used to call capabilities in the Container or a specific target layer and receive a result.
      • Scenarios: wx.request(), routing, system APIs, and selector queries.
  7. Supported relation types and lifecycles

    main

    Relation Types

    • parent: The parent component in a parent-child relationship.
    • child: The child component in a parent-child relationship.
    • ancestor: The ancestor component in an ancestor-descendant relationship.
    • descendant: The descendant component in an ancestor-descendant relationship.

    Lifecycle Hooks

    • linked: Triggered when the relationship is established.
    • linkChanged: Triggered when the relationship changes (e.g., the component is moved).
    • unlinked: Triggered when the relationship is severed or the component is destroyed.
  8. How Dimina runtime works across platforms

    main

    Dimina uses the DMCC (Dimina Mini-program Compiler) to convert source code into logic, view, style, and configuration resources. The container connects the logic layer, view layer, and native capabilities via a message channel.

    Each platform uses a different combination of logic engine and view container:

    | Platform | Logic Engine | View Container | Entry Point |
    | --- | --- | --- | --- |
    | Android | QuickJS | Android WebView | [Android SDK](./android/README.md) |
    | iOS | JavaScriptCore | WKWebView | [iOS SDK](./iOS/README.md) |
    | Harmony | QuickJS | Harmony WebView | [Harmony SDK](./harmony/dimina/README.md) |
    | Web | Web Worker | Browser | [Online Demo](https://didi.github.io/dimina/) |
  9. Understand Android same-layer rendering (同层渲染) limitations

    main

    On Android, same-layer rendering (e.g., for video) is implemented by placing native components behind the WebView and using transparency/hit-testing. This is not a browser-level DOM composition and has the following limitations:

    • Component Support: Only components with a native backplate solution are supported (primarily video).
    • Rendering: Native components do not participate in the DOM rendering tree, CSS z-index stacking, or browser compositor synthesis.
    • Layering: HTML elements can overlap native components, but native components can only be visible through transparent placeholder areas.
    • CSS Effects: CSS clip-path, complex transform, filter, and non-rectangular masking are not supported in synchronization with native components.
    • Gestures: Hit-testing is determined by the Web side. Touching a native placeholder forwards the event to the native component; touching an HTML overlay is handled by the WebView.
    • Transparency: WebView transparency is enabled on-demand only when a visible native component exists.
  10. Understand the App lifecycle

    main

    The App instance is created only once within a single Dimina logic runtime. Switching pages does not re-trigger onLaunch. onLaunch is only triggered again if the logic runtime is destroyed and rebuilt.

    ScenarioCallback
    Cold start and App instance creationApp.onLaunch(options)App.onShow(options)
    Host switches to foregroundApp.onShow(options)
    Host switches to backgroundApp.onHide()
  11. How Service and Render layers communicate via the Container Bridge

    main

    In a Dimina container, the Service (Logic Layer) and Render (View Layer) do not call each other directly. Instead, they communicate through a Container Bridge using two distinct message types:

    • publish (Data & Events): Used for passing data and events between layers. For example, a user click in the Render layer is published to the Service layer, or a setData patch from the Service layer is published to the Render layer.
    • invoke (Capability Calls): Used to request capabilities from a specific target. The Service layer uses invoke to call platform APIs (e.g., wx API), and the Render layer uses invoke to access view/component capabilities.

    Data Path Example (User Interaction):

    1. User interacts with Render.
    2. Render $\rightarrow$ publish(event, dataset) $\rightarrow$ Bridge $\rightarrow$ Service.
    3. Service executes business logic.
    4. Service $\rightarrow$ invoke(wx API) $\rightarrow$ Bridge $\rightarrow$ Native (executes platform implementation).
    5. Native $\rightarrow$ returns result $\rightarrow$ Bridge $\rightarrow$ Service.
    6. Service $\rightarrow$ publish(setData patch) $\rightarrow$ Bridge $\rightarrow$ Render.
    7. Render updates the DOM to show the new interface.
  12. Use global components in subpackages

    main

    Components declared in the root app.json are automatically inherited by pages within subPackages. You do not need to re-declare global components inside subpackage configurations.

    {
      "pages": ["pages/index/index"],
      "subPackages": [{
        "root": "packageA",
        "pages": ["pages/detail/detail"]
      }],
      "usingComponents": {
        "global-button": "./components/global-button/index"
      }
    }