logo
  • Guide
  • Config
  • Plugin
  • API
  • Examples
  • Community
  • Modern.js 2.x Docs
  • English
    • 简体中文
    • English
    • Start
      Introduction
      Quick Start
      Upgrading
      Glossary
      Tech Stack
      Core Concept
      Page Entry
      Build Engine
      Web Server
      Basic Features
      Routes
      Routing
      Config Routes
      Data Solution
      Data Fetching
      Data Writing
      Data Caching
      Rendering
      Server-Side Rendering
      Streaming SSR
      Rendering Cache
      Static Site Generation
      Render Preprocessing
      Styling
      Styling
      Use CSS Modules
      Using CSS-in-JS
      Using Tailwind CSS
      HTML Template
      Import Static Assets
      Import JSON Files
      Import SVG Assets
      Import Wasm Assets
      Debug
      Data Mocking
      Network Proxy
      Using Rsdoctor
      Using Storybook
      Testing
      Playwright
      Vitest
      Jest
      Cypress
      Path Alias
      Environment Variables
      Output Files
      Deploy Application
      Advanced Features
      Using Rspack
      Using BFF
      Basic Usage
      Runtime Framework
      Extend BFF Server
      Extend Request SDK
      File Upload
      Cross-Project Invocation
      Optimize Page Performance
      Code Splitting
      Inline Static Assets
      Bundle Size Optimization
      React Compiler
      Improve Build Performance
      Browser Compatibility
      Low-Level Tools
      Source Code Build Mode
      Server Monitor
      Monitors
      Logs Events
      Metrics Events
      Internationalization
      Basic Concepts
      Quick Start
      Configuration
      Locale Detection
      Resource Loading
      Routing Integration
      API Reference
      Advanced Usage
      Best Practices
      Custom Web Server
      Topic Detail
      Module Federation
      Introduction
      Getting Started
      Application-Level Modules
      Server-Side Rendering
      Deployment
      Integrating Internationalization
      FAQ
      Dependencies FAQ
      CLI FAQ
      Build FAQ
      HMR FAQ
      Deprecated
      📝 Edit this page
      Previous pageUsing Tailwind CSSNext pageImport Static Assets

      #HTML Template

      Modern.js provides JSX syntax and HTML(EJS) syntax to customize the HTML template.

      #JSX Syntax

      According to Modern.js conventions, you can create a Document.[jt]sx file under src/ or the entry directory and default export a component. The rendering result of this component can be used as the HTML template of the entry.

      For example, consider the following directory structure:

      .
      └── src
          ├── Document.tsx
          ├── entry-a
          │   ├── Document.tsx
          │   └── routes
          ├── entry-b
          │    └── routes
          └── modern-app-env.d.ts

      entry-a will use the Document.[jt]sx file under the current entry as the template. If there is no Document.[jt]sx file under the current entry, like entry-b, it will look for the Document.[jt]sx file under the root directory.

      If not found, default template will be used.

      Tip

      The Document.[jt]sx module will be compiled by esbuild and rendered to a string as the HTML template content, similar to Static Site Generation. The HTML template module will not be compiled by the Bundler. The React Hooks in the component also will not be executed at browser runtime, and JavaScript resources such as images cannot be resolved and imported.

      #HTML Components

      Modern.js provides some components for rendering pages to help developers generate templates. These components can be used from @modern-js/runtime/document:

      import { Html, Body, Root, Head, Scripts } from '@modern-js/runtime/document';
      • Html: provide the ability of native HTML Element and and render necessary components that the developer did not add by default. <Head> and <Body> must exist, and other components can be assembled as needed.

      • Body: provide the ability of native Body Element and needs to contain the <Root> component internally. It also supports other elements as child elements at the same time, such as adding footers.

      • Root: the root node <div id='root'></div> to be rendered. The default id of the root node is id = 'root'. You can set props.rootId to change the id attribute. Child components can be added and will be rendered in the HTML template. After React rendering is complete, it will be overwritten and is generally used to implement global Loading.

      • Head: provide the ability of native Head Element and automatically fills in <meta> and <Scripts> components.

      • Scripts: Used to control the placement of the <script> tags generated by the build. By default, they are placed within the <Head> component.

      • Comment: retain user-written comments like <!-- gateway --> and outputs them to the rendered HTML.

      #Template Parameters

      Because it is in JSX format, various variables can be used freely in the component to assign values to various custom components in Document.[jt]sx.

      Modern.js also provides DocumentContext to provide some configuration and environment parameters for easy access. The main parameters are:

      • processEnv: provides the process.env during the build.
      • config: the configuration of the Modern.js project. Currently, only the output configuration is exposed.
      • entryName: the current entry name.
      • templateParams: parameters of HTML template (compatible with traditional templates, so it's not recommended for use).

      #Basic Example

      import React, { useContext } from 'react';
      import {
        Html,
        Root,
        Head,
        Body,
        Comment,
        DocumentContext,
      } from '@modern-js/runtime/document';
      
      export default function Document(): React.ReactElement {
        // the params provide by DocumentContext
        const {
          config: { output: htmlConfig },
          entryName,
          templateParams,
        } = useContext(DocumentContext);
      
        return (
          <Html>
            <Head>
              <link href="https://modernjs.dev" />
              <Comment>{'<!-- Need a Comment -->'}</Comment>
            </Head>
            <Body>
              <Root rootId="root">
                <h1 style={{ color: 'red' }}>Some Params: </h1>
                <h2>entryName: {entryName}</h2>
                <h2>title: {htmlConfig.title}</h2>
                <h2>rootId: {templateParams.mountId}</h2>
              </Root>
              <h1>bottom</h1>
            </Body>
          </Html>
        );
      }

      The above JSX components will generate the following HTML template:

      <!DOCTYPE html>
      <html>
        <head>
          <meta charset="utf-8" />
          <meta
            name="viewport"
            content="width=device-width, initial-scale=1.0, shrink-to-fit=no, viewport-fit=cover, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no"
          />
          <meta http-equiv="x-ua-compatible" content="ie=edge" />
          <meta name="renderer" content="webkit" />
          <meta name="layoutmode" content="standard" />
          <meta name="imagemode" content="force" />
          <meta name="wap-font-scale" content="no" />
          <meta name="format-detection" content="telephone=no" />
          <link rel="icon" href="/a.icon" />
          <script defer src="/static/js/builder-runtime.js"></script>
          <script defer src="/static/js/lib-react.js"></script>
          <script defer src="/static/js/lib-polyfill.js"></script>
          <script defer src="/static/js/lib-router.js"></script>
          <script defer src="/static/js/main.js"></script>
          <link href="https://modernjs.dev" />
          <!-- Need a Comment -->
        </head>
      
        <body>
          <div id="root">
            <!--<?- html ?>-->
            <h1 style="color:red">Some Params:</h1>
            <h2>entryName: main</h2>
            <h2>title:</h2>
            <h2>rootId: root</h2>
          </div>
          <h1>bottom</h1>
          <!--<?- chunksMap.js ?>-->
          <!--<?- SSRDataScript ?>-->
        </body>
      </html>

      #Scripts Component Example

      You can use the <Scripts> component to insert the <script> tags generated by the build inside the <body> tag:

      import React from 'react';
      import { Html, Root, Head, Body, Scripts } from '@modern-js/runtime/document';
      
      export default function Document(): React.ReactElement {
        return (
          <Html>
            <Head></Head>
            <Body>
              <Root rootId="root"></Root>
              <Scripts />
            </Body>
          </Html>
        );
      }

      #HTML Syntax

      Modern.js also supports generating HTML files using HTML (EJS) syntax.

      By default, Modern.js projects come with a built-in HTML template for generating HTML code. If you need to customize the HTML template, you can use two methods: Custom HTML Fragments and Fully Custom HTML Templates.

      #Custom HTML Fragments

      Under the application root directory, create the config/html/ directory, which supports the creation of four types of HTML fragments:

      • top.html
      • head.html
      • body.html
      • bottom.html

      These fragments will be injected into the default HTML template according to their positions.

      <!DOCTYPE html>
      <html>
        <head>
          <%= topTemplate %>
          <%= headTemplate %>
          {/* webpack inject css  */}
        </head>
        <body>
          <noscript>
            We're sorry but react app doesn't work properly without JavaScript
            enabled. Please enable it to continue.
          </noscript>
          <div id="<%= mountId %>"></div>
          <%= bodyTemplate %>
          {/* webpack inject js  */}
          {/* <?- bottomTemplate ?> */}
        </body>
      </html>

      HTML fragments support the use of Lodash template.

      For example, to insert an external script in body.html:

      config/html/body.html
      <script src="//example.com/assets/a.js"></script>
      Info

      The implementation of custom HTML fragments is to merge the fragments with the built-in template. Since the <title> already exists in the default template, the title tag in the custom HTML template will not take effect. Please use html.title to modify the page title.

      #Customize the entire HTML Template

      In some cases, HTML fragments may not offer enough control. Modern.js provides a fully customized way.

      Note

      It is generally not recommended to directly override the default HTML template, as some functional options may be lost. If it is truly necessary to customize the entire HTML template, it is recommended to modify based on the built-in template as needed.

      Under the config/html/ directory, create an index.html file that will replace the default HTML template.

      Info

      The default HTML template can be viewed in node_modules/.modern-js/${entryName}/index.html.

      #Template Parameters

      The parameters used in the template can be defined by the html.templateParameters configuration.

      #Config By Entry

      The HTML fragments in the config/html/ directory take effect for all entries in the application. If you want to customize HTML fragments by entry, you can create a directory named after the entry name under the config/html/ directory, and then customize the HTML fragments in this directory.

      For example, the following HTML fragments are only effective for the entry1 entry:

      .
      ├── config/
      │   └── html/
      │       └── entry1
      │           ├── head.html
      │           └── body.html
      └── src/
          ├── entry1/
          │   └── routes
          └── entry2/
              └── routes