CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-vite-plugin-css-injected-by-js

A Vite plugin that injects CSS into JavaScript bundles for single-file applications.

Pending
Overview
Eval results
Files

custom-injection.mddocs/

Custom Injection

Advanced customization of CSS injection behavior with custom JavaScript code and runtime functions.

Capabilities

Custom Injection Types

Type definitions for custom CSS injection functions.

/**
 * Function that returns JavaScript code string for CSS injection
 * @param cssCode - CSS code to inject (as string literal)
 * @param options - Injection configuration options
 * @returns JavaScript code string that will inject the CSS
 */
type InjectCode = (cssCode: string, options: InjectCodeOptions) => string;

/**
 * Runtime function that directly injects CSS into the DOM
 * @param cssCode - CSS code to inject
 * @param options - Injection configuration options
 */
type InjectCodeFunction = (cssCode: string, options: InjectCodeOptions) => void;

/**
 * Options passed to injection functions
 */
interface InjectCodeOptions {
  /** Style element ID or generator function */
  styleId?: string | (() => string);
  /** Enable strict CSP support with nonce */
  useStrictCSP?: boolean;
  /** Additional attributes for the style element */
  attributes?: { [key: string]: string } | undefined;
}

Custom Injection Code

Provide a function that returns JavaScript code for CSS injection.

/**
 * Custom CSS injection code function
 * Returns JavaScript code that will be executed to inject CSS
 */
injectCode?: InjectCode;

Usage Examples:

import { defineConfig } from "vite";
import cssInjectedByJsPlugin from "vite-plugin-css-injected-by-js";

// Basic custom injection code
export default defineConfig({
  plugins: [
    cssInjectedByJsPlugin({
      injectCode: (cssCode, options) => {
        return `
          try {
            if (typeof document !== 'undefined') {
              var style = document.createElement('style');
              ${options.styleId ? `style.id = '${options.styleId}';` : ''}
              style.appendChild(document.createTextNode(${cssCode}));
              document.head.appendChild(style);
            }
          } catch (e) {
            console.error('CSS injection failed:', e);
          }
        `;
      },
    }),  
  ],
});

// Advanced injection with error handling and CSP
export default defineConfig({
  plugins: [
    cssInjectedByJsPlugin({
      injectCode: (cssCode, options) => {
        let attributeCode = '';
        
        // Add style ID if provided
        if (options.styleId) {
          attributeCode += `style.id = '${options.styleId}';`;
        }
        
        // Add CSP nonce if enabled
        if (options.useStrictCSP) {
          attributeCode += `
            var nonceMeta = document.head.querySelector('meta[property="csp-nonce"]');
            if (nonceMeta) style.nonce = nonceMeta.content;
          `;
        }
        
        // Add custom attributes
        if (options.attributes) {
          for (const [key, value] of Object.entries(options.attributes)) {
            attributeCode += `style.setAttribute('${key}', '${value}');`;
          }
        }
        
        return `
          try {
            if (typeof document !== 'undefined') {
              var style = document.createElement('style');
              ${attributeCode}
              style.appendChild(document.createTextNode(${cssCode}));
              document.head.appendChild(style);
            }
          } catch (e) {
            console.error('vite-plugin-css-injected-by-js injection failed:', e);
          }
        `;
      },
    }),
  ],
});

Custom Injection Runtime Function

Provide a runtime function that directly injects CSS into the DOM.

/**
 * Custom CSS injection runtime function
 * Executed directly at runtime to inject CSS
 */
injectCodeFunction?: InjectCodeFunction;

Usage Examples:

// Basic runtime injection function
export default defineConfig({
  plugins: [
    cssInjectedByJsPlugin({
      injectCodeFunction: (cssCode, options) => {
        try {
          if (typeof document !== 'undefined') {
            const style = document.createElement('style');
            
            // Set style ID if provided
            if (options.styleId) {
              style.id = options.styleId;
            }
            
            // Set CSP nonce if enabled
            if (options.useStrictCSP) {
              const nonceMeta = document.head.querySelector('meta[property="csp-nonce"]');
              if (nonceMeta) {
                style.nonce = nonceMeta.content;
              }
            }
            
            // Set custom attributes
            if (options.attributes) {
              for (const [key, value] of Object.entries(options.attributes)) {
                style.setAttribute(key, value);
              }
            }
            
            style.appendChild(document.createTextNode(cssCode));
            document.head.appendChild(style);
          }
        } catch (error) {
          console.error('CSS injection failed:', error);
        }
      },
    }),
  ],
});

