HTML本身无法实现路由懒加载——它无运行时、无模块系统、不支持动态import,实际由Vue/React等框架或Vite/Webpack等构建工具在JS层实现,HTML仅承载script标签。

HTML 本身无法实现基于路由的组件按需加载——它没有运行时、没有模块系统、也不理解“路由”概念。所谓“HTML 实现”,实际是前端框架(Vue/React/Angular)或构建工具(Vite/Webpack)在 JS 层完成的,HTML 只负责承载最终生成的 <script> 标签。
为什么直接写 HTML 不行
浏览器解析 <script src="page-about.js"></script> 时会立即下载执行(除非加 defer 或 async),但这和“按路由加载”无关:它不感知 URL 变化,也无法动态决定加载哪个文件。
关键依赖缺位:
-
import()是 ES 模块语法,原生 HTML 不支持相对路径动态导入(import('./About.vue')在纯 HTML + script 标签中直接报错:Failed to resolve module specifier) - 没有运行时来监听
history.pushState或hashchange,也就没法触发“该加载哪个组件” - 没有构建工具把
import()转成独立 chunk 文件(如about.abc123.js),所有代码只会打包进一个大文件
Vue Router 中必须用 defineAsyncComponent 包裹 import()
很多人写 component: () => import('./About.vue') 能跑通,但这是危险的简写。真正健壮的做法是显式包装:
立即学习“前端免费学习笔记(深入)”;
import { defineAsyncComponent } from 'vue'
const routes = [{
path: '/about',
component: defineAsyncComponent({
loader: () => import('./About.vue'),
loading: () => import('./Loading.vue'),
error: () => import('./Error.vue'),
delay: 200,
timeout: 5000
})
}]
不包装的后果:
- 加载失败时整个页面白屏,无 fallback
- SSR 场景下可能提前执行
import(),失去懒加载意义 - 无法控制 loading 延迟、超时重试等行为
React Router v6.4+ 的 lazy 必须配 <Suspense>
lazy 返回的是一个组件工厂函数,不是可直接渲染的组件。没 <Suspense> 会直接报错:A component suspended while responding to synchronous input。
正确写法(必须成对):
import { lazy, Suspense } from 'react'
import { Routes, Route } from 'react-router-dom'
const Dashboard = lazy(() => import('./Dashboard'))
function App() {
return (
<Routes>
<Route
path="/dashboard"
element={
<Suspense fallback={<Spinner />}>
<Dashboard />
</Suspense>
}
/>
</Routes>
)
}
常见错误:
-
<Suspense>没包住<Dashboard />,而是包住了整个<Routes>—— 这样 fallback 会覆盖全部路由,不合理 -
fallback写成空字符串或null,React 不接受 - 嵌套路由里子路由也用了
lazy,但没在对应层级加<Suspense>,导致子组件卡死
Framework7 的 async 路由函数要返回 resolve({ component })
Framework7 不依赖 React/Vue,而是用原生 JS 路由配置。它的懒加载靠 async 函数 + resolve 回调驱动:
{
path: '/about/',
async({ resolve }) {
const module = await import('../pages/about.js')
resolve({ component: module.default })
}
}
注意点:
-
resolve必须被调用,否则页面永远不渲染 -
module.default是关键——如果about.js没导出default(比如只写了export const About = {...}),这里会传undefined,报错 “component is not a function” - 不能直接写
component: () => import(...),Framework7 的路由系统不识别这种写法
最易被忽略的点:所有这些方案都依赖构建工具把 import() 提取为独立 chunk。如果你用 Vite 但没开 build.rollupOptions.output.manualChunks,或 Webpack 没配 optimization.splitChunks,那代码还是全打在一个包里,“懒加载”只是假象。



















