Skip to content

Static Assets Management

Proper management of static assets like images, fonts, CSS files, and other resources is essential for building professional documentation sites. This chapter covers how Rspress handles static assets and best practices for organizing them.

Understanding Static Assets

What Are Static Assets?

Static assets are files that don't need processing and are served directly to users:

  • Images: PNG, JPG, SVG, GIF, WebP
  • Fonts: WOFF, WOFF2, TTF, OTF
  • Stylesheets: CSS files
  • Documents: PDF, ZIP files
  • Media: Videos, audio files
  • Data: JSON, XML files

Asset Loading Strategies

Rspress provides multiple ways to handle assets:

  1. Public Directory: For assets referenced directly by URL
  2. Relative Imports: For assets processed by bundler
  3. External URLs: For CDN-hosted assets

Public Directory

Basic Usage

Place assets in the public directory to serve them directly:

my-rspress-site/
├── docs/
├── public/
│   ├── images/
│   │   ├── logo.png
│   │   └── screenshot.png
│   ├── fonts/
│   │   └── custom-font.woff2
│   └── favicon.ico
└── rspress.config.ts

Reference public assets with absolute paths:

markdown
<!-- In your Markdown files -->
![Logo](/images/logo.png)

<img src="/images/screenshot.png" alt="Screenshot" />

Subdirectory Organization

Organize assets by type:

public/
├── images/
│   ├── icons/
│   │   ├── check.svg
│   │   └── cross.svg
│   ├── screenshots/
│   │   ├── dashboard.png
│   │   └── settings.png
│   └── logos/
│       ├── logo-light.png
│       └── logo-dark.png
├── downloads/
│   ├── user-guide.pdf
│   └── template.zip
└── videos/
    └── demo.mp4

Base Path Configuration

If your site is deployed to a subdirectory:

typescript
// rspress.config.ts
export default defineConfig({
  base: '/my-docs/',  // Site deployed at example.com/my-docs/
});

Assets are automatically prefixed:

markdown
<!-- Automatically becomes /my-docs/images/logo.png -->
![Logo](/images/logo.png)

Image Handling

Basic Images

markdown
<!-- Relative to public directory -->
![Alt text](/images/photo.jpg)

<!-- With size attributes in HTML -->
<img src="/images/photo.jpg" width="600" height="400" alt="Photo" />

Responsive Images

Use the HTML picture element for responsive images:

markdown
<picture>
  <source media="(max-width: 768px)" srcset="/images/mobile.jpg" />
  <source media="(max-width: 1200px)" srcset="/images/tablet.jpg" />
  <img src="/images/desktop.jpg" alt="Responsive image" />
</picture>

Image Optimization

Optimize images before adding them:

bash
# Install image optimization tools
npm install -g imagemin-cli

