platform icon indicating copy to clipboard operation
platform copied to clipboard

React hybrid routing

Open mshabarov opened this issue 1 year ago • 6 comments

Description

Support routing to Flow views in React+Hilla applications using React Router.

Use cases

As a developer I want to extend my React+Hilla application with server-side Flow views
So that I can benefit from Flow provided features, e.g. server-side navigation, Push and others.

As a developer I want to extend my Flow application with React-based views/components using Hilla
So that I can benefit from using React where I want.

Acceptance criteria

  • [x] React Router is integrated with the client-side and server-side Flow API in a same way as Vaadin Router does for Lit - @ClientCallable and methods in Flow.js, so that this integration doesn't bring major changes in Flow API.
  • [x] Flow automatically generates on a build phase the codes for App.tsx and routes.tsx that is needed to connect React Router with the Flow API
  • [x] Flow views are rendered inside the same client-side main layout that is used for existing Hilla views.
  • [x] Adding Flow routes to React+Hilla apps need minor manual route customisation, which is well-documented in Hilla/Flow docs.
  • [x] The integration supports the same routing features as the Vaadin Router integration with regards to e.g.
    • [x] access control, including rerouting to a login page
    • [x] navigation events and server-side navigation
    • [x] beforeLeaveEvent.postpone()
    • [x] handling context path and query parameter within navigation
    • [x] routing exception handling
    • [x] page titles
    • [x] RouterLink and Anchor works the same way as for Vaadin Router
    • [x] Push support
    • [x] MPR
    • [x] eager bootstrapping/rendering.

General criteria

  1. Flow applications that are not hybrids keep using Vaadin Router just like today.
  2. No need for a new routing API for Hilla, this isn't in scope of this project.
  3. This acceptance criteria covers the routing aspect of integration between Flow and React. Other aspects such as reusing 3rd party React components or using React as a template language from Flow are outside the scope of this project.
  4. React router integration is turned on by feature flag and Flow gives a clarification message to developer about the need of adding this feature flag.
  5. Flow tracks usage of hybrid configuration, including React+Hilla+Flow, Lit+Hilla+Flow cases.
  6. start.vaadin.com includes starter project for React+Hilla+Flow, having Hilla and Flow views and feature flag turned ON by default.
  • [ ] APIs reviewed
  • [ ] Design
  • [ ] Performance
  • [ ] UX/DX tests in Alpha
  • [ ] Documentation:
  • [ ] How to test?
  • [ ] Limitations:

Security

  • [ ] Security implications have been taken into account (elaborate or link to product security requirement specification if there are implications)

mshabarov avatar Nov 16 '23 15:11 mshabarov

navigation events and server-side navigation

Tested Hilla view -> Flow view navigation and navigation lifecycle events: BeforeLeaveEvent, BeforeEnterEvent , AfterNavigationEvent, including .addBeforeEnterListener() listener and forwardTo/rerouteTo methods. Works as expected.

mshabarov avatar Nov 28 '23 16:11 mshabarov

Minimal documentation on getting the combination to work

