静态资源优化方案
静态资源优化的必要性
静态资源优化是提升Web应用性能的关键环节。Koa2作为轻量级Node.js框架,提供了灵活的中间件机制,能够高效处理静态资源请求。通过合理的优化策略,可以显著减少页面加载时间,降低服务器压力,改善用户体验。
静态资源缓存策略
强缓存与协商缓存
const path = require('path')
const static = require('koa-static')
const mount = require('koa-mount')
app.use(mount('/public', static(
path.join(__dirname, 'public'),
{
maxAge: 30 * 24 * 60 * 60 * 1000, // 30天缓存
immutable: true // 启用不可变资源缓存
}
)))
强缓存通过Cache-Control和Expires头实现,协商缓存则依赖Last-Modified/If-Modified-Since和ETag/If-None-Match。Koa-static中间件内置了ETag生成和Last-Modified处理。
缓存破坏技术
// 在构建过程中添加hash
app.use(static('dist', {
setHeaders: (res) => {
res.setHeader('Cache-Control', 'public, max-age=31536000')
}
}))
对于频繁更新的资源,推荐使用内容hash作为文件名(如main.a1b2c3d4.js),配合长期缓存策略。Webpack等构建工具可以自动完成hash生成。
资源压缩与合并
Gzip/Brotli压缩
const compress = require('koa-compress')
app.use(compress({
threshold: 2048,
gzip: {
level: 9
},
br: false // 禁用Brotli,需要Node 11.7.0+
}))
Koa-compress中间件支持实时压缩响应数据。建议对文本资源(HTML/CSS/JS)启用压缩,图片等二进制文件通常已压缩。
资源合并策略
// 使用构建工具合并文件
// webpack.config.js
module.exports = {
optimization: {
splitChunks: {
chunks: 'all',
minSize: 30000
}
}
}
合并小文件减少HTTP请求,但需平衡缓存效率。Webpack的代码分割功能可以智能拆分和合并资源。
静态资源CDN加速
CDN配置示例
const staticCache = require('koa-static-cache')
app.use(staticCache({
prefix: '/cdn',
dir: '/opt/cdn',
maxAge: 365 * 24 * 60 * 60,
buffer: true
}))
通过koa-static-cache实现边缘缓存,配合CDN服务:
- 配置自定义域名(cdn.example.com)
- 开启HTTP/2协议
- 设置合理的缓存规则
- 启用智能压缩
图片优化方案
响应式图片处理
const sharp = require('sharp')
router.get('/image/:size/:name', async (ctx) => {
const { size, name } = ctx.params
const [width, height] = size.split('x')
ctx.body = await sharp(`uploads/${name}`)
.resize(Number(width), Number(height))
.webp({ quality: 80 })
.toBuffer()
})
使用Sharp中间件实现:
- 动态尺寸调整
- WebP格式转换
- 质量压缩
- 懒加载支持
图片懒加载实现
<img data-src="/images/hero.jpg" class="lazyload" alt="...">
<script>
document.addEventListener("DOMContentLoaded", () => {
const lazyImages = [].slice.call(document.querySelectorAll("img.lazyload"))
if ("IntersectionObserver" in window) {
const lazyImageObserver = new IntersectionObserver((entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
const lazyImage = entry.target
lazyImage.src = lazyImage.dataset.src
lazyImageObserver.unobserve(lazyImage)
}
})
})
lazyImages.forEach((lazyImage) => {
lazyImageObserver.observe(lazyImage)
})
}
})
</script>
字体文件优化
字体子集化
const fontmin = new Fontmin()
.src('fonts/SourceHanSansCN-Regular.ttf')
.use(Fontmin.glyph({
text: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
}))
.dest('build/fonts')
使用Fontmin工具:
- 提取必要字符集
- 生成woff2格式
- 设置正确MIME类型
字体加载策略
@font-face {
font-family: 'MyFont';
src: url('font.woff2') format('woff2');
font-display: swap;
}
关键CSS中预加载关键字体:
<link rel="preload" href="/fonts/important.woff2" as="font" crossorigin>
构建工具优化
Webpack配置示例
// webpack.config.js
module.exports = {
output: {
filename: '[name].[contenthash:8].js',
chunkFilename: '[name].[contenthash:8].chunk.js'
},
optimization: {
runtimeChunk: 'single',
splitChunks: {
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
chunks: 'all'
}
}
}
}
}
关键优化点:
- 持久化缓存(contenthash)
- 代码分割(SplitChunksPlugin)
- Tree Shaking
- Scope Hoisting
资源预加载技术
资源提示实现
<!-- DNS预解析 -->
<link rel="dns-prefetch" href="//cdn.example.com">
<!-- 预连接 -->
<link rel="preconnect" href="https://api.example.com" crossorigin>
<!-- 预加载关键资源 -->
<link rel="preload" href="/css/main.css" as="style">
<link rel="preload" href="/js/main.js" as="script">
<!-- 预取非关键资源 -->
<link rel="prefetch" href="/images/next-bg.jpg" as="image">
基于路由的代码分割
// 动态导入组件
const ProductPage = () => import(/* webpackPrefetch: true */ './ProductPage.vue')
// Koa路由配置
router.get('/products/:id', async (ctx) => {
const product = await getProduct(ctx.params.id)
await ctx.render('product', {
product,
scripts: [
{ src: `/js/product.chunk.js`, preload: true }
]
})
})
监控与持续优化
性能指标收集
// 前端性能监控
window.addEventListener('load', () => {
const timing = performance.timing
const metrics = {
dns: timing.domainLookupEnd - timing.domainLookupStart,
tcp: timing.connectEnd - timing.connectStart,
ttfb: timing.responseStart - timing.requestStart,
fcp: performance.getEntriesByName('first-contentful-paint')[0].startTime,
lcp: performance.getEntriesByName('largest-contentful-paint')[0].startTime
}
navigator.sendBeacon('/perf', JSON.stringify(metrics))
})
自动化优化流程
// 构建后分析
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer')
module.exports = {
plugins: [
new BundleAnalyzerPlugin({
analyzerMode: 'static',
reportFilename: 'bundle-report.html'
})
]
}
集成工具链:
- Lighthouse CI
- Webpack Bundle Analyzer
- 资源变化监控
- 自动化A/B测试
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益,请来信告知我们删除。邮箱:cc@cccx.cn