Vaadin Flow

repository·main·Indexed 20 days ago

https://github.com/vaadin/flow

A Java framework for building modern, high-performance web applications with rich user interfaces. It includes the Flow Client for client-server communication, as well as build plugins for Maven and Gradle to manage frontend lifecycles, production mode bundling, and development environment preparation.

Tokens
28.2K
Snippets
64
Records
107
Agent score
72%

What's inside Vaadin Flow

  1. Overview of embedding test modules

    main

    The test-embedding module contains integration tests for embedding Vaadin Flow. The module structure is organized by execution mode and environment:

    Generic Embedding Modules

    These modules run the same core tests but differ in configuration:

    • test-embedding-generic: Runs in development mode.
    • test-embedding-production: Runs in production mode.
    • test-embedding-generic-compatibility: Runs in compatibility (Bower) mode using HTML imports.
    • test-embedding-production-compatibility: Runs in production mode using compatibility (Bower) mode.

    All four generic modules depend on embedding-test-assets, which provides the test classes and the classes under test. The HTML pages for these tests are located in test-embedding/webapp.

    Theme Variant Modules

    Because a package containing embeddable components can only have one theme, modules leveraging theme variants are separated:

    • test-embedding-theme-variant
    • test-embedding-theme-variant-compatibility
  2. Limitations of the Polymer to Lit converter

    main

    The converter is designed for basic transformations and cannot handle all migration scenarios. Complex cases must be converted manually.

    Key Limitations:

    • Java Models: Implementation is only generated for internal models declared within the View class.
    • Java Model Types: Only String and Boolean fields can have automated model implementations generated.
    • TypeScript: Not supported; type conversion requires project-specific knowledge.
    • Complex Observers: Polymer observers with complex arguments (e.g., observer: 'userListChanged(users.*, filter)') are not supported.
  3. Configure Vaadin Production Mode

    main

    Vaadin determines whether to run in production mode via the META-INF/VAADIN/config/flow-build-info.json file. The plugin sets the productionMode property in this JSON file to true when triggered via:

    1. The command line flag -Pvaadin.productionMode.
    2. The Gradle configuration vaadin { productionMode = true }.
  4. How Flow Express Build mode works and how to refresh it

    main

    Since Vaadin 24.0, Flow applications can run in Express Build mode, where frontend files are pre-compiled and bundled into the {project.root}/src/main/bundles directory.

    If you make changes to the flow-client module, these changes will not be reflected in Flow test modules automatically because they will continue to use the existing bundles. To force Flow to re-compile the bundles with your new changes, you must delete the src/main/bundles directory.

    To remove the dev-bundle in the current folder: rm -rf src/main/bundles

    To remove dev-bundles in all sub-folders: find . -type d -wholename "*/src/main/bundles" -exec rm -r {} +

    # Remove dev-bundle in the current folder
    rm -rf src/main/bundles
    
    # Remove dev-bundles in all sub-folders
    find . -type d -wholename "*/src/main/bundles" -exec rm -r {} +
  5. Understand the flow-tests module structure and organization

    main

    The flow-tests suite is organized along two independent axes to ensure clear testing coverage without duplication:

    1. Settings → module: Modules are split based on the specific build or deployment configuration they require (e.g., production mode, vaadinrouter, pnpm, springsecurity). A module should ideally pin exactly one specific setting.
    2. Feature → package: Within a module, tests are organized into Java packages based on the framework feature they exercise (e.g., routing, dom, components).

    Key Principles:

    • Source Home: Every Integration Test (IT) has exactly one "home" (one module + one package) where its source code lives.
    • Permutations via Reuse: To test a feature under a different setting (e.g., testing routing in production mode), the specialized module reuses the test-jar from the feature's "home" module rather than duplicating the source code.
    • Minimal Specialized Modules: Specialized modules contain only tests that specifically exercise their pinned setting. Generic feature tests are housed in test-default.
  6. Expose reactive state using Signals

    main

    Instead of traditional listener APIs, expose observable state using the Signal<T> pattern.

    Best Practices:

    • Naming: Suffix accessors with Signal (e.g., localeSignal(), valueSignal(), activeSignal()).
    • Implementation: Back the signal with a private ValueSignal<T> and expose it as read-only using valueSignal.asReadonly().
    • Performance: Cache the read-only wrapper in a field. Do not call .asReadonly() inside the getter, as it allocates a new lambda every time.
    • Defaults: Never seed a signal with null. Use a sentinel enum (e.g., UNKNOWN) or a dedicated record (e.g., Pending) to represent missing data.
    • Usage: Use .get() when inside a reactive context (subscribes) and .peek() when outside (snapshot).
    public class MyComponent {
        private final ValueSignal<String> statusSignal = new ValueSignal<>("UNKNOWN");
        private final Signal<String> readOnlyStatus = statusSignal.asReadonly();
    
        public Signal<String> statusSignal() {
            return readOnlyStatus;
        }
    }
  7. Separate read and write surfaces for internal state

    main

    To prevent developer errors, do not expose framework-only setters on classes intended for user consumption.

    The Pattern:

    • Read Surface: Place on the user-facing class or facade.
    • Write Surface: Place on UIInternals (or an equivalent internal-only class).

    For example, if the framework needs to update geolocation availability, setGeolocationAvailability should live on UIInternals, while the user only reads the status from ExtendedClientDetails.

  8. Implement Server-to-Client signaling patterns

    main

    To manage streaming and state changes between the browser and the server, use a pattern where DOM events act as the transport and Signal acts as the state.

    Event-to-Signal Bridging

    1. The client dispatches a CustomEvent (e.g., vaadin-xxx-position or vaadin-xxx-error).
    2. The server-side facade listens for the DOM event, extracts the detail record, and writes it to a private ValueSignal.
    3. Applications subscribe to the Signal rather than the DOM event.

    Client-Initiated State Changes

    For state changes that occur without a server request (e.g., network status, window resize):

    1. The client dispatches a vaadin-xxx-change event on document.body.
    2. The facade registers a listener on ui.getElement() and forwards the detail to the appropriate signal.

    Managing Async Browser Handles

    When a browser API returns an opaque ID (like watchPosition()), do not round-trip the ID itself. Instead:

    1. Pre-generate a UUID on the server.
    2. Pass the UUID as an executeJs parameter.
    3. The client-side wrapper stores a mapping of Map<key, browserId>.
    4. Subsequent operations (like clearWatch(key)) use the server-generated key to look up the actual browser ID.
  9. Understand Vaadin Flow and Platform version alignment

    main

    Since Vaadin Platform 23.0, Flow major and minor versions are aligned with the corresponding Vaadin Platform versions. Use this mapping to ensure compatibility with your Java, Servlet, Jakarta EE, and Spring Boot requirements.

    BranchPlatform VersionFlow VersionRequirements
    2.1314.142.13Java 8+, Servlet 3
    23.623.623.6Java 11+, Servlet 3
    24.1024.1024.10Java 17+, Jakarta EE 10, Spring Boot 3
    25.125.125.1Java 21+, Jakarta EE 11, Spring Boot 4
    25.225.225.2Java 21+, Jakarta EE 11, Spring Boot 4 (Pre-release)
    main25.325.3Java 21+, Jakarta EE 11, Spring Boot 4 (Preparations)
  10. How Integration Test (IT) placement is determined

    main

    Integration Tests are placed in modules based on two axes: Feature and Settings.

    • Feature Packages: Generic feature tests (e.g., dom, components, routing, push) reside in the test-default module.
    • Settings-relevant ITs: Tests that only pass or are only relevant under a specific configuration (e.g., test-pwa, test-tailwind, or test-spring-security) are moved into specialized modules.
    • Special Infrastructure Rule: If an IT requires special infrastructure (like a proxy for network interruption tests), it gets its own dedicated module. If the infrastructure is already present in an existing module (like custom servlet overrides in test-plain-servlet), the IT is placed there.