Skip to main content
important

This is a contributors guide and NOT a user guide. Please visit these docs if you are using or evaluating SuperTokens.

Split recipe-specific route handlers into separate components

Status

This is just a proposal so far, it hasn't been accepted and needs further discussion.

Status:
proposed
Deciders:
rishabhpoddar, porcellus
Proposed by:
porcellus
Created:
2023-01-24

Context and Problem Statement#

We want to enable apps to initialize supertokens-auth-react without bundling react. This is useful for example in angular apps, where we should be able to use a single init call in the main route (and use auth-react throughout the app), while only bundling react to the module handling auth.

Considered Options#

  • Add recipeIds into input of getRoutingComponent
  • Add separate components for the pre-built UI of each recipe

Decision Outcome#

Chosen option: Add recipe specific UI classes into input of getRoutingComponent

  • Works with most bundlers
  • Works with react-router-dom
  • Less interface change

Notes:

  • The new classes will be called RecipeNamePreBuiltUI
  • We choose not to handle component overrides in the new Routes components, in order to avoid multiple ways of adding the same config.
  • canHandleRoute will also take a list of UIs
  • We can remove disableDefaultUI from the email verification config, but other recipes use this on a per-feature basis (e.g.: disable only signInUp instead of all pre-built routes).

Pros and Cons of the Options#

Add recipeIds into input of getRoutingComponent#

  • Could work with really smart bundlers
  • Less interface change
  • The recipes need to be listed in two places
  • For most bundlers, this will import all recipes ui components instead of just the required ones
  • function App() {
    return (
    <SuperTokensWrapper>
    <EmailVerificationComponentsOverrideProvider
    components={{
    EmailVerificationSendVerifyEmail_Override: () => <OtpScreen />,
    }}>
    <div className="App">
    <Router>
    <Routes>
    {getSuperTokensRoutesForReactRouterDom(require("react-router-dom"), [EmailPassword.recipeId])}
    <Route
    path="/"
    element={
    <SessionAuth>
    <Home />
    </SessionAuth>
    }
    />
    </Routes>
    </Router>
    </div>
    </EmailVerificationComponentsOverrideProvider>
    </SuperTokensWrapper>
    );
    }

    Add separate components for the pre-built UI of each recipe#

    important

    This was scrapped, because react-router-dom v6 requires you to add the route components as direct children of <Routes>

  • Should work with all bundlers
  • Interface feels native to react
  • Adding a `componentOverrides` prop would replace the separate override provider component in most (but not all) cases
  • The interface changes a lot
  • The recipes have to be listed in two places
  • `canHandleRoute` and `getRoutingComponent` will have to be recipe specific as well
  • With react-router-dom:

    function App() {
    return (
    <SuperTokensWrapper>
    <EmailVerificationComponentsOverrideProvider
    components={{
    EmailVerificationSendVerifyEmail_Override: () => <OtpScreen />,
    }}>
    <div className="App">
    <Router>
    <Routes>
    <EmailPasswordPreBuiltUIRoutes router={require("react-router-dom")} />
    <EmailVerificationPreBuiltUIRoutes router={require("react-router-dom")} />
    <Route
    path="/"
    element={
    <SessionAuth>
    <Home />
    </SessionAuth>
    }
    />
    </Routes>
    </Router>
    </div>
    </EmailVerificationComponentsOverrideProvider>
    </SuperTokensWrapper>
    );
    }

    With no react-router-dom:

    class App extends React.Component {
    render() {
    // We could handle looping through these for the user but I don't think this is an issue.
    if (EmailPasswordPreBuiltUI.canHandleRoute()) {
    return EmailPasswordPreBuiltUI.getRoutingComponent();
    }

    if (EmailVerificationPreBuiltUI.canHandleRoute()) {
    return (
    <EmailVerificationComponentsOverrideProvider
    components={{
    EmailVerificationSendVerifyEmail_Override: () => <OtpScreen />,
    }}>
    {EmailVerificationPreBuiltUI.getRoutingComponent()}
    </EmailVerificationComponentsOverrideProvider>
    );
    }

    return <SuperTokensWrapper>{/*Your app*/}</SuperTokensWrapper>;
    }
    }

    Add recipe specific UI classes into input of getRoutingComponent#

  • Should work with all bundlers
  • Less interface change
  • The recipes have to be listed in two places
  • With react-router-dom:

    function App() {
    return (
    <SuperTokensWrapper>
    <EmailVerificationComponentsOverrideProvider
    components={{
    EmailVerificationSendVerifyEmail_Override: () => <OtpScreen />,
    }}>
    <div className="App">
    <Router>
    <Routes>
    {getSuperTokensRoutesForReactRouterDom(reactRouterDom, [EmailPasswordPreBuiltUIRoutes, EmailVerificationPreBuiltUIRoutes])}
    <Route
    path="/"
    element={
    <SessionAuth>
    <Home />
    </SessionAuth>
    }
    />
    </Routes>
    </Router>
    </div>
    </EmailVerificationComponentsOverrideProvider>
    </SuperTokensWrapper>
    );
    }

    With no react-router-dom:

    class App extends React.Component {
    render() {
    // We could handle looping through these for the user but I don't think this is an issue.
    if (canHandleRoute([EmailPasswordPreBuiltUI])) {
    return getRoutingComponent([EmailPasswordPreBuiltUI]);
    }

    if (canHandleRoute([EmailPasswordPreBuiltUI])) {
    return (
    <EmailVerificationComponentsOverrideProvider
    components={{
    EmailVerificationSendVerifyEmail_Override: () => <OtpScreen />,
    }}>
    {getRoutingComponent([EmailPasswordPreBuiltUI])}
    </EmailVerificationComponentsOverrideProvider>
    );
    }

    return <SuperTokensWrapper>{/*Your app*/}</SuperTokensWrapper>;
    }
    }