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
      Rendering Mode Overview
      Server-Side Rendering
      Streaming Server-Side Rendering
      Rendering Cache
      Static Site Generation
      React Server Components (RSC)
      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
      Creating Extensible BFF Functions
      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
      Upgrade
      Overview
      Configuration Changes
      Entry Changes
      Custom Web Server Changes
      Tailwind Plugin Changes
      Other Important Changes
      📝 Edit this page
      Previous pageConfiguration ChangesNext pageCustom Web Server Changes

      #Entry Changes

      This chapter introduces changes related to page entries when upgrading from Modern.js 2.0 to 3.0.

      #Overview

      Modern.js 3.0 has optimized and simplified the entry mechanism. The main changes include:

      • Entry File Naming Change: Custom entry files changed from index.[jt]sx to entry.[jt]sx
      • Bootstrap Function Replacement: Use the new createRoot and render APIs
      • Runtime Configuration Migration: App.config and config exports from routes/layout need to be migrated
      • Initialization Logic Migration: App.init and init exports from routes/layout need to be changed to runtime plugins

      #Entry Type Identification

      Before starting migration, first identify the entry type used in your project.

      #Entry Identification Conditions

      Modern.js scans directories and identifies entries that meet any of the following conditions:

      1. Has a routes/ directory → Convention-based routing entry
      2. Has an App.[jt]sx? file → Self-controlled routing entry
      3. Has an index.[jt]sx? file (2.0) or entry.[jt]sx? file (3.0) → Custom entry

      #Single Entry vs Multiple Entries

      Single Entry Application: Scans the src/ directory by default

      src/
      ├── routes/        # or
      ├── App.tsx        # or
      └── index.tsx      # 2.0 version

      Multiple Entry Application: Scans first-level subdirectories under src/

      src/
      ├── entry1/
      │   └── routes/    # Each subdirectory is an entry
      └── entry2/
          └── App.tsx
      Tip

      You can modify the entry scanning directory through the source.entriesDir configuration.

      #Migration Steps

      The migration operations in this section only need to be performed when the corresponding usage actually exists in the project, such as bootstrap function, App.config/App.init, config/init functions in routes/layout.tsx, etc.

      #1. Custom Entry File Rename

      If your project uses a custom entry file (index.[jt]sx), you need to rename it to entry.[jt]sx.

      2.0 Version:

      src/
      └── index.tsx

      3.0 Version:

      src/
      └── entry.tsx

      #2. Bootstrap Function Migration

      If your entry file exports a function that receives App and bootstrap parameters, you need to use the new API instead.

      2.0 Version:

      src/index.tsx
      export default (App: React.ComponentType, bootstrap: () => void) => {
        // Perform initialization operations
        initSomething().then(() => {
          bootstrap();
        });
      };

      3.0 Version:

      src/entry.tsx
      import { createRoot } from '@modern-js/runtime/react';
      import { render } from '@modern-js/runtime/browser';
      
      // Create root component
      const ModernRoot = createRoot();
      
      // Perform initialization operations
      async function beforeRender() {
        await initSomething();
      }
      
      // Render application
      beforeRender().then(() => {
        render(<ModernRoot />);
      });
      Note
      • The component returned by createRoot() corresponds to the component generated by the routes/ directory or exported by App.tsx
      • The render() function is used to handle rendering and mounting components

      #3. App.config Migration

      If you defined App.config in App.[tj]sx, you need to migrate it to the runtime configuration file.

      2.0 Version:

      src/App.tsx
      const App = () => {
        return <div>Hello</div>;
      };
      
      App.config = {
        router: {
          supportHtml5History: true,
        },
      };
      
      export default App;

      3.0 Version:

      Create modern.runtime.ts in the same directory as the entry:

      src/modern.runtime.ts
      import { defineRuntimeConfig } from '@modern-js/runtime';
      
      export default defineRuntimeConfig({
        router: {
          supportHtml5History: true,
        },
      });
      Note

      Modern.js 3.0 no longer supports configuring runtime in modern.config.ts, you must use the modern.runtime.ts file.

      #4. App.init Migration

      If you defined App.init in App.[tj]sx, you need to change it to a runtime plugin.

      2.0 Version:

      src/App.tsx
      const App = () => {
        return <div>Hello</div>;
      };
      
      App.init = context => {
        context.store = createStore();
        context.request = (url: string) => fetch(url);
      };
      
      export default App;

      3.0 Version:

      src/modern.runtime.ts
      import type { RuntimePlugin } from '@modern-js/runtime';
      import { defineRuntimeConfig } from '@modern-js/runtime';
      
      const initPlugin = (): RuntimePlugin => ({
        name: 'init-plugin',
        setup: api => {
          return {
            init({ context }) {
              context.store = createStore();
              context.request = (url: string) => fetch(url);
            },
          };
        },
      });
      
      export default defineRuntimeConfig({
        plugins: [initPlugin()],
      });

      #5. config Export Migration from routes/layout.tsx

      If you exported a config function in routes/layout.tsx, you need to migrate it to the runtime configuration file.

      2.0 Version:

      src/routes/layout.tsx
      export const config = () => {
        return {
          router: {
            supportHtml5History: true,
          },
        };
      };
      
      export default function Layout() {
        return <Outlet />;
      }

      3.0 Version:

      src/routes/layout.tsx
      export default function Layout() {
        return <Outlet />;
      }
      src/modern.runtime.ts
      import { defineRuntimeConfig } from '@modern-js/runtime';
      
      export default defineRuntimeConfig({
        router: {
          supportHtml5History: true,
        },
      });

      #6. init Export Migration from routes/layout.tsx

      If you exported an init function in routes/layout.tsx, you need to change it to a runtime plugin.

      2.0 Version:

      src/routes/layout.tsx
      export const init = context => {
        context.request = (url: string) => fetch(url);
      };
      
      export default function Layout() {
        return <Outlet />;
      }

      3.0 Version:

      src/routes/layout.tsx
      export default function Layout() {
        return <Outlet />;
      }
      src/modern.runtime.ts
      import type { RuntimePlugin } from '@modern-js/runtime';
      import { defineRuntimeConfig } from '@modern-js/runtime';
      
      const initPlugin = (): RuntimePlugin => ({
        name: 'init-plugin',
        setup: api => {
          return {
            init({ context }) {
              context.request = (url: string) => fetch(url);
            },
          };
        },
      });
      
      export default defineRuntimeConfig({
        plugins: [initPlugin()],
      });

      #Multi-Entry Application Migration Notes

      For multi-entry applications, you need to use function-form configuration in src/modern.runtime.ts, returning different runtime configurations based on entry names.

      #Configuration Method

      Directory Structure:

      src/
      ├── modern.runtime.ts  # Unified runtime configuration file
      ├── entry1/
      │   └── routes/
      └── entry2/
          └── App.tsx

      Configuration Example:

      src/modern.runtime.ts
      import { defineRuntimeConfig } from '@modern-js/runtime';
      
      export default defineRuntimeConfig(entryName => {
        // Common configuration
        const commonConfig = {
          plugins: [commonPlugin()],
        };
      
        // Return specific configuration based on entry name
        if (entryName === 'entry1') {
          return {
            ...commonConfig,
            router: {
              supportHtml5History: true,
            },
            plugins: [...commonConfig.plugins, entry1Plugin()],
          };
        }
      
        if (entryName === 'entry2') {
          return {
            ...commonConfig,
            router: {
              supportHtml5History: false,
            },
            plugins: [...commonConfig.plugins, entry2Plugin()],
          };
        }
      
        // Default configuration
        return commonConfig;
      });
      Note
      • The entryName parameter corresponds to the entry directory name
      • Main entry (same name as name in package.json): the directory name is passed in
      • Other entries: the entry directory name is passed in

      #Migration Notes

      1. Merge configurations for the same entry: If both App.config/App.init and config/init from routes/layout.tsx exist for the same entry, you need to merge them into the corresponding entry configuration in the src/modern.runtime.ts file

      2. Multiple plugins in parallel: Multiple runtime plugins can be configured in parallel in the plugins array

      3. Clean up old code: After migration is complete, remember to delete from the original files:

        • App.config property
        • App.init method
        • config export from routes/layout.tsx
        • init export from routes/layout.tsx

      #Migration Example

      Assume you have a 2.0 version multi-entry application:

      2.0 Version Directory Structure:

      src/
      ├── main/
      │   ├── routes/
      │   │   └── layout.tsx  # Contains config and init
      │   └── App.tsx         # Contains App.config and App.init
      └── admin/
          └── routes/
              └── layout.tsx  # Contains config and init

      2.0 Version Configuration:

      src/main/App.tsx
      const App = () => <div>Main App</div>;
      
      App.config = {
        router: { supportHtml5History: true },
      };
      
      App.init = context => {
        context.mainData = 'main';
      };
      src/admin/routes/layout.tsx
      export const config = () => ({
        router: { supportHtml5History: false },
      });
      
      export const init = context => {
        context.adminData = 'admin';
      };

      3.0 Version After Migration:

      src/
      ├── modern.runtime.ts  # New unified configuration file
      ├── main/
      │   ├── routes/
      │   │   └── layout.tsx  # Removed config and init
      │   └── App.tsx         # Removed App.config and App.init
      └── admin/
          └── routes/
              └── layout.tsx  # Removed config and init
      src/modern.runtime.ts
      import { defineRuntimeConfig } from '@modern-js/runtime';
      import type { RuntimePlugin } from '@modern-js/runtime';
      
      // Main entry initialization plugin
      const mainInitPlugin = (): RuntimePlugin => ({
        name: 'main-init-plugin',
        setup: api => {
          return {
            init({ context }) {
              context.mainData = 'main';
            },
          };
        },
      });
      
      // Admin entry initialization plugin
      const adminInitPlugin = (): RuntimePlugin => ({
        name: 'admin-init-plugin',
        setup: api => {
          return {
            init({ context }) {
              context.adminData = 'admin';
            },
          };
        },
      });
      
      export default defineRuntimeConfig(entryName => {
        if (entryName === 'main') {
          return {
            router: {
              supportHtml5History: true,
            },
            plugins: [mainInitPlugin()],
          };
        }
      
        if (entryName === 'admin') {
          return {
            router: {
              supportHtml5History: false,
            },
            plugins: [adminInitPlugin()],
          };
        }
      
        return {};
      });

      #Related Links

      • Page Entries
      • Runtime Configuration
      • Runtime Plugins
      • source.entries Configuration
      • source.entriesDir Configuration