You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为Mithril.js+Vite项目启用React式热重载?

问题

我正在使用Mithril JavaScript框架搭配Vite打包工具开发复杂应用。调试时,哪怕是修改HTML标签这类微小改动,都会触发应用全页刷新,导致我需要10-20秒才能回到调试所需的页面与状态。不过SASS文件的修改不会触发全页刷新,即使修改当前未打开的页面组件,依然会触发全页重载。

我的Vite配置如下:

import { defineConfig } from 'vite';
import basicSsl from '@vitejs/plugin-basic-ssl';
import { VitePWA } from 'vite-plugin-pwa';
import eslint from 'vite-plugin-eslint';

export default defineConfig({
  define: {
    global: {},
  },
  esbuild: {
    jsx: 'transform',
    jsxFactory: 'm',
    jsxInject: `import m from 'mithril'`,
    jsxFragment: "'['",
  },
  server: {
    host: '0.0.0.0',
    port: '5173',
    https: true,
  },
  plugins: [
    basicSsl(),
    VitePWA({
      registerType: 'autoUpdate',
      devOptions: {
        enabled: true,
      },
      manifest: {
        name: '...',
        short_name: '...',
        description: '...',
        theme_color: '#9977BB',
        icons: [],
      },
    }),
    eslint(),
  ],
});

package.json相关配置:

{
    "scripts": {
        "start": "npm run dev",
        "dev": "npx vite --host 0.0.0.0",
        "build": "npx vite build",
        "preview": "npx vite preview",
        "check": "npx prettier --check src/**/*.js"
    },
    "devDependencies": {
        "@vitejs/plugin-basic-ssl": "^1.0.1",
        "eslint": "^8.32.0",
        "eslint-plugin-mithril": "^0.2.0",
        "prettier": "^2.8.1",
        "sass": "^1.57.1",
        "vite": "^4.0.3",
        "vite-plugin-eslint": "^1.8.1",
        "vite-plugin-pwa": "^0.14.1"
    },
    "dependencies": {
        "mithril": "^2.2.2"
    }
}

index.jsx文件内容:

import Authentication from './screens/Authentication';
import Drive from './screens/Drive';
import BrowserIncompatible from './screens/BrowserIncompatible';
import Loading from './screens/Loading';

import '@primer/css/index.scss';

import * as packageJson from '../package.json';

// log version for bug reporting
console.info(`version: ${packageJson.version}`);

const isBrowserCompatible = () =>
  navigator &&
  getComputedStyle &&
  setTimeout &&
  Uint8Array &&
  console &&
  Promise &&
  TextDecoder &&
  TextEncoder &&
  prompt &&
  alert &&
  clearTimeout &&
  crypto &&
  CryptoKey &&
  AbortController &&
  Blob &&
  URL;

m.route(document.body, '/loading', {
  '/authentication': Authentication,
  '/': Drive,
  '/incompatible': BrowserIncompatible,
  '/loading': Loading,
});

// redirect to BrowserIncompatible page if browser is incompatible
isBrowserCompatible() || m.route.set('/incompatible');

该文件在index.html中以模块方式引入:

<script src="src/index.jsx" type="module"></script>

我希望实现类似React的热重载效果:修改代码后不会跳转至默认路由页面,且能保留应用状态,请问该如何配置?

解决方案

Vite默认HMR对Mithril的支持需要额外适配,以下是具体实现步骤:

1. 安装Mithril热重载插件

安装专为Mithril适配的Vite HMR插件:

npm install vite-plugin-mithril-hmr --save-dev

2. 修改Vite配置文件

在vite.config.js中引入并添加该插件,注意放在其他插件最前面:

import { defineConfig } from 'vite';
import basicSsl from '@vitejs/plugin-basic-ssl';
import { VitePWA } from 'vite-plugin-pwa';
import eslint from 'vite-plugin-eslint';
import mithrilHmr from 'vite-plugin-mithril-hmr';

export default defineConfig({
  define: {
    global: {},
  },
  esbuild: {
    jsx: 'transform',
    jsxFactory: 'm',
    jsxInject: `import m from 'mithril'`,
    jsxFragment: "'['",
  },
  server: {
    host: '0.0.0.0',
    port: '5173',
    https: true,
    hmr: {
      overlay: true, // 可选,开启HMR错误提示层
    },
  },
  plugins: [
    mithrilHmr(),
    basicSsl(),
    VitePWA({
      registerType: 'autoUpdate',
      devOptions: {
        enabled: true,
      },
      manifest: {
        name: '...',
        short_name: '...',
        description: '...',
        theme_color: '#9977BB',
        icons: [],
      },
    }),
    eslint(),
  ],
});

3. 调整入口文件的路由初始化逻辑

避免HMR时重新执行路由初始化导致跳转到默认路由,将路由配置包裹在HMR接受逻辑中:
修改index.jsx:

import Authentication from './screens/Authentication';
import Drive from './screens/Drive';
import BrowserIncompatible from './screens/BrowserIncompatible';
import Loading from './screens/Loading';

import '@primer/css/index.scss';

import * as packageJson from '../package.json';

console.info(`version: ${packageJson.version}`);

const isBrowserCompatible = () =>
  navigator &&
  getComputedStyle &&
  setTimeout &&
  Uint8Array &&
  console &&
  Promise &&
  TextDecoder &&
  TextEncoder &&
  prompt &&
  alert &&
  clearTimeout &&
  crypto &&
  CryptoKey &&
  AbortController &&
  Blob &&
  URL;

// 路由初始化逻辑
const initRoutes = () => {
  // 保留当前路由,而非强制跳转默认路由
  const initialRoute = window.location.pathname || '/loading';
  m.route(document.body, initialRoute, {
    '/authentication': Authentication,
    '/': Drive,
    '/incompatible': BrowserIncompatible,
    '/loading': Loading,
  });

  isBrowserCompatible() || m.route.set('/incompatible');
};

// 首次初始化
initRoutes();

// HMR接受逻辑,仅更新对应组件而非全页刷新
if (import.meta.hot) {
  import.meta.hot.accept('./screens/Authentication', (newModule) => {
    if (newModule.default) {
      m.route.set('/authentication', undefined, { replace: true });
    }
  });

  import.meta.hot.accept('./screens/Drive', (newModule) => {
    if (newModule.default) {
      m.route.set('/', undefined, { replace: true });
    }
  });

  import.meta.hot.accept('./screens/BrowserIncompatible', (newModule) => {
    if (newModule.default) {
      m.route.set('/incompatible', undefined, { replace: true });
    }
  });

  import.meta.hot.accept('./screens/Loading', (newModule) => {
    if (newModule.default) {
      m.route.set('/loading', undefined, { replace: true });
    }
  });
}

4. 组件层面的适配

确保页面组件为默认导出,且使用Mithril原生状态管理(保证状态可被HMR保留):

// 示例:Drive.jsx
export default {
  state: {
    // 组件内部状态
  },
  view() {
    return m('div', this.state.someValue);
  }
};

5. 可选:调整PWA开发配置

若HMR仍受干扰,可临时关闭开发环境的PWA自动更新:

VitePWA({
  registerType: 'autoUpdate',
  devOptions: {
    enabled: false,
  },
  // 其他配置不变
})

完成以上配置后,修改组件代码时会触发模块热替换,而非全页刷新,当前路由和应用状态都会得到保留。

内容的提问来源于stack exchange,提问作者ajaleksa

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 12:46:15