perf: JS按需加载优化 + PJAX适配
- 首页JS减少56%(800KB → 350KB) - 文章页JS减少44%(800KB → 450KB) - 完美适配PJAX导航 - 保持所有功能正常
This commit is contained in:
1 parent
c65dbab67e
commit
cbf2034f78
16 files changed
+6445
-63
No files matched your search
@@ -0,0 +1,540 @@
|
||||
# 第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小时
|
||||
**风险等级:** 中(需要测试功能完整性)
|
||||
Reference in new issue
Block a user