Evershop view system
The view is one of the most important parts of a web application. It is the part that the user interacts with.
Evershop makes use of React to render the view. The page will be rendered on the server side and then sent to the client side. The client side does the Hydration process and make the page interactive.
The EverShop view system was designed to be flexible and easy to extend. Third party developers can insert their own React components into the view system without having to modify the core code.
The View
Multi page application
The EverShop is a multi page application. Each page has its own layout and components. The build process will generate a bundle file for each page. The bundle file will contain the HTML markup and the JavaScript code to render the page.
Server-Side Rendering And Hydration
The EverShop follows the server-side-rendering approach. The page will be rendered on the server side and sent to the client along with some JavaScript code. The client side will do the Hydration process to make the page fully interactive.
Dynamic layout
Evershop layout was designed to be flexible and easy to extend. Third party developers can insert their own React components into the layout without having to modify the core code. Check the bellow section to understand more about how to extend the layout.
Compared to a client-side Single-Page Application (SPA), the advantage of SSR primarily lies in:
-
Faster time-to-content: this is more prominent on slow internet or slow devices. Server-rendered markup doesn't need to wait until all JavaScript has been downloaded and executed to be displayed, so your user will see a fully-rendered page sooner. In addition, data fetching is done on the server-side for the initial visit, which likely has a faster connection to your database than the client. This generally results in improved Core Web Vitals metrics, better user experience, and can be critical for applications where time-to-content is directly associated with conversion rate.
-
Unified mental model: you get to use the same language and the same declarative, component-oriented mental model for developing your entire app, instead of jumping back and forth between a backend templating system and a frontend framework.
-
Better SEO: the search engine crawlers will directly see the fully rendered page.
Fast Refresh
The EverShop implements Fast Refresh. This feature helps to improve the developer experience and performance. This feature is only available in the development mode.
The Module View
Please check this document to understand the structure of EverShop module.
Every module in EverShop has a pages
folder. This folder contains all of the React components that are used to render a page. The pages
folder has the following structure:
Let's take an example of the catalog
module:
catalog
├── api
├── pages
├── admin
│ └── productEdit
│ ├── route.json
│ ├── index.js
│ ├── General.jsx
│ ├── Images.jsx
│ ├── Price.jsx
└── frontStore
└── productView
├── route.json
├── index.js
├── ProductImages.jsx
├── ProductInfo.jsx
├── ProductOptions.jsx
The pages
folder has 3 sub-folders: admin
, frontStore
and global
. The admin
folder contains all of admin panel pages. The frontStore
folder contains pages for your store front. The global
folder contains middleware function that are used in both admin panel and store front.
Master components and page
Let's take a look again the catalog
module:
catalog
├── api
├── pages
├── admin
│ └── productEdit
│ ├── route.json
│ ├── index.js
│ ├── General.jsx
│ ├── Images.jsx
│ └── Price.jsx
└── frontStore
├── categoryView
│ ├── route.json
│ ├── index.js
│ ├── CategoryInfo.jsx
│ └── CategoryProducts.jsx
└── productView
├── route.json
├── index.js
├── ProductImages.jsx
├── ProductInfo.jsx
└── ProductOptions.jsx
In the above example, there are 3 pages: productEdit
, categoryView
and productView
.
The productEdit
is a admin panel page used to edit a product. The categoryView
and productView
are store front pages.
productEdit
, categoryView
and productView
are route Id of the corresponding pages. The detail of the route(HTTP method, path) is defined in the route.json
file. Check this document for more information.
The index.js
file is a middleware function that will be called when the page is requested. You can add however many middleware functions you want to the page folder. The middleware functions will be executed in the order they are defined. Check this document for more information.
To distinguish between a component and a middleware, the component file name must start with a capital letter. For example, General.js
is a component and the middleware file name muse start with a lower case. index.js
is a middleware.
Every of master component must be provided as a default export.
Shared master components
Sometime, you may want to share a component between multiple pages. Let's say you have a ProductInfo
component that is used in both productNew
and productEdit
pages. You can create a folder named productNew + productEdit
in the admin
folder and put the ProductInfo.js
component in it. The productNew + productEdit
folder is a shared folder. The ProductInfo.js
component will be available in both productNew
and productEdit
pages.
catalog
├── pages
├── admin
│ └── productNew+productEdit
│ └── ProductInfo.jsx
└── frontStore
The Area
Component
Let's take a look at the following layout:
Each of the block at the above layout is an Area
and it has a unique ID.
The Area
is a React Higher-Order component(HOC) that takes components as its child. It will render the child components and pass the Area
's props to the child components.
If a block is rendered by an Area component, third party developers can insert their own React components into the block without modifying the core code. That make the view system flexible and easy to extend.
Using Area component:
Let's take a look at the following code:
import React from 'react';
import Area from '@evershop/evershop/src/lib/components/Area';
export default function Layout() {
return (
<div className="just-a-block">
<Area id="blockId" />
</div>
);
}
In the above code, we declare a Area
with the ID# blockId
. The Area
will render all of the child components that have the areaId = blockId
.
You can also provide a list of pre-defined components to the Area
component:
import React from 'react';
import Area from '@evershop/evershop/src/lib/components/Area';
import Top from './Top';
import Bottom from './Bottom';
export default function Layout() {
return (
<div className="just-a-block">
<Area
id="blockId"
coreComponents={
[
{
component: { default: () => <Top />},
props: {
title: 'Top',
},
sortOrder: 1
},
{
component: { default: () => Bottom },
props: {
title: 'Bottom',
},
sortOrder: 2
},
]
}
/>
</div>
);
}
The Area
component will render its child components in order of sortOrder
.
Injecting components into an Area
Let's say we have a page 'productView' with the bellow layout component:
import React from 'react';
import Area from '@evershop/evershop/src/lib/components/Area';
export default function Layout() {
return (
<div className="just-a-block">
<Area id="productViewLeft" />
<Area id="productViewRight" />
</div>
);
}
Now we want to insert a component into the left side of the product view page to show the product rating. We can create a new component named ProductRating.js
:
import React from 'react';
import Area from '@evershop/evershop/src/lib/components/Area';
export default function ProductRating({stars}) {
return (
<div className="just-a-block">
<Star stars = {stars} />
</div>
);
}
export const layout = {
areaId: 'productViewLeft',
sortOrder: 1
}
Then we need to export the layout
object from the ProductRating.js
component. The layout
object is used to tell the system where to insert the component into the page.
In above code, we export a layout
object with the areaId
and sortOrder
properties. The areaId
is the ID of the Area
component that we want to insert the component into. The sortOrder
is the order of the component in the Area
component.
That's it. Now we can insert the ProductRating
component into the productView
page.
The component data fetching
Check this document for more information about how to fetch data in the component.