如何为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
相关产品推荐
相关产品推荐

