首屏加载体积是浏览器首次渲染前必须下载解析的HTML、CSS、JS总量,拆分能减小它是因为通过import()按需加载非首屏资源(如路由组件、模态框),并配合SSR/SSG输出真实首屏内容,避免空容器和冗余HTML。

什么是首屏加载体积,为什么拆分能减小它
首屏加载体积指的是浏览器首次渲染页面时必须下载并解析的 HTML、CSS、JS 总量。它不等于整个页面资源大小,而是 DOMContentLoaded 前阻塞渲染的关键资源之和。代码拆分不是“把 JS 拆成更多文件”,而是让非首屏逻辑延迟加载——比如路由级组件、模态框、图表库、富文本编辑器等,它们在首屏渲染完成前根本用不到。
常见错误是:把所有 import 写在模块顶层,导致 Webpack/Vite 无法识别动态依赖;或误以为 async 脚本就能解决一切,却忽略了 CSS 和内联 JS 的阻塞影响。
用 import() 实现按需加载(ES 模块动态导入)
import() 是标准语法,支持 Webpack、Vite、Rollup 等构建工具自动生成 chunk。它返回 Promise,必须配合 await 或 .then() 使用,不能出现在顶层作用域。
- ✅ 正确写法:
button.addEventListener('click', async () => { const { default: Editor } = await import('./Editor.svelte'); new Editor({ target: modal }); }); - ❌ 错误写法:
import('./Editor.svelte')不加await,或写在函数外 - ⚠️ 注意:
import()中路径必须是静态字符串(不能拼接变量),否则构建工具无法分析依赖 - ? 提示:Vite 中
import.meta.glob()可批量处理多文件,适合菜单或文档页
HTML 中如何避免内联脚本/样式阻塞首屏
内联 <script> 和 <style> 默认同步执行,会中断 HTML 解析。哪怕只有几行,也可能拖慢首屏时间。
立即学习“前端免费学习笔记(深入)”;
- 内联 JS:用
type="module"或defer属性(defer仅适用于外部脚本);若必须内联,改用<script type="application/json">存数据,逻辑仍走外部模块 - 内联 CSS:只保留「首屏关键 CSS」(Critical CSS),其余用
<link rel="stylesheet" href="..." media="print" onload="this.media='all'">异步加载 - ⚠️ 避坑:不要在
<head>里写<script>fetch(...),它会发起请求但不阻塞渲染——可接受;但若里面调用了document.write或修改了document.head,就可能触发重排
服务端如何配合做 HTML 级代码拆分
纯前端拆分有局限:HTML 本身仍是完整骨架,含大量占位 <div id="app"></div>,且首屏数据仍需等待 JS 执行后才渲染。服务端渲染(SSR)或静态生成(SSG)能真正减少首屏传输体积。
- Vite + SSR:用
vite-plugin-ssr,路由组件通过import()加载,服务端只渲染当前 route 对应 chunk 的内容 - Next.js/Nuxt:默认对每个
pages/或app/下的路由生成独立 HTML,天然支持拆分 - ⚠️ 关键点:服务端输出的 HTML 必须包含真实首屏内容(文本、图片、按钮),而不是空容器 + loading spinner —— 否则再怎么拆 JS,LCP(最大内容绘制)指标也不会改善
- ? 小技巧:用
<link rel="preload" as="script" href="chunk-xxx.js">提前提示浏览器加载关键异步 chunk
首屏体积优化最易被忽略的,是「HTML 本身的结构冗余」:无意义的 wrapper div、重复的 data-* 属性、未压缩的内联 JSON、过早注入的第三方 tracker 脚本。这些都不在打包分析报告里,但直接出现在网络面板的「Size」列中。



















