540 lines
18 KiB
Markdown
540 lines
18 KiB
Markdown
# 第2步:JS按需加载优化实施方案
|
||||
|
|
|
|||
|
|
## 📋 当前JS加载分析
|
|||
|
|
|
|||
|
|
### JS文件清单(从footer.html)
|
|||
|
|
|
|||
|
|
#### 核心JS(必须始终加载)
|
|||
|
|
```javascript
|
|||
|
|
1. iconfont.js - 图标字体(UIkit图标依赖)
|
|||
|
|
2. uikit.min.js - UI框架(基础依赖)
|
|||
|
|
3. view-image.min.js - 图片灯箱(文章详情页)
|
|||
|
|
4. utils.js - 工具函数(主题切换、代码折叠等)
|
|||
|
|
5. loader.js - 加载器
|
|||
|
|
6. cache.js - 缓存管理
|
|||
|
|
7. search.js - 搜索功能
|
|||
|
|
8. floating-tools.js - 浮动工具栏
|
|||
|
|
9. nprogress.js - 页面进度条
|
|||
|
|
10. pjax.js - PJAX导航库
|
|||
|
|
11. mypjax.js - PJAX配置
|
|||
|
|
12. pangu.js - 中英文空格处理
|
|||
|
|
13. linkify.js - 链接处理
|
|||
|
|
14. main.js - 主题主逻辑(初始化所有功能)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 非核心JS(可按需加载)
|
|||
|
|
```javascript
|
|||
|
|
15. artalk.js - Artalk评论系统
|
|||
|
|
- 加载时机:文章详情页(有#comments容器)
|
|||
|
|
- 大小:~150KB
|
|||
|
|
|
|||
|
|
16. infinite-scroll.js - 无限滚动
|
|||
|
|
- 加载时机:首页(且启用该功能)
|
|||
|
|
- 大小:~20KB
|
|||
|
|
|
|||
|
|
17. paragraph-comments.js - 段落评论
|
|||
|
|
- 加载时机:文章详情页
|
|||
|
|
- 大小:~15KB
|
|||
|
|
|
|||
|
|
18. toast.js - Toast消息提示
|
|||
|
|
- 加载时机:特定交互触发时
|
|||
|
|
- 大小:~10KB
|
|||
|
|
|
|||
|
|
19. tiaozhuan.js - 跳转功能
|
|||
|
|
- 加载时机:特定页面(如links、circles)
|
|||
|
|
- 大小:~8KB
|
|||
|
|
|
|||
|
|
20. reward.js - 打赏功能
|
|||
|
|
- 加载时机:文章详情页(有打赏按钮)
|
|||
|
|
- 大小:~12KB
|
|||
|
|
|
|||
|
|
21. lazyload.js - 图片懒加载
|
|||
|
|
- 加载时机:页面加载后(延迟加载)
|
|||
|
|
- 大小:~15KB
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 🎯 优化策略
|
|||
|
|
|
|||
|
|
### 策略1:代码拆分(推荐)
|
|||
|
|
|
|||
|
|
将JS拆分为两个bundle:
|
|||
|
|
- `core.js` - 核心功能(约200KB)
|
|||
|
|
- `optional.js` - 可选功能(约230KB)
|
|||
|
|
|
|||
|
|
**优点:**
|
|||
|
|
- 实现简单
|
|||
|
|
- 首页加载减少230KB(约40%)
|
|||
|
|
|
|||
|
|
### 策略2:按需动态导入
|
|||
|
|
|
|||
|
|
使用ES6的 `import()` 语法,在需要时动态加载模块
|
|||
|
|
|
|||
|
|
**优点:**
|
|||
|
|
- 更精细的控制
|
|||
|
|
- 最小化加载量
|
|||
|
|
|
|||
|
|
**缺点:**
|
|||
|
|
- 需要修改较多代码
|
|||
|
|
- 需要确保模块兼容性
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 📝 实施方案:策略1(代码拆分)
|
|||
|
|
|
|||
|
|
### 步骤2.1:创建核心JS bundle
|
|||
|
|
|
|||
|
|
**修改文件:** `themes/Ying/layouts/partials/footer.html`
|
|||
|
|
|
|||
|
|
**当前代码(第50-73行):**
|
|||
|
|
```gohtml
|
|||
|
|
{{ $iconfont := resources.Get "js/libs/iconfont.js" }}
|
|||
|
|
{{ $uikit := resources.Get "js/libs/uikit.min.js" }}
|
|||
|
|
{{ $easylazyload := resources.Get "js/modules/lazyload.js" }}
|
|||
|
|
{{ $viewimage := resources.Get "js/libs/view-image.min.js" }}
|
|||
|
|
{{ $main := resources.Get "js/main.js" }}
|
|||
|
|
{{ $mypjax := resources.Get "js/modules/mypjax.js" }}
|
|||
|
|
{{ $nprogress := resources.Get "js/libs/nprogress.js" }}
|
|||
|
|
{{ $tiaozhuan := resources.Get "js/modules/tiaozhuan.js" }}
|
|||
|
|
{{ $toast := resources.Get "js/modules/toast.js" }}
|
|||
|
|
{{ $reward := resources.Get "js/modules/reward.js" }}
|
|||
|
|
{{/* Modules */}}
|
|||
|
|
{{ $utils := resources.Get "js/modules/utils.js" }}
|
|||
|
|
{{ $loader := resources.Get "js/modules/loader.js" }}
|
|||
|
|
{{ $cache := resources.Get "js/modules/cache.js" }}
|
|||
|
|
{{ $search := resources.Get "js/modules/search.js" }}
|
|||
|
|
{{ $floatingTools := resources.Get "js/modules/floating-tools.js" }}
|
|||
|
|
{{ $paragraphComments := resources.Get "js/modules/paragraph-comments.js" }}
|
|||
|
|
{{ $infiniteScroll := resources.Get "js/modules/infinite-scroll.js" }}
|
|||
|
|
{{ $artalkModule := resources.Get "js/modules/artalk.js" }}
|
|||
|
|
{{ $pjaxLib := resources.Get "js/libs/pjax.js" }}
|
|||
|
|
{{ $linkify := resources.Get "js/modules/linkify.js" }}
|
|||
|
|
{{ $pangu := resources.Get "js/modules/pangu.js" }}
|
|||
|
|
|
|||
|
|
{{ $scripts := slice $iconfont $uikit $easylazyload $viewimage $utils $loader $cache $search $floatingTools $paragraphComments $infiniteScroll $artalkModule $nprogress $pjaxLib $pangu $linkify $main $mypjax $toast $tiaozhuan $reward | resources.Concat "js/bundle.js" | resources.Minify | resources.Fingerprint }}
|
|||
|
|
|
|||
|
|
<script defer src="{{ $scripts.RelPermalink }}"></script>
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**修改后代码:**
|
|||
|
|
```gohtml
|
|||
|
|
{{/* ====== JS加载优化:核心JS + 非核心JS分离 ====== */}}
|
|||
|
|
|
|||
|
|
{{/* 1. 核心JS - 始终加载 */}}
|
|||
|
|
{{ $iconfont := resources.Get "js/libs/iconfont.js" }}
|
|||
|
|
{{ $uikit := resources.Get "js/libs/uikit.min.js" }}
|
|||
|
|
{{ $viewimage := resources.Get "js/libs/view-image.min.js" }}
|
|||
|
|
{{ $utils := resources.Get "js/modules/utils.js" }}
|
|||
|
|
{{ $loader := resources.Get "js/modules/loader.js" }}
|
|||
|
|
{{ $cache := resources.Get "js/modules/cache.js" }}
|
|||
|
|
{{ $search := resources.Get "js/modules/search.js" }}
|
|||
|
|
{{ $floatingTools := resources.Get "js/modules/floating-tools.js" }}
|
|||
|
|
{{ $nprogress := resources.Get "js/libs/nprogress.js" }}
|
|||
|
|
{{ $pjaxLib := resources.Get "js/libs/pjax.js" }}
|
|||
|
|
{{ $mypjax := resources.Get "js/modules/mypjax.js" }}
|
|||
|
|
{{ $pangu := resources.Get "js/modules/pangu.js" }}
|
|||
|
|
{{ $linkify := resources.Get "js/modules/linkify.js" }}
|
|||
|
|
{{ $main := resources.Get "js/main.js" }}
|
|||
|
|
|
|||
|
|
{{ $coreScripts := slice $iconfont $uikit $viewimage $utils $loader $cache $search $floatingTools $nprogress $pjaxLib $mypjax $pangu $linkify $main | resources.Concat "js/core.js" | resources.Minify | resources.Fingerprint }}
|
|||
|
|
|
|||
|
|
<script defer src="{{ $coreScripts.RelPermalink }}"></script>
|
|||
|
|
|
|||
|
|
{{/* 2. 非核心JS - 使用requestIdleCallback延迟加载 */}}
|
|||
|
|
{{ $artalkModule := resources.Get "js/modules/artalk.js" }}
|
|||
|
|
{{ $infiniteScroll := resources.Get "js/modules/infinite-scroll.js" }}
|
|||
|
|
{{ $paragraphComments := resources.Get "js/modules/paragraph-comments.js" }}
|
|||
|
|
{{ $toast := resources.Get "js/modules/toast.js" }}
|
|||
|
|
{{ $tiaozhuan := resources.Get "js/modules/tiaozhuan.js" }}
|
|||
|
|
{{ $reward := resources.Get "js/modules/reward.js" }}
|
|||
|
|
{{ $easylazyload := resources.Get "js/modules/lazyload.js" }}
|
|||
|
|
|
|||
|
|
{{ $optionalScripts := slice $artalkModule $infiniteScroll $paragraphComments $toast $tiaozhuan $reward $easylazyload | resources.Concat "js/optional.js" | resources.Minify | resources.Fingerprint }}
|
|||
|
|
|
|||
|
|
<script>
|
|||
|
|
// 使用requestIdleCallback在浏览器空闲时加载非核心JS
|
|||
|
|
// 如果浏览器不支持requestIdleCallback,使用setTimeout降级
|
|||
|
|
if ('requestIdleCallback' in window) {
|
|||
|
|
requestIdleCallback(function() {
|
|||
|
|
var script = document.createElement('script');
|
|||
|
|
script.src = '{{ $optionalScripts.RelPermalink }}';
|
|||
|
|
script.defer = true;
|
|||
|
|
document.body.appendChild(script);
|
|||
|
|
});
|
|||
|
|
} else {
|
|||
|
|
setTimeout(function() {
|
|||
|
|
var script = document.createElement('script');
|
|||
|
|
script.src = '{{ $optionalScripts.RelPermalink }}';
|
|||
|
|
script.defer = true;
|
|||
|
|
document.body.appendChild(script);
|
|||
|
|
}, 1000); // 延迟1秒加载
|
|||
|
|
}
|
|||
|
|
</script>
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### 步骤2.2:条件加载特定页面的JS(高级优化)
|
|||
|
|
|
|||
|
|
如果需要更精细的控制,可以根据页面类型加载特定JS:
|
|||
|
|
|
|||
|
|
```gohtml
|
|||
|
|
{{/* 根据页面类型条件加载JS */}}
|
|||
|
|
|
|||
|
|
{{/* 文章详情页专用JS */}}
|
|||
|
|
{{ if .IsPage }}
|
|||
|
|
{{ $artalkModule := resources.Get "js/modules/artalk.js" }}
|
|||
|
|
{{ $paragraphComments := resources.Get "js/modules/paragraph-comments.js" }}
|
|||
|
|
{{ $reward := resources.Get "js/modules/reward.js" }}
|
|||
|
|
|
|||
|
|
{{ $pageScripts := slice $artalkModule $paragraphComments $reward | resources.Concat "js/page-only.js" | resources.Minify | resources.Fingerprint }}
|
|||
|
|
|
|||
|
|
<script defer src="{{ $pageScripts.RelPermalink }}"></script>
|
|||
|
|
{{ end }}
|
|||
|
|
|
|||
|
|
{{/* 首页专用JS */}}
|
|||
|
|
{{ if .IsHome }}
|
|||
|
|
{{ $infiniteScroll := resources.Get "js/modules/infinite-scroll.js" }}
|
|||
|
|
|
|||
|
|
<script>
|
|||
|
|
window.enableInfiniteScroll = {{ .Site.Params.infiniteScroll.enable | default false }};
|
|||
|
|
</script>
|
|||
|
|
|
|||
|
|
{{ if .Site.Params.infiniteScroll.enable }}
|
|||
|
|
<script defer src="{{ $infiniteScroll.RelPermalink }}"></script>
|
|||
|
|
{{ end }}
|
|||
|
|
{{ end }}
|
|||
|
|
|
|||
|
|
{{/* 特定页面专用JS */}}
|
|||
|
|
{{ if or (eq .Type "links") (eq .Type "circles") }}
|
|||
|
|
{{ $tiaozhuan := resources.Get "js/modules/tiaozhuan.js" }}
|
|||
|
|
<script defer src="{{ $tiaozhuan.RelPermalink }}"></script>
|
|||
|
|
{{ end }}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 🔧 完整实施方案
|
|||
|
|
|
|||
|
|
### 修改footer.html的完整代码
|
|||
|
|
|
|||
|
|
**文件路径:** `themes/Ying/layouts/partials/footer.html`
|
|||
|
|
|
|||
|
|
**删除原有JS加载代码(第50-133行)**,替换为:
|
|||
|
|
|
|||
|
|
```gohtml
|
|||
|
|
{{/* ====== 优化后的JS加载策略 ====== */}}
|
|||
|
|
|
|||
|
|
{{/* ====== 1. 核心JS Bundle - 始终加载 ====== */}}
|
|||
|
|
{{ $iconfont := resources.Get "js/libs/iconfont.js" }}
|
|||
|
|
{{ $uikit := resources.Get "js/libs/uikit.min.js" }}
|
|||
|
|
{{ $viewimage := resources.Get "js/libs/view-image.min.js" }}
|
|||
|
|
{{ $utils := resources.Get "js/modules/utils.js" }}
|
|||
|
|
{{ $loader := resources.Get "js/modules/loader.js" }}
|
|||
|
|
{{ $cache := resources.Get "js/modules/cache.js" }}
|
|||
|
|
{{ $search := resources.Get "js/modules/search.js" }}
|
|||
|
|
{{ $floatingTools := resources.Get "js/modules/floating-tools.js" }}
|
|||
|
|
{{ $nprogress := resources.Get "js/libs/nprogress.js" }}
|
|||
|
|
{{ $pjaxLib := resources.Get "js/libs/pjax.js" }}
|
|||
|
|
{{ $mypjax := resources.Get "js/modules/mypjax.js" }}
|
|||
|
|
{{ $pangu := resources.Get "js/modules/pangu.js" }}
|
|||
|
|
{{ $linkify := resources.Get "js/modules/linkify.js" }}
|
|||
|
|
{{ $main := resources.Get "js/main.js" }}
|
|||
|
|
|
|||
|
|
{{ $coreScripts := slice $iconfont $uikit $viewimage $utils $loader $cache $search $floatingTools $nprogress $pjaxLib $mypjax $pangu $linkify $main | resources.Concat "js/core.js" | resources.Minify | resources.Fingerprint }}
|
|||
|
|
|
|||
|
|
<script defer src="{{ $coreScripts.RelPermalink }}"></script>
|
|||
|
|
|
|||
|
|
{{/* ====== 2. 配置变量 - 必须在核心JS之前 ====== */}}
|
|||
|
|
<script>
|
|||
|
|
window.enableInfiniteScroll = {{ .Site.Params.infiniteScroll.enable | default false }};
|
|||
|
|
</script>
|
|||
|
|
|
|||
|
|
{{/* ====== 3. 远程数据获取 - 构建时 ====== */}}
|
|||
|
|
{{/* Fetch friend data at build time — no runtime network requests */}}
|
|||
|
|
{{ $linkHosts := slice }}
|
|||
|
|
{{ $linkNames := slice }}
|
|||
|
|
{{ with resources.GetRemote "https://api.usj.cc/api/links?all=1" }}
|
|||
|
|
{{ with .Err }}
|
|||
|
|
{{ warnf "Links API fetch failed: %s" . }}
|
|||
|
|
{{ else }}
|
|||
|
|
{{ with .Content | transform.Unmarshal }}
|
|||
|
|
{{ range .links }}
|
|||
|
|
{{ $host := "" }}
|
|||
|
|
{{ with .url | urls.Parse }}
|
|||
|
|
{{ $host = .Host | strings.TrimPrefix "www." }}
|
|||
|
|
{{ end }}
|
|||
|
|
{{ $title := .name | default "" }}
|
|||
|
|
{{ if $host }}
|
|||
|
|
{{ $linkHosts = $linkHosts | append (dict "host" $host "title" $title) }}
|
|||
|
|
{{ end }}
|
|||
|
|
{{ if $title }}
|
|||
|
|
{{ $linkNames = $linkNames | append (dict "lower" (lower $title) "title" $title) }}
|
|||
|
|
{{ end }}
|
|||
|
|
{{ end }}
|
|||
|
|
{{ end }}
|
|||
|
|
{{ end }}
|
|||
|
|
{{ end }}
|
|||
|
|
<script>
|
|||
|
|
window.friendLinks = {{ dict "hosts" $linkHosts "names" $linkNames | jsonify | safeJS }};
|
|||
|
|
</script>
|
|||
|
|
|
|||
|
|
{{ $feedHosts := slice }}
|
|||
|
|
{{ $feedNames := slice }}
|
|||
|
|
{{ with resources.GetRemote "https://api.usj.cc/api/feeds" }}
|
|||
|
|
{{ with .Err }}
|
|||
|
|
{{ warnf "Feeds API fetch failed: %s" . }}
|
|||
|
|
{{ else }}
|
|||
|
|
{{ with .Content | transform.Unmarshal }}
|
|||
|
|
{{ range .feeds }}
|
|||
|
|
{{ $host := "" }}
|
|||
|
|
{{ with .url | urls.Parse }}
|
|||
|
|
{{ $host = .Host | strings.TrimPrefix "www." }}
|
|||
|
|
{{ end }}
|
|||
|
|
{{ $title := .feedTitle | default "" }}
|
|||
|
|
{{ if $host }}
|
|||
|
|
{{ $feedHosts = $feedHosts | append (dict "host" $host "title" $title) }}
|
|||
|
|
{{ end }}
|
|||
|
|
{{ if $title }}
|
|||
|
|
{{ $feedNames = $feedNames | append (dict "lower" (lower $title) "title" $title) }}
|
|||
|
|
{{ end }}
|
|||
|
|
{{ end }}
|
|||
|
|
{{ end }}
|
|||
|
|
{{ end }}
|
|||
|
|
{{ end }}
|
|||
|
|
<script>
|
|||
|
|
window.friendFeeds = {{ dict "hosts" $feedHosts "names" $feedNames | jsonify | safeJS }};
|
|||
|
|
</script>
|
|||
|
|
|
|||
|
|
{{/* ====== 4. 条件加载 - 页面特定JS ====== */}}
|
|||
|
|
|
|||
|
|
{{/* 文章详情页专用JS */}}
|
|||
|
|
{{ if .IsPage }}
|
|||
|
|
{{ $artalkModule := resources.Get "js/modules/artalk.js" }}
|
|||
|
|
{{ $paragraphComments := resources.Get "js/modules/paragraph-comments.js" }}
|
|||
|
|
{{ $reward := resources.Get "js/modules/reward.js" }}
|
|||
|
|
|
|||
|
|
{{ $pageScripts := slice $artalkModule $paragraphComments $reward | resources.Concat "js/page-only.js" | resources.Minify | resources.Fingerprint }}
|
|||
|
|
|
|||
|
|
<script defer src="{{ $pageScripts.RelPermalink }}"></script>
|
|||
|
|
{{ end }}
|
|||
|
|
|
|||
|
|
{{/* 首页专用JS */}}
|
|||
|
|
{{ if .IsHome }}
|
|||
|
|
{{ if .Site.Params.infiniteScroll.enable }}
|
|||
|
|
{{ $infiniteScroll := resources.Get "js/modules/infinite-scroll.js" }}
|
|||
|
|
<script defer src="{{ $infiniteScroll.RelPermalink }}"></script>
|
|||
|
|
{{ end }}
|
|||
|
|
{{ end }}
|
|||
|
|
|
|||
|
|
{{/* 特定页面专用JS */}}
|
|||
|
|
{{ if or (eq .Type "links") (eq .Type "circles") }}
|
|||
|
|
{{ $tiaozhuan := resources.Get "js/modules/tiaozhuan.js" }}
|
|||
|
|
<script defer src="{{ $tiaozhuan.RelPermalink }}"></script>
|
|||
|
|
{{ end }}
|
|||
|
|
|
|||
|
|
{{/* ====== 5. 其他非核心JS - 延迟加载 ====== */}}
|
|||
|
|
{{ $toast := resources.Get "js/modules/toast.js" }}
|
|||
|
|
{{ $easylazyload := resources.Get "js/modules/lazyload.js" }}
|
|||
|
|
|
|||
|
|
{{ $deferredScripts := slice $toast $easylazyload | resources.Concat "js/deferred.js" | resources.Minify | resources.Fingerprint }}
|
|||
|
|
|
|||
|
|
<script>
|
|||
|
|
// 使用requestIdleCallback在浏览器空闲时加载
|
|||
|
|
if ('requestIdleCallback' in window) {
|
|||
|
|
requestIdleCallback(function() {
|
|||
|
|
var script = document.createElement('script');
|
|||
|
|
script.src = '{{ $deferredScripts.RelPermalink }}';
|
|||
|
|
script.defer = true;
|
|||
|
|
document.body.appendChild(script);
|
|||
|
|
});
|
|||
|
|
} else {
|
|||
|
|
setTimeout(function() {
|
|||
|
|
var script = document.createElement('script');
|
|||
|
|
script.src = '{{ $deferredScripts.RelPermalink }}';
|
|||
|
|
script.defer = true;
|
|||
|
|
document.body.appendChild(script);
|
|||
|
|
}, 1000);
|
|||
|
|
}
|
|||
|
|
</script>
|
|||
|
|
|
|||
|
|
{{/* ====== 6. 其他脚本(bsz等) ====== */}}
|
|||
|
|
<script async src="/js/bsz.js"></script>
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 📊 预期收益
|
|||
|
|
|
|||
|
|
### 性能指标提升(预估)
|
|||
|
|
|
|||
|
|
| 页面类型 | 优化前 | 优化后 | 提升 |
|
|||
|
|
|---------|--------|--------|------|
|
|||
|
|
| **首页** | ~800KB | ~350KB | ⚡ -56% |
|
|||
|
|
| **文章详情页** | ~800KB | ~450KB | ⚡ -44% |
|
|||
|
|
| **其他页面** | ~800KB | ~350KB | ⚡ -56% |
|
|||
|
|
|
|||
|
|
### 加载时间提升
|
|||
|
|
|
|||
|
|
| 指标 | 优化前 | 优化后 | 提升 |
|
|||
|
|
|------|--------|--------|------|
|
|||
|
|
| **FCP** | ~1.2s | ~0.9s | ⚡ -25% |
|
|||
|
|
| **TTI** | ~2.5s | ~1.8s | ⚡ -28% |
|
|||
|
|
| **TBT** | ~150ms | ~80ms | ⚡ -47% |
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 🧪 测试验证清单
|
|||
|
|
|
|||
|
|
### 功能测试
|
|||
|
|
|
|||
|
|
#### 首页
|
|||
|
|
- [ ] 导航菜单正常工作
|
|||
|
|
- [ ] 搜索功能正常
|
|||
|
|
- [ ] 主题切换正常
|
|||
|
|
- [ ] 文章列表显示正常
|
|||
|
|
- [ ] 分页功能正常
|
|||
|
|
- [ ] 无限滚动功能正常(如果启用)
|
|||
|
|
|
|||
|
|
#### 文章详情页
|
|||
|
|
- [ ] 文章内容正常显示
|
|||
|
|
- [ ] 图片灯箱功能正常
|
|||
|
|
- [ ] 评论区正常加载(Artalk)
|
|||
|
|
- [ ] 打赏按钮功能正常
|
|||
|
|
- [ ] 段落评论功能正常(如果启用)
|
|||
|
|
|
|||
|
|
#### 其他页面
|
|||
|
|
- [ ] 友链页面跳转功能正常
|
|||
|
|
- [ ] 搜索结果页正常
|
|||
|
|
- [ ] 归档页面正常
|
|||
|
|
|
|||
|
|
### 性能测试
|
|||
|
|
|
|||
|
|
使用Chrome DevTools:
|
|||
|
|
1. **Network面板**
|
|||
|
|
- [ ] 核心JS(core.js)首先加载
|
|||
|
|
- [ ] 页面特定JS按条件加载
|
|||
|
|
- [ ] 非核心JS在空闲时加载
|
|||
|
|
|
|||
|
|
2. **Performance面板**
|
|||
|
|
- [ ] TBT指标改善
|
|||
|
|
- [ ] 长任务减少
|
|||
|
|
- [ ] 交互响应更快
|
|||
|
|
|
|||
|
|
3. **Lighthouse**
|
|||
|
|
- [ ] Performance得分提升
|
|||
|
|
- [ ] TTI指标改善
|
|||
|
|
- [ ] TBT指标改善
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## ⚠️ 注意事项
|
|||
|
|
|
|||
|
|
### 1. 模块依赖关系
|
|||
|
|
|
|||
|
|
某些JS模块可能有依赖关系:
|
|||
|
|
- `artalk.js` 可能依赖 `Artalk.js`(第三方库)
|
|||
|
|
- `mypjax.js` 依赖 `pjax.js`
|
|||
|
|
- `main.js` 可能调用其他模块的初始化函数
|
|||
|
|
|
|||
|
|
**解决方案:**
|
|||
|
|
- 确保核心JS包含所有依赖
|
|||
|
|
- 或者使用 `window` 全局变量暴露必要函数
|
|||
|
|
|
|||
|
|
### 2. 初始化时机
|
|||
|
|
|
|||
|
|
如果模块的初始化代码在模块内部,延迟加载可能导致初始化失败。
|
|||
|
|
|
|||
|
|
**解决方案:**
|
|||
|
|
- 在 `main.js` 中使用事件监听或轮询
|
|||
|
|
- 或者将初始化代码移到主JS中
|
|||
|
|
|
|||
|
|
示例:
|
|||
|
|
```javascript
|
|||
|
|
// main.js 中的初始化代码
|
|||
|
|
function initArtalk() {
|
|||
|
|
if (window.Artalk) {
|
|||
|
|
// 初始化Artalk
|
|||
|
|
} else {
|
|||
|
|
// Artalk还未加载,等待
|
|||
|
|
setTimeout(initArtalk, 100);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 3. 浏览器兼容性
|
|||
|
|
|
|||
|
|
`requestIdleCallback` 兼容性:
|
|||
|
|
- Chrome 47+ ✅
|
|||
|
|
- Firefox 55+ ✅
|
|||
|
|
- Safari 12.1+ ✅
|
|||
|
|
- Edge 79+ ✅
|
|||
|
|
- IE ❌(使用setTimeout降级)
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 🔄 回滚方案
|
|||
|
|
|
|||
|
|
如果出现问题,快速回滚到原始方案:
|
|||
|
|
|
|||
|
|
```gohtml
|
|||
|
|
{{/* 恢复原始JS加载方式 */}}
|
|||
|
|
{{ $iconfont := resources.Get "js/libs/iconfont.js" }}
|
|||
|
|
{{ $uikit := resources.Get "js/libs/uikit.min.js" }}
|
|||
|
|
{{ $easylazyload := resources.Get "js/modules/lazyload.js" }}
|
|||
|
|
{{ $viewimage := resources.Get "js/libs/view-image.min.js" }}
|
|||
|
|
{{ $main := resources.Get "js/main.js" }}
|
|||
|
|
{{ $mypjax := resources.Get "js/modules/mypjax.js" }}
|
|||
|
|
{{ $nprogress := resources.Get "js/libs/nprogress.js" }}
|
|||
|
|
{{ $tiaozhuan := resources.Get "js/modules/tiaozhuan.js" }}
|
|||
|
|
{{ $toast := resources.Get "js/modules/toast.js" }}
|
|||
|
|
{{ $reward := resources.Get "js/modules/reward.js" }}
|
|||
|
|
{{/* Modules */}}
|
|||
|
|
{{ $utils := resources.Get "js/modules/utils.js" }}
|
|||
|
|
{{ $loader := resources.Get "js/modules/loader.js" }}
|
|||
|
|
{{ $cache := resources.Get "js/modules/cache.js" }}
|
|||
|
|
{{ $search := resources.Get "js/modules/search.js" }}
|
|||
|
|
{{ $floatingTools := resources.Get "js/modules/floating-tools.js" }}
|
|||
|
|
{{ $paragraphComments := resources.Get "js/modules/paragraph-comments.js" }}
|
|||
|
|
{{ $infiniteScroll := resources.Get "js/modules/infinite-scroll.js" }}
|
|||
|
|
{{ $artalkModule := resources.Get "js/modules/artalk.js" }}
|
|||
|
|
{{ $pjaxLib := resources.Get "js/libs/pjax.js" }}
|
|||
|
|
{{ $linkify := resources.Get "js/modules/linkify.js" }}
|
|||
|
|
{{ $pangu := resources.Get "js/modules/pangu.js" }}
|
|||
|
|
|
|||
|
|
{{ $scripts := slice $iconfont $uikit $easylazyload $viewimage $utils $loader $cache $search $floatingTools $paragraphComments $infiniteScroll $artalkModule $nprogress $pjaxLib $pangu $linkify $main $mypjax $toast $tiaozhuan $reward | resources.Concat "js/bundle.js" | resources.Minify | resources.Fingerprint }}
|
|||
|
|
|
|||
|
|
<script defer src="{{ $scripts.RelPermalink }}"></script>
|
|||
|
|
<script async src="/js/bsz.js"></script>
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## ✅ 实施清单
|
|||
|
|
|
|||
|
|
- [ ] 备份原始 `footer.html`
|
|||
|
|
- [ ] 修改JS加载逻辑
|
|||
|
|
- [ ] 测试首页功能
|
|||
|
|
- [ ] 测试文章详情页功能
|
|||
|
|
- [ ] 测试其他页面功能
|
|||
|
|
- [ ] 使用Lighthouse验证性能提升
|
|||
|
|
- [ ] 提交代码
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 📚 扩展阅读
|
|||
|
|
|
|||
|
|
1. **JavaScript代码拆分**
|
|||
|
|
- https://web.dev/reduce-javascript-payloads-with-code-splitting/
|
|||
|
|
|
|||
|
|
2. **Dynamic Imports**
|
|||
|
|
- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import
|
|||
|
|
|
|||
|
|
3. **requestIdleCallback**
|
|||
|
|
- https://developer.mozilla.org/en-US/docs/Web/API/Window/requestIdleCallback
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
**预计耗时:** 2-3小时
|
|||
|
|
**风险等级:** 中(需要测试功能完整性)
|