// Advanced runtime function with insertion control
export default defineConfig({
  plugins: [
    cssInjectedByJsPlugin({
      injectCodeFunction: (cssCode, options) => {
        try {
          if (typeof document !== 'undefined') {
            const style = document.createElement('style');
            
            // Configure style element
            if (options.styleId) {
              style.id = options.styleId;
            }
            
            // Add all custom attributes
            if (options.attributes) {
              Object.entries(options.attributes).forEach(([key, value]) => {
                style.setAttribute(key, value);
              });
            }
            
            // Handle CSP nonce
            if (options.useStrictCSP) {
              const nonceMeta = document.head.querySelector('meta[property="csp-nonce"]');
              if (nonceMeta?.content) {
                style.nonce = nonceMeta.content;
              }
            }
            
            // Insert CSS content
            style.appendChild(document.createTextNode(cssCode));
            
            // Insert at specific position (after title if exists)
            const title = document.head.querySelector('title');
            if (title) {
              document.head.insertBefore(style, title.nextSibling);
            } else {
              document.head.appendChild(style);
            }
          }
        } catch (error) {
          console.error('vite-plugin-css-injected-by-js:', error);
        }
      },
    }),
  ],
});

Injection Options

Configuration options passed to custom injection functions.

/**
 * Options passed to injection functions
 */
interface InjectCodeOptions {
  /** Style element ID or generator function */
  styleId?: string | (() => string);
  /** Enable strict CSP support with nonce */
  useStrictCSP?: boolean;
  /** Additional attributes for the style element */
  attributes?: { [key: string]: string } | undefined;
}

Option Details:

  • styleId: Sets the id attribute on the created style element
  • useStrictCSP: Enables Content Security Policy support by reading nonce from meta tag
  • attributes: Additional attributes to set on the style element (includes development mode attributes)

Development Mode Integration

Custom injection functions work with development mode and receive additional attributes:

// Development mode aware injection
injectCodeFunction: (cssCode, options) => {
  try {
    if (typeof document !== 'undefined') {
      const style = document.createElement('style');
      
      // Handle all attributes (including dev mode attributes)
      if (options.attributes) {
        Object.entries(options.attributes).forEach(([key, value]) => {
          style.setAttribute(key, value);
        });
      }
      
      // In development mode, attributes will include:
      // { "data-vite-dev-id": "path/to/file.css" }
      
      style.appendChild(document.createTextNode(cssCode));
      document.head.appendChild(style);
    }
  } catch (error) {
    console.error('CSS injection failed:', error);
  }
}

Content Security Policy Support

When useStrictCSP is enabled, injection functions should read the nonce from a meta tag:

// CSP-compliant injection
injectCodeFunction: (cssCode, options) => {
  try {
    if (typeof document !== 'undefined') {
      const style = document.createElement('style');
      
      if (options.useStrictCSP) {
        // Read nonce from meta tag
        const nonceMeta = document.head.querySelector('meta[property="csp-nonce"]');
        if (nonceMeta?.content) {
          style.nonce = nonceMeta.content;
        }
      }
      
      style.appendChild(document.createTextNode(cssCode));
      document.head.appendChild(style);
    }
  } catch (error) {
    console.error('CSS injection failed:', error);
  }
}

Required HTML meta tag:

<meta property="csp-nonce" content="your-nonce-value" />

Error Handling Best Practices

Custom injection functions should include proper error handling:

injectCodeFunction: (cssCode, options) => {
  try {
    // Check for document availability (SSR compatibility)
    if (typeof document === 'undefined') {
      return;
    }
    
    // Create and configure style element
    const style = document.createElement('style');
    
    // Apply all options safely
    if (options.styleId) {
      style.id = options.styleId;
    }
    
    if (options.attributes) {
      Object.entries(options.attributes).forEach(([key, value]) => {
        try {
          style.setAttribute(key, value);
        } catch (attrError) {
          console.warn(`Failed to set attribute ${key}:`, attrError);
        }
      });
    }
    
    if (options.useStrictCSP) {
      const nonceMeta = document.head.querySelector('meta[property="csp-nonce"]');
      if (nonceMeta?.content) {
        style.nonce = nonceMeta.content;
      }
    }
    
    // Insert CSS content
    style.appendChild(document.createTextNode(cssCode));
    document.head.appendChild(style);
    
  } catch (error) {
    // Use the plugin's error prefix for consistency
    console.error('vite-plugin-css-injected-by-js:', error);
  }
}

Install with Tessl CLI

npx tessl i tessl/npm-vite-plugin-css-injected-by-js

docs

configuration.md

custom-injection.md

development-mode.md

index.md

tile.json