Category Archives: Vite

Auto-discovery using Vite (and React)

I’m messing around with a Shell application in React and wanting to load information from apps/components that are added to the shell dynamically, i.e. via auto-discovery.

Now, we’re using React for this example so we can create React apps using Vite for what we will call, our components, as these can be loaded into React as components. The reason to create these as standalone apps would be for use to develop against.

So let’s assume I have a main application, the Shell app and this can get routes for functionality (our apps/components) which may get added later on in the development process, basically a pluggable type of architecture which just uses React components along with those components supplying routing information to allow us to plug them into the Shell.

To give it more context, I build a Shell application with Search and later on want to add a Document UI, so it’d be nice if the Document can be worked on separately and when ready, deployed to a specific locations where the Shell (upon refresh) can discover the new component and wire into the Shell.

Vite has a feature import.meta.glob which we can use to discover our routes.tsx that are deployed to a specific path, i.e.

const modules = import.meta.glob<Record<string, unknown>>(
  '../../apps/*/src/routes.tsx', { eager: true }
);

This will return keys for the file paths and values being the functions that import from the files or modules. For example it might locate components such as

apps/search/src/routes.tsx
apps/document/src/routes.tsx
apps/export/src/routes.tsx
apps/settings/src/routes.tsx

If eager is missing (or false) then Vite lazy imports the functions and you’d then need to call them yourself, with eager:true, Vite imports the modules immediately.

If we use something like this


import type { RouteObject } from 'react-router-dom';

const modules = import.meta.glob<Record<string, unknown>>(
  '../../apps/*/src/routes.tsx', { eager: true }
);

export const allAppRoutes: RouteObject[] = Object.values(modules)
  .flatMap((mod) => {
    const arr = Object.values(mod).find(
      (v): v is RouteObject[] => Array.isArray(v) && 
        v.every(item => typeof item === 'object' && 
           item !== null && 'path' in item && 'element' in item)
    );
    return arr || [];
  });

Then we could use the routes via the react-router-dom in App.tsx, like this

const baseRoutes = [
  { path: '/', element: <div>Welcome to the Shell</div> },
];

const routes = [
  ...baseRoutes,
  ...allAppRoutes,
];
return (
  <AuthContext.Provider value={auth}>
    <ShellLayout>
      <Suspense fallback={<div>Loading…</div>}>
        <Routes>
          {routes.map(({ path, element }) => (
            <Route key={path} path={path} element={element} />
          ))}
        </Routes>
      </Suspense>
    </ShellLayout>
  </AuthContext.Provider>
);

and finally here’s an example routes.tsx file for our components

import SearchApp from './App';

export const searchRoutes = [
  { path: '/search/*', element: <SearchApp /> },
];

Quick start to creating a React application using Vite

Just noting this process here, but the full instructions can be found at Getting Started.

To create a React application using Vite, simply run

npm create vite@latest my-app -- --template react-ts

Obviously change my-app to your app. name and in this case I’m using the React Typescript template.

Then cd into the app. folder and run the following

npm install
npm run dev