npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@ropean/inline-assets

v1.0.3

Published

A zero-dependency utility to inline CSS, JavaScript, and SVG assets into HTML for single-file deployment. Works as a Vite plugin or standalone function with any build tool.

Readme

@ropean/inline-assets

Deploy Website Live Site license npm version downloads

A zero-dependency Vite plugin and standalone utility to inline CSS, JavaScript, and SVG assets into HTML for single-file deployment.

✨ Features

  • 🚀 Zero Dependencies - No external packages required
  • 🔌 Dual Mode - Use as Vite plugin or standalone function
  • 🎨 Inline CSS - Converts <link> tags to <style> tags
  • 📦 Inline JavaScript - Converts <script src> to inline <script>
  • 🖼️ Inline SVG - Converts SVG files to base64 data URIs
  • 🎯 Selective Inlining - Exclude specific files with patterns
  • 🧹 Auto Cleanup - Removes inlined files and empty directories
  • 📝 Custom Logger - Bring your own logger or use the built-in one
  • 🔧 TypeScript Support - Full type definitions included

📦 Installation

npm install @ropean/inline-assets -D
yarn add @ropean/inline-assets -D
pnpm add @ropean/inline-assets -D

🚀 Usage

As a Vite Plugin

// vite.config.ts
import { defineConfig } from 'vite';
import inlineAssets from '@ropean/inline-assets';

export default defineConfig({
  plugins: [
    inlineAssets({
      css: true,
      js: true,
      svg: { img: false, link: true },
      excludes: ['assets/large-file.js'],
    }),
  ],
});

As a Standalone Function

Perfect for use with any build tool (Webpack, Rollup, esbuild, etc.):

import { inlineAssets } from '@ropean/inline-assets';

// After your build process
await inlineAssets({
  htmlPath: './dist/index.html',
  css: true,
  js: true,
  svg: { img: true, link: true },
});

With Custom Logger

import { inlineAssets } from '@ropean/inline-assets';

const myLogger = {
  info: (msg) => console.log('[INFO]', msg),
  success: (msg) => console.log('[✓]', msg),
  warning: (msg) => console.warn('[⚠]', msg),
  error: (msg) => console.error('[✖]', msg),
};

await inlineAssets({
  htmlPath: './dist/index.html',
  logger: myLogger,
});

// Or disable logging completely
await inlineAssets({
  htmlPath: './dist/index.html',
  logger: false,
});

⚙️ Options

Vite Plugin Options

interface VitePluginOptions {
  /** Whether to inline CSS files (default: true) */
  css?: boolean;

  /** Whether to inline JavaScript files (default: true) */
  js?: boolean;

  /** SVG inlining options (default: { img: false, link: true }) */
  svg?:
    | boolean
    | {
        img?: boolean; // Inline SVG in <img> tags
        link?: boolean; // Inline SVG in <link> tags (favicon)
      };

  /** File patterns to exclude from inlining (default: []) */
  excludes?: string[];

  /** Distribution directory name (default: 'dist') */
  distDir?: string;

  /** HTML file name to process (default: 'index.html') */
  htmlFileName?: string;

  /** Where to insert inlined CSS (default: 'original') */
  cssInsertPosition?: 'original' | 'head-start' | 'head-end';

  /** Custom logger or false to disable (default: built-in logger) */
  logger?: LoggerInterface | false;
}

Standalone Function Options

interface InlineAssetsOptions {
  /** Path to the HTML file to process (required) */
  htmlPath: string;

  /** Base directory for resolving asset paths (default: HTML file's directory) */
  baseDir?: string;

  /** Whether to inline CSS files (default: true) */
  css?: boolean;

  /** Whether to inline JavaScript files (default: true) */
  js?: boolean;

  /** SVG inlining options (default: true) */
  svg?:
    | boolean
    | {
        img?: boolean;
        link?: boolean;
      };

  /** File patterns to exclude from inlining (default: []) */
  excludes?: string[];

  /** Whether to delete inlined asset files (default: true) */
  removeInlinedFiles?: boolean;

  /** Whether to remove empty directories (default: true) */
  cleanupEmptyDirs?: boolean;

  /** Where to insert inlined CSS (default: 'original') */
  cssInsertPosition?: 'original' | 'head-start' | 'head-end';

