An open API service indexing awesome lists of open source software.

https://github.com/ropean/inline-assets

A zero-dependency Vite plugin and standalone utility to inline CSS, JavaScript, and SVG assets into HTML for single-file deployment.
https://github.com/ropean/inline-assets

inline-assets

Last synced: 3 months ago
JSON representation

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

Awesome Lists containing this project

README

          

# @ropean/inline-assets

[![Deploy Website](https://github.com/ropean/inline-assets/actions/workflows/deploy-to-cloudflare.yml/badge.svg)](https://github.com/ropean/inline-assets/actions/workflows/deploy-to-cloudflare.yml)
[![Live Site](https://img.shields.io/badge/live-inline-assets.ropean.org-purple)](https://inline-assets.ropean.org)
[![license](https://img.shields.io/npm/l/@ropean/inline-assets.svg)](https://github.com/ropean/inline-assets/blob/main/LICENSE)
[![npm version](https://img.shields.io/npm/v/@ropean/inline-assets.svg)](https://www.npmjs.com/package/@ropean/inline-assets)
[![downloads](https://img.shields.io/npm/dm/@ropean/inline-assets.svg)](https://www.npmjs.com/package/@ropean/inline-assets)

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 `` tags to `` 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

```bash
npm install @ropean/inline-assets -D
```

```bash
yarn add @ropean/inline-assets -D
```

```bash
pnpm add @ropean/inline-assets -D
```

## ๐Ÿš€ Usage

### As a Vite Plugin

```typescript
// 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.):

```javascript
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

```javascript
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

```typescript
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

```typescript
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:

```typescript
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:

```javascript
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

```javascript
// 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:

```javascript
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/`](examples/) directory for complete, runnable examples:

- ๐Ÿ“˜ **[Vite Plugin Usage](examples/vite-usage.js)** - Basic and advanced Vite plugin configurations
- ๐Ÿ”ง **[Standalone Function](examples/standalone-usage.js)** - Use with any build tool
- ๐Ÿ“ฆ **[Webpack Integration](examples/webpack-integration.js)** - Webpack plugin example
- ๐ŸŽฏ **[Rollup Integration](examples/rollup-integration.js)** - Rollup plugin example
- ๐ŸŒŠ **[Gulp Integration](examples/gulp-integration.js)** - Gulp task example
- ๐Ÿ“œ **[npm Scripts](examples/npm-script.js)** - Post-build script with error handling
- ๐ŸŽจ **[CSS Insert Position](examples/css-insert-position.js)** - CSS positioning strategies

### Quick Start Examples

<details>
<summary><b>Webpack Integration</b></summary>

```javascript
// 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](examples/webpack-integration.js)

</details>

<details>
<summary><b>Rollup Integration</b></summary>

```javascript
// 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](examples/rollup-integration.js)

</details>

<details>
<summary><b>npm Scripts</b></summary>

```json
{
"scripts": {
"build": "vite build",
"postbuild": "node inline-assets.js"
}
}
```

```javascript
// 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](examples/npm-script.js)

</details>

<details>
<summary><b>Gulp Integration</b></summary>

```javascript
// 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](examples/gulp-integration.js)

</details>

## ๐Ÿ› 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](https://github.com/ropean/inline-assets/issues)