DEV Community 👩‍💻👨‍💻

Hasan Zohdy
Hasan Zohdy

Posted on • Updated on

Let's create a Clean React Js Project with Typescript And Mongez Part II: Project Structure

Let's continue with part two of the React Mongez app series with the project structure.

The Project Structure

Once you open the editor, you'll see the following structure:

Image description

Let's go with the structure and the important files/directories.

Dot Env Files

You'll notice there are two .env files, .env and .env.production, the purpose behind this is to separate the development configurations from the production configurations so you won't have to change the .env file each time you make a new build

For now the two files have the same content, but we 'll talk about .env.production in the production section, so let's see the .env file

# Disable ESlint error
ESLINT_NO_DEV_ERRORS=true

# App Name
REACT_APP_NAME="blog"

# App Description
REACT_APP_DESCRIPTION=

# App Code Name
REACT_APP_CODE_NAME="b"

# Branch Name
REACT_APP_BRANCH_NAME="main"

# App default locale code
REACT_APP_DEFAULT_LOCALE_CODE=en

# App Fallback locale code
REACT_APP_FALLBACK_LOCALE_CODE=en

# App default direction
REACT_APP_DEFAULT_DIRECTION=ltr

# App Primary Color
REACT_APP_PRIMARY_COLOR=#000

# App API URL
REACT_APP_API_URL=

# App API Key
REACT_APP_API_KEY=
Enter fullscreen mode Exit fullscreen mode

Let's go through the file properties quickly:

  • ESLINT_NO_DEV_ERRORS: will disable the unnecessary eslint errors that keeps popped up in the browser.
  • REACT_APP_NAME: will be added as the project title by default in public/index.html file.
  • REACT_APP_DESCRIPTION: will be added as the project meta description in public/index.html file.
  • REACT_APP_CODE_NAME: Useful for caching prefixes and encryption keys.
  • REACT_APP_BRANCH_NAME: can be used to distinguish between branches in the cache prefix, will be discussed later when we reach the src/shared/config.ts file.
  • REACT_APP_DEFAULT_LOCALE_CODE: Default application locale code, will be added in the html tag as lang attribute in public/index.html
  • REACT_APP_FALLBACK_LOCALE_CODE: Fallback language when a translation key is missing from language so it will search in the fallback language keywords list. REACT_APP_DEFAULT_DIRECTION: Default direction, will be added in html tag as dir attribute in public/index.html.
  • REACT_APP_PRIMARY_COLOR: Primary Color for the app, will update the meta theme-color in public/index.html file.
  • REACT_APP_API_URL: Define the API Base Url.
  • REACT_APP_API_KEY: Define the Api Authorization Key.

Package.json File

In the package.json file we will look into sections, scripts and _moduleAliases

Scripts have some quite interesting commands other than the normal ones:

  • build:prod: will make a build for production using .env.production settings instead of .env file.
  • postinstall: will remake the aliases after each install.
  • dev: can be used to make your application's packages up to date then start the project.
  • update: will run npm-check-updates command to update the project packages to latest updates.
  • lint: Run the eslint command to check for errors based on eslintrc.json configurations.
  • fix: will run the eslint to fix errors as could as possible based on eslintrc.json configurations.
  • format: will run the prettier to properly format the files based on prettierrc.json configurations.

The second property will be _moduleAliases that stores the paths aliases thanks to link-module-alias.

In nutshell, this will allow us instead of setting the paths as relatives to be absolutes,

Before:

import BaseButton from './../../design-system/components/Button';
Enter fullscreen mode Exit fullscreen mode

After:

import BaseButton from 'design-system/components/Button';
Enter fullscreen mode Exit fullscreen mode

This will make your code neat and if you move your file from directory to another you won't have to update your imports.

What you will usually is design-system which contains your styling components and themeing, app for base project app which is located in src/apps/front-office and user for managing current user (if the application has a user management system).

The src Directory

Now we are done with the outside files, let's dive into the src directory, which will look like:

Mongez React Src Directory

the src directory contains two important directories and one file:

  • apps: which contains all our project apps, i.e front-office to the website and we can add admin app for the admin panel.
  • shared: contains the shared data, files, styles and assets between all apps.
  • index.ts: The application bootstrap file.

src/index.ts file

If we look at the file, it will be something like this:

import startApplication from "@mongez/react";
import "./shared/apps-list";
import "./shared/config";

startApplication({
  debug: true,
});
Enter fullscreen mode Exit fullscreen mode

The startApplication function will be the anchor function to fire up our application, alongside with the apps-list file which defines our apps structure (for lazy loading) and lastly the base configurations file src/shared/config.ts.

These are the available configurations that can be passed to startApplication function.

import { ReportHandler } from "web-vitals";

declare  type ApplicationOptions = {
    /**
     * Determine whether to enable debugging mode or not
     *
     * @default false
     */
    debug?: boolean;
    /**
     * Debug method that is passed to reportWebVitals function
     *
     * @default console.log
     */
    debugMethod?: ReportHandler;
    /**
     * Detect current used device and browser such as google chrome, ipad, tablet and so on
     *
     * @default true
     */
    detectDeviceAndBrowser?: boolean;
    /**
     * Detect Dark Mode based on user's preferences, if found then a `dark` class will be added to body
     *
     * @default true
     */
    detectDarkMode?: boolean;
    /**
     * Determine whether to use the application in strict mode
     *
     * @default true
     */
    strict?: boolean;
}
Enter fullscreen mode Exit fullscreen mode

Keep in mind that the debug feature works with debugMethod which by default is set to web-vitals reporting system, you may of course enable or disable or even change the debugger, totally up to you.

When setting strict to true which defaults to true it will wrap the application in React.StrictMode

If detectDarkMode is enabled, the dark class will be appended to html tag.

