Let's create a Clean React Js Project with Typescript And Mongez Part II: Project Structure
Hasan Zohdy
Posted on September 2, 2022
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:
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=
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 inpublic/index.html
file. -
REACT_APP_DESCRIPTION
: will be added as the project meta description inpublic/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 thesrc/shared/config.ts
file. -
REACT_APP_DEFAULT_LOCALE_CODE
: Default application locale code, will be added in the html tag aslang
attribute inpublic/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 asdir
attribute inpublic/index.html
. -
REACT_APP_PRIMARY_COLOR
: Primary Color for the app, will update the metatheme-color
inpublic/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 oneslintrc.json
configurations. -
fix
: will run the eslint to fix errors as could as possible based oneslintrc.json
configurations. -
format
: will run the prettier to properly format the files based onprettierrc.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';
After:
import BaseButton from 'design-system/components/Button';
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:
the src directory contains two important directories and one file:
-
apps
: which contains all our project apps, i.efront-office
to the website and we can addadmin
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,
});
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;
}
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';
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);
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
-
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]);
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`
In our next article, we'll talk about the the apps structure and the modules structure.
Stay tuned...
Posted on September 2, 2022
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.