优化Typecho的思路

AI摘要:文章介绍了优化Typecho博客性能的多种方法:1)服务器端使用Nginx开启gzip压缩和浏览器缓存;2)图片优化采用原生JS实现懒加载;3)通过PHP压缩HTML输出;4)设置浏览器缓存和页面缓存策略,包括简单的PHP缓存实现。这些技术可显著提升网站加载速度和性能。

服务器端

使用Nginx作为web服务端可以使用以下开启

# 启用 gzip 压缩
gzip on;
gzip_comp_level 5;
gzip_min_length 256;
gzip_proxied any;
gzip_types
  application/javascript
  application/json
  application/xml
  text/css
  text/plain
  text/xml;

# 浏览器缓存控制
location ~* \.(jpg|jpeg|png|gif|ico|css|js)$ {
    expires 30d;
    add_header Cache-Control "public, no-transform";
}

图片优化

使用原生js实现懒加载

document.addEventListener('DOMContentLoaded', function() {
    // 获取所有图片(如果主题默认输出 src,可以动态替换为 data-src)
    const images = document.querySelectorAll('img[src]:not([data-src])');
    
    // 防止重复处理
    images.forEach(img => {
        if (!img.getAttribute('data-src')) {
            img.setAttribute('data-src', img.src); // 把 src 存到 data-src
            img.removeAttribute('src'); // 移除 src,避免立即加载
        }
    });

    // 懒加载逻辑
    const lazyLoad = (targets) => {
        if ('IntersectionObserver' in window) {
            const observer = new IntersectionObserver((entries) => {
                entries.forEach(entry => {
                    if (entry.isIntersecting) {
                        const img = entry.target;
                        img.src = img.dataset.src;
                        observer.unobserve(img); // 加载后停止观察
                    }
                });
            });
            targets.forEach(img => observer.observe(img));
        } else {
            // 兼容旧浏览器(滚动监听)
            const checkImages = () => {
                targets.forEach(img => {
                    const rect = img.getBoundingClientRect();
                    if (rect.top < window.innerHeight + 100) { // 提前 100px 加载
                        img.src = img.dataset.src;
                    }
                });
            };
            window.addEventListener('scroll', checkImages);
            checkImages(); // 初始检查
        }
    };

    // 对所有 data-src 图片应用懒加载
    lazyLoad(document.querySelectorAll('img[data-src]'));
});

资源合并与压缩

压缩HTML输出

// 在主题的 functions.php 中
function compress_html($html) {
    $placeholders = [];
    $i = 0;

    // 匹配 <pre> 和 <code> 区块,替换为唯一占位符
    $html = preg_replace_callback(
        '/<(pre|code)[^>]*>.*?<\/\1>/is',
        function ($matches) use (&$placeholders, &$i) {
            $key = "###HTML_COMPRESS_IGNORE_" . $i . "###";
            $placeholders[$key] = $matches[0];
            $i++;
            return $key;
        },
        $html
    );

    // 正常压缩
    $search = array(
        '/\>[^\S ]+/s',
        '/[^\S ]+\</s',
        '/(\s)+/s'
    );
    $replace = array(
        '>',
        '<',
        '\\1'
    );
    $html = preg_replace($search, $replace, $html);

    // 恢复占位符
    if (!empty($placeholders)) {
        $html = str_replace(array_keys($placeholders), array_values($placeholders), $html);
    }

    return $html;
}
//在head.php中开启
<?php ob_start("compress_html"); ?>
//在footer.php中结束
<?php ob_end_flush(); ?>

缓存策略

浏览器缓存

<meta http-equiv="Cache-Control" content="max-age=86400" />

header.php中加入

页面缓存

在主题的 functions.php 中添加简单的页面缓存

function page_cache() {
    // 不缓存后台、登录页和提交操作
    if (defined('__TYPECHO_ADMIN__') || $_SERVER['REQUEST_METHOD'] != 'GET') {
        return;
    }
    
    $cache_dir = __TYPECHO_ROOT_DIR__ . '/cache';
    if (!is_dir($cache_dir)) {
        mkdir($cache_dir, 0755, true);
    }
    
    $url_hash = md5($_SERVER['REQUEST_URI']);
    $cache_file = $cache_dir . '/' . $url_hash . '.html';
    
    // 缓存过期时间(秒)
    $cache_time = 3600; // 1小时
    
    // 如果缓存文件存在且未过期,则直接输出
    if (file_exists($cache_file) && (time() - filemtime($cache_file) < $cache_time)) {
        echo file_get_contents($cache_file);
        exit;
    }
    
    // 否则开始输出缓冲
    ob_start();
}

function save_cache() {
    // 同样跳过后台等页面
    if (defined('__TYPECHO_ADMIN__') || $_SERVER['REQUEST_METHOD'] != 'GET') {
        return;
    }
    
    $cache_dir = __TYPECHO_ROOT_DIR__ . '/cache';
    $url_hash = md5($_SERVER['REQUEST_URI']);
    $cache_file = $cache_dir . '/' . $url_hash . '.html';
    
    // 保存缓冲内容到文件
    $content = ob_get_contents();
    file_put_contents($cache_file, $content);
}
// 在页面开始处调用
page_cache();
// 在页面结束前调用
register_shutdown_function('save_cache');