By default Mongez React will try to detect the browser name and the device type, so you may see classes like chrome desktop dark in the html tag.

The Shared directory

Mainly this folder contains two files and one directory config.ts apps-list.ts and assets directory, let's go quickly over it.

We can import any file from it using its direct alias shared/file-path-to-import for example to import the config file.

import 'shared/config'; 
Enter fullscreen mode Exit fullscreen mode

src/shared/config.ts file

It will contain the main application configurations that can be used with any sub application from src/apps apps, it looks like:

import { EncryptedLocalStorageDriver } from "@mongez/cache";
import { ApplicationConfigurations, setAppConfigurations } from "@mongez/react";
import uk from "assets/images/flags/uk.png";
import AES from "crypto-js/aes";
import Root from "design-system/layouts/Root";

const appConfigurations: ApplicationConfigurations = {
  localization: {
    defaultLocaleCode: process.env.REACT_APP_DEFAULT_LOCALE_CODE,
    fallback: process.env.REACT_APP_FALLBACK_LOCALE_CODE,
    locales: {
      en: {
        direction: "ltr",
        name: "English",
        flag: uk, // optional
      },
    },
  },
  encryption: {
    key: process.env.REACT_APP_CODE_NAME,
    driver: AES,
  },
  cache: {
    // make the cache prefix with the app code name, append the branch name (if exists)
    prefix:
      process.env.REACT_APP_CODE_NAME +
      ((process.env.NODE_ENV === "development" &&
        process.env.REACT_APP_BRANCH_NAME) ||
        ""),
    driver: new EncryptedLocalStorageDriver(),
  },
  helmet: {
    appName: process.env.REACT_APP_NAME,
    appendAppName: true,
    appNameSeparator: " | ",
    translatable: true,
    translateAppName: true,
  },
  router: {
    // used for production
    basePath: process.env.REACT_APP_PRODUCTION_BASE_PATH,
    notFound: {
      mode: "redirect",
      route: "/404",
    },
    // to set a preloader between the router navigation, pass it to the `preloader` property
    // preloader: Preloader,
    // will wrap the entire application
    rootComponent: Root,
  },
  endpoint: {
    // will convert any PUT request to a POST request with a body of the form: and append _method=PUT to the body
    // whether the request body is object, FormElement or FormData
    putToPost: true,
    baseUrl: process.env.REACT_APP_API_URL,
    apiKey: process.env.REACT_APP_API_KEY,
  },
};

setAppConfigurations(appConfigurations);
Enter fullscreen mode Exit fullscreen mode

Before we go down to what are these configurations and their usage, the setAppConfigurations uses Mongez Config under the hood to manage the configurations between the other packages.

You can also add any configurations to the configurations list which can be used using config.get('your.object.key')

Let's split it down int categories to illustrate what's going on in this file

  1. localization Category

Which sets Mongez Localization configurations for translation

  • defaultLocaleCode: defines the default locale code for translation.
  • fallback: defines the fallback locale code that will be used if the keyword doesn't exist in the current locale code.
  • locales: contains the localization settings such as the locale code, direction and flag (optional but can be useful if you're having a multilingual application to display the locale name with its flag).

The direction is important as Mongez React uses it to update the application direction.

encryption: Category

It defines the Encryption Configurations, we defines the encryption key for encrypting and decrypting data and the encryption driver which is AES from Crypto JS

cache Category

which is also known as Local Storage, we provide a prefix key for all cached items and the cache driver which is Encryption local storage (Requires encryption settings that we mentioned).

The prefix key is a useful way to separate each project local storage keys without the need to clean it every time we start developing a project, so each project has its own prefix so do the local storage keys.

The cache driver sets the default cache handler that will be used later with the cache manager instance among the application runtime.

helmet Category

It defines the Helmet Configurations, self explained but we will go deeper inside it when we react the Home page.

router Category

It defines the Router Configurations.

endpoint Category

It defines the Http Configurations.

  • we set the api base url and the api key (if needed), the putToPost property will transform any PUT request to POST and append _method=PUT to the request payload, the reason behind this property to allow us uploading files and images as PUT requests do not allow such a request.

src/shared/apps-list.ts file

Here we will define our apps list, oh i forgot to tell you what are the apps list.

Mongez React Router provides a way to split the application code into apps/modules based.

What does that mean?

Let's say we have two apps admin with base route /admin for the admin dashboard and front-office with base route / for the public website.

MRR will build each application module routes inside each app as standalone files, so the files of the admin will not be loaded until you hit /admin route, same applies to front-office main route / and vice versa.

This will deduct the unnecessary loaded contents and decrease the bundle size as long as you don't hit that route.

For more information about the apps and modules i suggest you pay a visit to MRR documentation, we'll re-touch the apps/modules concept again later though.

Back to our apps-list, now we'll define what apps do we have, our apps-list.ts file will look like:

import { setApps } from "@mongez/react-router";
import frontOfficeApp from "apps/front-office/front-office-modules.json";

setApps([frontOfficeApp]);
Enter fullscreen mode Exit fullscreen mode

Not too much to say here we just imported the app module configurations file front-office-modules.json and passed it to setApps which allows the route to know what apps and base paths for each app will be to load the proper module accordingly.

Of course if we want to create another app we'll have to import the app configurations file to setApps function as well.

The assets directory

As mentioned earlier, the assets directory contains our shared images, icons, videos and so on, in other words our application media files.

assets directory has an alias assets to import files quickly from it.

import myLogo from 'assets/images/logo.png'; // equivalent to `src/shared/assets/logo.png`
Enter fullscreen mode Exit fullscreen mode

In our next article, we'll talk about the the apps structure and the modules structure.

Stay tuned...

Top comments (0)

🌚 Life is too short to browse without dark mode