# Optimize images
imagemin public/images/*.{jpg,png} --out-dir=public/images/optimized

# Or use online tools:
# - TinyPNG: https://tinypng.com/
# - Squoosh: https://squoosh.app/
# - ImageOptim (Mac): https://imageoptim.com/

SVG Images

SVG images work great for logos and icons:

markdown
<!-- Inline SVG -->
<svg width="100" height="100" viewBox="0 0 100 100">
  <circle cx="50" cy="50" r="40" fill="blue" />
</svg>

<!-- External SVG file -->
![Icon](/images/icon.svg)

Dark Mode Images

Provide different images for light/dark themes:

tsx
// components/ThemedImage.tsx
import { useTheme } from 'rspress/runtime';

export function ThemedImage({ lightSrc, darkSrc, alt }) {
  const { theme } = useTheme();

  return (
    <img
      src={theme === 'dark' ? darkSrc : lightSrc}
      alt={alt}
    />
  );
}
mdx
import { ThemedImage } from '../components/ThemedImage';

<ThemedImage
  lightSrc="/images/logo-light.png"
  darkSrc="/images/logo-dark.png"
  alt="Logo"
/>

Fonts

Custom Fonts

Add custom fonts to your site:

public/
└── fonts/
    ├── CustomFont-Regular.woff2
    ├── CustomFont-Bold.woff2
    └── CustomFont-Italic.woff2

Create a CSS file:

css
/* styles/fonts.css */
@font-face {
  font-family: 'CustomFont';
  src: url('/fonts/CustomFont-Regular.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: 'CustomFont';
  src: url('/fonts/CustomFont-Bold.woff2') format('woff2');
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}

Import in your config:

typescript
// rspress.config.ts
export default defineConfig({
  head: [
    ['link', { rel: 'stylesheet', href: '/styles/fonts.css' }],
  ],
  themeConfig: {
    // Apply font
  },
});

Google Fonts

Use Google Fonts via CDN:

typescript
// rspress.config.ts
export default defineConfig({
  head: [
    [
      'link',
      {
        rel: 'stylesheet',
        href: 'https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&display=swap',
      },
    ],
  ],
});

CSS and Stylesheets

Global Styles

Add global CSS:

public/
└── styles/
    └── custom.css
css
/* public/styles/custom.css */
:root {
  --primary-color: #007bff;
  --secondary-color: #6c757d;
}

.custom-container {
  max-width: 1200px;
  margin: 0 auto;
  padding: 20px;
}

.highlight {
  background-color: yellow;
  padding: 2px 4px;
}

Import in config:

typescript
// rspress.config.ts
export default defineConfig({
  head: [
    ['link', { rel: 'stylesheet', href: '/styles/custom.css' }],
  ],
});

Component Styles

Use CSS Modules for component-specific styles:

tsx
// components/Card.tsx
import styles from './Card.module.css';

export function Card({ children }) {
  return <div className={styles.card}>{children}</div>;
}
css
/* components/Card.module.css */
.card {
  border: 1px solid #ddd;
  border-radius: 8px;
  padding: 20px;
  margin: 20px 0;
}

Theme Override

Override default theme styles:

css
/* public/styles/theme-override.css */
/* Override navigation background */
.rspress-nav {
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
}

/* Override code block theme */
.rspress-code-block {
  border-radius: 12px;
}

/* Override sidebar width */
.rspress-sidebar {
  width: 280px;
}

Downloadable Assets

Documentation Files

Provide downloadable resources:

public/
└── downloads/
    ├── api-reference.pdf
    ├── quick-start-guide.pdf
    └── code-samples.zip

Link to them in your docs:

markdown
# Resources

Download our resources:

- [API Reference (PDF)](/downloads/api-reference.pdf)
- [Quick Start Guide (PDF)](/downloads/quick-start-guide.pdf)
- [Code Samples (ZIP)](/downloads/code-samples.zip)

File Size Display

Show file sizes for downloads:

tsx
// components/DownloadLink.tsx
export function DownloadLink({ href, size, children }) {
  return (
    <a href={href} download className="download-link">
      {children}
      <span className="file-size">({size})</span>
    </a>
  );
}
mdx
import { DownloadLink } from '../components/DownloadLink';

<DownloadLink href="/downloads/guide.pdf" size="2.5 MB">
  Download User Guide
</DownloadLink>

Video and Audio

Embedded Videos

Embed video files:

markdown
<video controls width="100%">
  <source src="/videos/tutorial.mp4" type="video/mp4" />
  <source src="/videos/tutorial.webm" type="video/webm" />
  Your browser doesn't support video playback.
</video>

YouTube/Vimeo Embeds

markdown
<!-- YouTube -->
<iframe
  width="560"
  height="315"
  src="https://www.youtube.com/embed/VIDEO_ID"
  frameborder="0"
  allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
  allowfullscreen
></iframe>

<!-- Vimeo -->
<iframe
  src="https://player.vimeo.com/video/VIDEO_ID"
  width="640"
  height="360"
  frameborder="0"
  allow="autoplay; fullscreen"
  allowfullscreen
></iframe>

Audio Files

markdown
<audio controls>
  <source src="/audio/podcast.mp3" type="audio/mpeg" />
  <source src="/audio/podcast.ogg" type="audio/ogg" />
  Your browser doesn't support audio playback.
</audio>

Favicon and Meta Images

Favicon

Add favicon files:

public/
├── favicon.ico
├── favicon-16x16.png
├── favicon-32x32.png
└── apple-touch-icon.png

Configure in rspress.config.ts:

typescript
export default defineConfig({
  icon: '/favicon.ico',
  head: [
    ['link', { rel: 'icon', type: 'image/png', sizes: '16x16', href: '/favicon-16x16.png' }],
    ['link', { rel: 'icon', type: 'image/png', sizes: '32x32', href: '/favicon-32x32.png' }],
    ['link', { rel: 'apple-touch-icon', sizes: '180x180', href: '/apple-touch-icon.png' }],
  ],
});

Open Graph Images

Add social media preview images:

typescript
export default defineConfig({
  head: [
    ['meta', { property: 'og:image', content: '/images/og-image.png' }],
    ['meta', { property: 'og:image:width', content: '1200' }],
    ['meta', { property: 'og:image:height', content: '630' }],
    ['meta', { name: 'twitter:card', content: 'summary_large_image' }],
    ['meta', { name: 'twitter:image', content: '/images/twitter-card.png' }],
  ],
});

Asset Optimization

Image Formats

Choose appropriate formats:

  • JPEG: Photos, complex images with many colors
  • PNG: Graphics with transparency, screenshots
  • SVG: Logos, icons, simple graphics
  • WebP: Modern format, best compression (with fallbacks)

Compression

Compress assets for faster loading:

bash
# JPG/PNG compression
imagemin public/images/*.{jpg,png} --plugin.webp --out-dir=public/images/compressed

# SVG optimization
npx svgo public/images/*.svg

Lazy Loading

Lazy load images for better performance:

markdown
<img src="/images/large-image.jpg" loading="lazy" alt="Large image" />

CDN Usage

Host large assets on CDN:

markdown
<!-- Local asset -->
![Slow](/images/very-large-image.jpg)

<!-- CDN asset (faster) -->
![Fast](https://cdn.example.com/images/very-large-image.jpg)

Best Practices

File Naming

Use consistent, descriptive names:

✅ Good:
- dashboard-screenshot-2024.png
- user-authentication-flow.svg
- api-integration-guide.pdf

❌ Bad:
- IMG_1234.png
- pic.svg
- download.pdf

Organization

Organize by purpose or type:

public/
├── images/
│   ├── features/      # Feature images
│   ├── tutorials/     # Tutorial screenshots
│   └── ui/            # UI elements
├── downloads/
│   ├── guides/        # User guides
│   └── samples/       # Code samples
└── media/
    ├── videos/        # Video content
    └── audio/         # Audio content

File Sizes

Keep file sizes reasonable:

  • Images: < 200KB (optimize larger images)
  • Documents: < 10MB
  • Videos: Use streaming services for large videos

Alt Text

Always provide alt text for images:

markdown
✅ Good:
![Dashboard showing user analytics with graphs](/images/dashboard.png)

❌ Bad:
![](/images/dashboard.png)

Troubleshooting

Images Not Loading

  1. Check file path: Ensure path is correct
markdown
<!-- Wrong -->
![Image](images/photo.jpg)

<!-- Correct -->
![Image](/images/photo.jpg)
  1. Verify file exists: Check public directory

  2. Check base path: Ensure base path is configured

Large File Sizes

bash
# Check file sizes
du -h public/images/*

# Files > 1MB should be optimized
find public -type f -size +1M

404 Errors

bash
# Build and check output
npm run build

# Verify files in output
ls -R doc_build/

Performance Tips

Optimize Loading

  1. Use WebP format with fallbacks
  2. Implement lazy loading for below-fold images
  3. Use appropriate dimensions (don't load 4K images for thumbnails)
  4. Enable compression on your server
  5. Use CDN for static assets

Cache Headers

Configure caching for static assets:

typescript
// For custom server deployment
app.use('/images', express.static('public/images', {
  maxAge: '1y',
  immutable: true,
}));

Next Steps


Best Practices

  • Optimize images before adding them
  • Use appropriate image formats
  • Provide alt text for accessibility
  • Organize assets logically
  • Consider lazy loading for large images

File Size

  • Keep images under 200KB when possible
  • Compress PDFs before upload
  • Use video streaming services for large videos
  • Test loading times on slow connections

Tools

Content is for learning and research only.