In this chapter, you will learn about the entry convention in Modern.js and how to customize it.
Entry refers to the starting module of a page.
In a Modern.js project, each entry corresponds to an independent page and a server-side route. By default, Modern.js automatically determines the entry of a page based on directory conventions, but also supports customizing the entry through configuration options.
Many configuration options provided by Modern.js are divided by entry, such as page title, HTML template, page meta information, whether to enable SSR/SSG, server-side routing rules, etc. If you want to learn more about the technical details of entries, please refer to the In-Depth section.
The project initialized by Modern.js is a single entry project, with the following structure:
In a Modern.js project, you can easily switch from single entry to multiple entries by running pnpm run new
in the project directory and creating an entry:
After running the command, Modern.js will automatically generate a new entry directory. At this point, you can see that the src/
directory has the following structure:
The original entry code has been moved to a directory with the same name as the name
field in package.json
, and a new-entry
entry directory has been created.
Modern.js will use the entry with the same name as the name
field in package.json
as the main entry. The route of the main entry is /
, and the route of other entries is /{entryName}
.
You can run pnpm run dev
to start the development server. At this point, you will see a new route named /new-entry
added, and the existing page routes remain unchanged.
The concepts of single entry/multiple entry and SPA/MPA are not equivalent. The former pertains to how to configure and package the application, while the latter is about the patterns for organizing front-end applications. Each entry point can be either an SPA or a non-SPA.
Different entry types have different compilation and runtime behaviors.
By default, Modern.js scans the files under src/
before starting the project, identifies the entry, and generates the corresponding server-side route.
The entry directory must meet one of the following three conditions:
routes/
directory.App.[jt]sx?
file.entry.[jt]sx?
file.(Requires source.enableCustomEntry to be enabled)When the src/
directory meets the conditions of an entry, Modern.js will consider the current application to be a single-entry application. Otherwise, Modern.js will scan the first-level directories under src/
and further determine if they are entries. In this case, the application is typically a multi-entry application.
In a single entry application, the default entry name is main
.
Framework mode refers to using Modern.js's framework capabilities, such as convention routing, SSR (Server-Side Rendering), and integrated calls. Under this type of entry convention, the entries in the application are not the actual compilation entries. Modern.js will generate a wrapped entry during startup, which you can find in node_modules/.modern/[entryName]/index.js
.
If there is a routes/
directory within the entry, we refer to this entry as a convention-based route. Modern.js will scan the files under routes/
during startup and automatically generate client-side routes (react-router) based on file conventions. For example:
In the above directory, the component exported in layout.tsx
will be the outermost component, and the component exported in page.tsx
will be the component of the /
route.
For more information, please refer to Conventional Routing.
If there is an App.[jt]sx?
file within the entry, we refer to this entry as a self-controlled route. For example:
For entry points defined as src/App.tsx
, Modern.js does not perform any additional routing operations. Developers can use the React Router 6 API for development, define client-side routes or not to set any client-side routes.
for example, define client-side routes in application:
We recommend that developers use conventional routing. Modern.js provides a series of optimizations in resource loading and rendering for conventional routing by default and offers built-in SSR capabilities. When using manual routing, these capabilities need to be encapsulated by developers themselves.
Using this features requires enabling source.enableCustomEntry.
By default, whether you use convention routing or self-controlled routing, Modern.js will automatically handle rendering. If you wish to customize this behavior, you can creating a custom entry file.
If there is an entry.[jt]sx
file within the entry, Modern.js will no longer control the application's rendering process. You can call the createRoot
and render
functions within the entry.[jt]sx
file to complete the entry logic for your application.
In the code above, the component returned by the createRoot
function is either the component generated from the routes/
directory or the component exported by App.tsx
.
The render
function is used to handle rendering and mounting of the component. For example, if you want to execute some asynchronous tasks before rendering, you can achieve it like this:
Using this features requires enabling source.enableCustomEntry.
Build mode refers to the development mode that does not use Modern.js's runtime capabilities and only utilizes Modern.js's build capabilities. When the @modern-js/runtime
dependency is not installed in the application, Modern.js will treat all entries as build mode entries.
In this case, if there is an entry.[jt]sx
file within the entry, this file will be recognized as the build entry for webpack or Rspack. Modern.js will not automatically generate entry code at this time, and you need to mount the component to the DOM node yourself. For example:
In build mode, the application will not be able to use Modern.js's runtime capabilities, such as:
Convention routing, the routing based on the files under src/routes
Server-Side Rendering (SSR)
The runtime
configuration in the modern.config.js
file will no longer take effect
In some cases, you may need to customize the entry configuration instead of using the entry conventions provided by Modern.js.
For example, if you want to migrate a non-Modern.js project to Modern.js and it is not structured according to Modern.js directory structure, there might be some migration costs involved in changing it to the conventional structure. In such cases, you can custom the entries.
Modern.js provides the following configuration options that you can set in modern.config.ts:
Here is an example of a custom entry point. You can also refer to the documentation of the corresponding configuration options for more usage.
It is worth noting that, by default, Modern.js considers entries specified through the configuration as framework mode entries and will automatically generate the actual compilation entry.
If your application is migrating from build tools like Webpack or Vite to the Modern.js framework, you typically need to enable the disableMount
option in the entry configuration. In this case, Modern.js will treat the entry as a build mode entry.
The concept of page entry is derived from the concept of Entrypoint in webpack. It is mainly used to configure the JavaScript or any other modules to be executed during the application startup. Webpack usually corresponds each entry to an HTML file in the output. The modules imported by the entry will be bundled and split into multiple chunks in the output. For a JavaScript module, it might be compiled into several chunks like dist/static/js/index.ea39u8.js
.
Here's a summary of the differences between the concepts of entry and route:
react-router
, determining which React component to load and render based on the browser's current URL using the History API.Their relationships are as follows:
react-router
and @tanstack/react-router
in the same page).react-router
defined client route generate a separate HTML file?No. Each entry usually only generates one HTML file, and if a single entry contains multiple client routing systems, it will share the same HTML file.
routes/
directory generate multiple HTML files?No. Modern.js will scan the routes/
directory during startup and automatically generate client-side routes based on the file conventions. The HTML file generated corresponds to the routes/
directory.
A Server Side Rendering (SSR) project does not necessarily need to generate an HTML file in the output. It can only include the server-side JavaScript output. At this point, the react-router
routing will be executed on the server side, and the HTML content will be rendered and responded while a request is triggered.
At the same time, Modern.js will also generate a complete client-side HTML file for each entry in the output, which can be used to fallback to client-side rendering when the SSR fails.
Another special case is a Single Entry Static Site Generation (SSG) project, even if it is built with a convention routing, Modern.js will also generate an HTML file for each page.tsx
file.
Note that even if SSR is used, React still needs to go through the hydration phase, so the routing defined by react-router
will still be executed on the client side.
You can configure html-rspack-plugin to generate multiple HTML files for each entry, or let multiple entries share the same HTML file.
The "page" in a Multi-Page Application (MPA) refers to a static HTML file.
Generally, any application that outputs multiple entries and multiple HTML files can be called a Multi-Page Application.
Narrowly speaking, a Multi-Page Application does not contain client-side routing, and navigation between pages is usually achieved through elements like <a>
tags. But in practice, Multi-Page Applications also often need to configure client-side routing to meet different needs.
Conversely, a application with react-router
defined routes that generates only one HTML file is called a Single-Page Application (SPA).
Currently, if the entry directory meets the following conditions, it will also be considered an application entry:
index.[jt]sx?
file.pages/
directory.The pages/
directory was the convention routing in older versions of Modern.js. Now, it is recommended to use the routes/
directory.
The index.[jt]sx?
file supported Custom Bootstrap and Build Mode Entry in older versions. Now, it is recommended to use entry.[jt]sx?
instead.
When there is an index.[jt]sx
file in the entry, and the file's default export is a function, Modern.js will pass the default bootstrap
function as an argument and use the exported function to replace the default bootstrap
.
This allows developers to customize mounting components to DOM or add custom behaviors before mounting. For example:
When an index.[jt]sx
file exists in the entry directory and does not export a function via export default, this entry will also be considered a build mode entry.