Adding Flow to a Hilla-react project. (sample from CRM tutorial)

  • Add the flow managed dependency bom to pom.xml
    <properties>
        <java.version>17</java.version>
        <vaadin.version>24.3-SNAPSHOT</vaadin.version>
        <hilla.version>2.4.0</hilla.version>
    </properties>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>com.vaadin</groupId>
                <artifactId>vaadin-bom</artifactId>
                <version>${vaadin.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!-- Other pom imports like hilla -->
        </dependencies>
    </dependencyManagement>
  • Add the vaadin-core / vaadin dependency

      <dependency>
          <groupId>com.vaadin</groupId>
          <!-- Replace artifactId with vaadin-core to use only free components -->
          <artifactId>vaadin</artifactId>
      </dependency>
    
  • enable in src/main/resources/vaadin-featureflags.properties react for flow with:

    com.vaadin.experimental.reactRouter=true

  • Into frontend/routes.tsx add the serverSideRoutes object:

    
    mport {serverSideRoutes} from "Frontend/generated/flow/Flow";
    
    ..
    xport const routes = [
    // Hilla definitions
    ...serverSideRoutes
    
    

    .crm_routes

    xport const routes = [
     {
       element: <MainLayout />,
       handle: { title: 'Hilla CRM' },
       children: [
         { path: '/', element: <ContactsView />, handle: { title: 'Contacts' } },
         { path: '/about', element: <AboutView />, handle: { title: 'About' } },
         ...serverSideRoutes
       ],
     },
     as RouteObject[];
    

    [NOTE] The Frontend/generated/flow/Flow will be created when the project is run (node tasks will generate this)

  • Add Flow views with Route annotation.

  • Run project and Flow views can be navigated to.

caalador avatar Dec 05 '23 12:12 caalador

Enabling eagerServerLoad in a Flow project works as expected. Also couldn't see any issues in a hilla-flow-react hybrid after enabling the flag.

caalador avatar Dec 07 '23 12:12 caalador

Access control seems to work fine for Flow view.

  1. Navigating from Hilla view to protected Flow view reroutes to login view if not authenticated.
  2. Navigating from Hilla view to unauthorised Flow view shows "Could not navigate to..." standard page.

However, one thing that doesn't work is navigating to Hilla view that is protected by a role. For some reason, this view redirects back to login view, even after successful login. Public Hilla view doesn't have this problem.

In the browser console log I see that UserInfoService returns "ROLE_USER" to the client and login method returns no errors.

Maybe my project configuration is incorrect. I followed this tutorial https://hilla.dev/docs/react/guides/security/spring-login.

Here is my test project. proto-hilla-react-hybrid.zip

@platosha could you please verify my test project when appropriate ?

mshabarov avatar Dec 07 '23 15:12 mshabarov

  • Add hilla managed dependency bom to pom.xml
     <properties>
        ...
        <hilla.version>2.3.3</hilla.version>
     </properties>
 
    <dependencyManagement>
        <dependencies>
            <!-- Other pom imports like hilla -->
            <dependency>
                <groupId>dev.hilla</groupId>
                <artifactId>hilla-bom</artifactId>
                <version>${hilla.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
         </dependencies>
     </dependencyManagement>
  • Add hilla-react and hilla-spring-boot-starter dependencies
        <dependency>
            <groupId>dev.hilla</groupId>
            <artifactId>hilla-react</artifactId>
        </dependency>
        <!-- REPLACE vaadin-spring-boot-starter with hilla starter
         <dependency>
             <groupId>com.vaadin</groupId>
             <artifactId>vaadin-spring-boot-starter</artifactId>
        </dependency>-->
        <dependency>
            <groupId>dev.hilla</groupId>
            <artifactId>hilla-react-spring-boot-starter</artifactId>
         </dependency>
  • Change all vaadin-maven-plugin instances into hilla-maven-plugin
             <plugin>
-                <groupId>com.vaadin</groupId>
-                <artifactId>vaadin-maven-plugin</artifactId>
-                <version>${vaadin.version}</version>
+                <groupId>dev.hilla</groupId>
+                <artifactId>hilla-maven-plugin</artifactId>
+                <version>${hilla.version}</version>
                 <executions>
                     <execution>
                         <goals>
  • enable in src/main/resources/vaadin-featureflags.properties react for flow with:

com.vaadin.experimental.reactRouter=true

  • Run mvn hilla:init-app

  • Add into frontend/routes.tsx the serverSideRoutes object:

 import {serverSideRoutes} from "Frontend/generated/flow/Flow";

 ...
 export const routes = [
 	// Hilla definitions
 	...serverSideRoutes
 ]

caalador avatar Dec 12 '23 08:12 caalador

So the issue with React routes redirect was that the server returns {"authorities": ["ROLE_USER"]}, whereas the Hilla helper expects {"roles": ["USER"]}. This implementation mismatch is not related with hybrid routing and is easy to workaround by specifying client-side auth configuration with getRoles.

platosha avatar Dec 12 '23 16:12 platosha

This ticket/PR has been released with Vaadin 24.4.0.

vaadin-bot avatar Jun 11 '24 15:06 vaadin-bot