⚠️ WARNING: This repo is now archived. It should only be used as a reference if you want to set up a custom webpack configuration. The practices in this repo may be outdated and you should be cautious when used as a reference. Hipo uses this new CRA template when starting out new projects.
This template includes all the configurations for kick-starting a project with React and TypeScript.
For now, you need to manually copy-paste all the files from the template into your directory. Eventually, there will be a command-line tool that does this for you. After you copied all the files in this template, you will need to take the following steps:
- This project requires Node >= 12.x and npm >= 6.x for proper development environment.
-
Update necessary fields inside
package.jsonfor your projects. -
Go over all the files inside
configfolder and update them with your project's necessities. Here you will find the following configuration files:
apiConfig:Configurations for the API requests in different environments.assetConfig:Paths for the assets in different environmentss3Config:S3 configurations for different environments.sentryConfig:Sentry configurations for different environments.
-
Update
changelog-context-variables.jsonto include your project'scodebaseProjectName. -
Run
npm installto install dependencies. -
Check commented out code for Sentry integration. You will find them inside
index.tsxandNetworkManager.ts. Make sure to checksentryHandler.tsfor correcting integration.
npm startThis will build out the frontend for development environment. It is an alias for npm run build:dev:live. This will use the webpack.dev.config.js file and start out the webpack dev server with local being the target environment. If you want to build in another environment then do npm run build:dev:live -- --env.target=TARGET_ENV where TARGET_ENV may be one of the following: production, staging or local (or preproduction, if you add it). You can simply run npm run build:dev if you don't want to listen for changes.
It is recommended to split your terminal and run npm start in one and npm run type-check:watch in another. npm run type-check offers cleaner output when you have errors from the tsc.
npm run build:release -- --env.target=RELEASE_TARGET --env.awsAccessKeyId=AWS_ACCESS_KEY_ID_FOR_YOUR_TARGET_ENV --env.awsSecretAccessKey=AWS_SECRET_ACCESS_KEY_FOR_YOUR_TARGET_ENVThis will generate /build folder with static files to serve. RELEASE_TARGET may be one of the following: production, staging or local (or preproduction, if you add it). During server deployment (executed by the CI jobs), RELEASE_TARGET is derived by the branch name (currently can be staging, or production).
There is a pre-commit git hook which runs npm run lint; npm run type-check; script when you want to commit your changes. If any of them fails, it won't allow you to commit. You can still force commit by telling git to skip pre-commit, but you shouldn't.
Also, a pre-push git hook which runs npm run test script when you want to push your changes. If any of them fails, it won't allow you to push.
npm run changelogThis will generate a changelog from your commits. Refer to its repo for details.
The template already have protected and public route system. Dig into src/core/route/ to see how it works. There you will find an example of one public route that passes a prop to its component and a lazy loaded protected route.
The template is generated with the token authentication in mind. webStorage and authenticationManager utilities are generated for this purposes. authenticationManager allows you to store or retrieve the token with the help of webStorage. authenticationState is added to the root Redux Store. This state has to have an authenticateProfile key which is used for the functionality behind protectedRoutes. When you authenticate your user in your application, you need to save the user data as the value of authenticateProfile.
The template has a network manager and an api handler utility which needs to be used when making requests with axios. An example for a GET request:
function listBuyerPO(
{projectId, params}: {projectId: string; params?: TBuyerPOListRequestParams},
cancelToken?: CancelToken
) {
return apiHandler<IListResponse<IBuyerPO[]>>(
manufacturitApiManager,
"get",
`/projects/${projectId}/buyer-purchase-orders/`,
{
settings: {
params,
cancelToken
}
}
);
}These functions would usually be inside a file named as, e.g., buyerPOApiHandlers.ts. As you can see apiHandler allows you to type the returned promise. These types would usually be defined inside a file named as, e.g., buyerPOApiModels.ts.
Redux and redux-saga integration is already available with the template. For the asynchronous actions, you can use asyncReduxAutomator tool to speed up the generation of necessary action creators, saga watchers, etc. For example, for the buyer PO list request above you can create a redux namespace object with:
const initialBuyerPOListState = getMinimalAsyncStoreState<IBuyerPO>([]);
const buyerPOListReduxNamespace = {
initialState: initialBuyerPOListState,
...asyncReduxAutomator("listBuyerPO", listBuyerPO, initialBuyerPOListState, "list")
};buyerPOListReduxNamespace will now have initialState, actionTypes, actionCreators, saga, watcher, reducer keys which you can use to integrate into your Redux store.
Note: promisifyAsyncActionsMiddleware is added to Redux to promisify REQUEST_TRIGGER actions.
Note: For the async processes, avoid using Redux and Redux-saga, if possible. Instead, try using useAsync hook. Example usage:
const requestState = useAsync(
{
handlerCreator: accountApi.updateAccount,
argumentGenerator() {
return {
accountId: accountDetail!.id,
payload: generateUpdateAccountPayload(state)
};
}
},
[shouldUpdate, state, accountDetail],
{
shouldMakeRequest() {
return Boolean(shouldUpdate && accountDetail?.id);
},
onSuccess(account) {
setSuccessModalVisibility(true);
},
onFailure(error) {
dispatchFloatingMessage({
type: "DISPLAY",
payload: {
type: "error",
message: generateErrorMessageFromCaughtError(error)
}
});
}
}
);This template utilizes react-modal library for implementing modals. There is a component called Modal that uses react-modal in the background that lets you generate modals easily. An example modal named as ReportModal is generated.
These files should be gathered inside /src/core/declarations/.
npm run testTests can be run by executing the command above. Tests files should be placed right below the original implementation file, see numberUtils for example inside /src/utils/number/.
Group by main modules or routes for the project:
├── config
└── src
└── components <- Where common components of the project are placed
└── button
└── dropdown
└── form
├── core <- Core functionality, routes and root app is here
├── dashboard <- Homepage related stuff
└── home <- Homepage related stuff
├── api
└──homeApiHandlers.ts <- Api handler functions are defined here
└──homeApiModels.ts <- Api models are defined here
├── invester
└── _invester-homepage.scss
└── InvesterHomepage.tsx
└── InvesterHomepage.test.ts
├── advisor
└── _advisor-homepage.scss
└── AdvisorHomepage.tsx
└── AdvisorHomepage.test.ts
├── redux
└── advisor
└── advisorHomeReduxState.ts
└── advisorStatsReduxState.ts
└── investor
└── investorHomeReduxState.ts
└── investorStatsReduxState.ts
└── homeReduxState.ts <- Main `homeState`, its reducer and saga factory are defined here
└── utils
└── homeReduxUtils.ts
└── homeReduxUtils.test.ts
└── utils
└── homeUtils.ts
└── homeUtils.test.ts
NOTE: Avoid a deeply nested structure and don't overthink it.