  /** Custom logger or false to disable (default: built-in logger) */
  logger?: LoggerInterface | false;
}

📝 Custom Logger Interface

Implement this interface to create your own logger:

interface LoggerInterface {
  info(message: string): void;
  success(message: string): void;
  warning(message: string): void;
  error(message: string): void;
  event?(message: string): void; // Optional
  file?(path: string): string; // Optional
  newline?(count?: number): void; // Optional
}

🎯 CSS Insert Position

Control where inlined CSS is placed in your HTML:

inlineAssets({
  cssInsertPosition: 'original', // Default: keep CSS at original <link> position
});

Available Options

  • 'original' (default) - Keeps CSS at the original <link> tag position

    • ✅ Preserves the order of CSS and JS
    • ✅ CSS appears before JS if that's how you structured it
    • ⚠️ May create multiple <style> tags if you have multiple CSS files
  • 'head-start' - Moves all CSS to the beginning of <head>

    • ✅ Optimal for performance (CSS loads first)
    • ✅ Single merged <style> tag
    • ⚠️ Changes the original order
  • 'head-end' - Moves all CSS to the end of <head>

    • ✅ Single merged <style> tag
    • ⚠️ CSS loads after other head elements

Example

// Keep CSS before JS (preserves order)
inlineAssets({
  cssInsertPosition: 'original',
});

// Optimize for performance (CSS at top)
inlineAssets({
  cssInsertPosition: 'head-start',
});

🎯 Exclusion Patterns

Exclude specific files from inlining:

inlineAssets({
  excludes: [
    'index.js', // Matches any file named 'index.js'
    'assets/vendor.js', // Matches 'assets/vendor.js' specifically
    'large-image.svg', // Matches any file named 'large-image.svg'
  ],
});

🔧 How It Works

Vite Plugin Mode

  1. Config Hook: Automatically configures Vite to extract CSS as a single file
  2. Build: Vite builds your project normally
  3. Close Bundle Hook: After build completes, inlines assets into HTML
  4. Cleanup: Removes inlined files and empty directories

Standalone Mode

  1. Reads the HTML file
  2. Finds all CSS, JS, and SVG references
  3. Inlines their content (CSS/JS as text, SVG as base64)
  4. Writes the modified HTML back
  5. Optionally removes inlined files

📊 Example Output

Before (3 files):

dist/
├── index.html
├── assets/
│   ├── index.css
│   └── index.js

After (1 file):

dist/
└── index.html  (with inlined CSS and JS)

🤝 Integration Examples

See the examples/ directory for complete, runnable examples:

Quick Start Examples

// webpack.config.js
const { inlineAssets } = require('@ropean/inline-assets');

module.exports = {
  plugins: [
    {
      apply: (compiler) => {
        compiler.hooks.done.tap('InlineAssets', async () => {
          await inlineAssets({ htmlPath: './dist/index.html' });
        });
      },
    },
  ],
};

👉 View full example

// rollup.config.js
import { inlineAssets } from '@ropean/inline-assets';

export default {
  plugins: [
    {
      name: 'inline-assets',
      closeBundle: async () => {
        await inlineAssets({ htmlPath: './dist/index.html' });
      },
    },
  ],
};

👉 View full example

{
  "scripts": {
    "build": "vite build",
    "postbuild": "node inline-assets.js"
  }
}
// inline-assets.js
import { inlineAssets } from '@ropean/inline-assets';

const result = await inlineAssets({
  htmlPath: './dist/index.html',
});

if (!result.success) {
  console.error('Failed to inline assets');
  process.exit(1);
}

👉 View full example with error handling

// gulpfile.js
import { inlineAssets } from '@ropean/inline-assets';
import gulp from 'gulp';

gulp.task('inline', async () => {
  await inlineAssets({ htmlPath: './dist/index.html' });
});

gulp.task('build', gulp.series('your-build-task', 'inline'));

👉 View full example with error handling

🐛 Troubleshooting

CSS not inlining properly?

Make sure you're not using cssCodeSplit: true in your Vite config. The plugin automatically sets this to false.

Assets not found?

Check that baseDir points to the correct directory where your assets are located.

Want to keep some files external?

Use the excludes option to prevent specific files from being inlined.

📄 License

MIT © ropean

🙏 Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

📮 Issues

Found a bug or have a feature request? Open an issue