CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-html-loader

Webpack loader for processing HTML files with asset handling and minification capabilities

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

content-processing.mddocs/

Content Processing

HTML Loader provides preprocessor and postprocessor hooks for custom HTML transformations, enabling integration with template engines and other processing tools.

Capabilities

Preprocessor Function

Process HTML content before html-loader handles asset imports and minification.

/**
 * Preprocessor function for custom HTML transformations before processing
 * @param content - Raw HTML content as a string
 * @param loaderContext - Webpack loader context object
 * @returns Processed HTML content (must be valid HTML)
 */
type PreprocessorFunction = (
  content: string,
  loaderContext: LoaderContext
) => string | Promise<string>;

interface LoaderContext {
  /** Path to the current file being processed */
  resourcePath: string;
  /** Directory context for the loader */
  context: string;
  /** Webpack mode (development/production) */
  mode?: string;
  /** Function to emit error messages */
  emitError: (error: Error) => void;
  /** Get loader options */
  getOptions: (schema?: object) => any;
}

Usage Examples:

// Handlebars template processing
const Handlebars = require("handlebars");

{
  test: /\.hbs$/i,
  loader: "html-loader",
  options: {
    preprocessor: (content, loaderContext) => {
      let result;
      
      try {
        result = Handlebars.compile(content)({
          title: "My App",
          version: "1.0.0"
        });
      } catch (error) {
        loaderContext.emitError(error);
        return content;
      }
      
      return result;
    }
  }
}

// Async preprocessing with PostHTML
const posthtml = require("posthtml");
const posthtmlWebp = require("posthtml-webp");

{
  test: /\.html$/i,
  loader: "html-loader",
  options: {
    preprocessor: async (content, loaderContext) => {
      try {
        const result = await posthtml()
          .use(posthtmlWebp())
          .process(content);
        return result.html;
      } catch (error) {
        loaderContext.emitError(error);
        return content;
      }
    }
  }
}

// Environment-based processing
{
  test: /\.html$/i,
  loader: "html-loader",
  options: {
    preprocessor: (content, loaderContext) => {
      const isDevelopment = loaderContext.mode === 'development';
      
      // Remove analytics scripts in development
      if (isDevelopment) {
        content = content.replace(
          /<script[^>]*google-analytics[^>]*>[\s\S]*?<\/script>/gi,
          ''
        );
      }
      
      return content;
    }
  }
}

Postprocessor Function

Process the generated JavaScript module code after html-loader has handled asset imports and minification.

/**
 * Postprocessor function for custom transformations of generated module code
 * @param content - Generated JavaScript module code as a string
 * @param loaderContext - Webpack loader context object
 * @returns Processed JavaScript module code
 */
type PostprocessorFunction = (
  content: string,
  loaderContext: LoaderContext
) => string | Promise<string>;

Generated Code Context:

The postprocessor receives the final JavaScript module code that html-loader generates, which includes:

  • Import statements for assets
  • HTML content as a string (potentially minified)
  • Export statement

Usage Examples:

// Template literal transformation
{
  test: /\.html$/i,
  loader: "html-loader",
  options: {
    postprocessor: (content, loaderContext) => {
      // Detect if template literals are supported
      const isTemplateLiteralSupported = content[0] === "`";
      
      // Transform <%= %> syntax to template literal or string concatenation
      return content
        .replace(/<%=/g, isTemplateLiteralSupported ? `\${` : '" +')
        .replace(/%>/g, isTemplateLiteralSupported ? "}" : '+ "');
    }
  }
}

// Add runtime transformations
{
  test: /\.html$/i,
  loader: "html-loader",
  options: {
    postprocessor: (content, loaderContext) => {
      // Add custom runtime processing
      const runtimeCode = `
        // Custom runtime transformation
        function processHtml(html) {
          return html.replace(/{{(\w+)}}/g, (match, key) => {
            return window.templateVars && window.templateVars[key] || match;
          });
        }
      `;
      
      // Wrap the exported HTML in the processing function
      return content.replace(
        /export default (.*);$/,
        `${runtimeCode}\nexport default processHtml($1);`
      );
    }
  }
}

// Async postprocessing
{
  test: /\.html$/i,
  loader: "html-loader",
  options: {
    postprocessor: async (content, loaderContext) => {
      const processedContent = await someAsyncTransformation(content);
      return processedContent;
    }
  }
}

Template Engine Integration

Common patterns for integrating template engines with html-loader.

/**
 * Template engine integration patterns
 */

Handlebars Integration:

const Handlebars = require("handlebars");

// Register helpers
Handlebars.registerHelper('json', function(context) {
  return JSON.stringify(context);
});

{
  test: /\.hbs$/i,
  loader: "html-loader",
  options: {
    preprocessor: (content, loaderContext) => {
      const template = Handlebars.compile(content);
      
      // Get data from various sources
      const templateData = {
        // From loader context
        filename: path.basename(loaderContext.resourcePath),
        // From environment
        isDev: process.env.NODE_ENV === 'development',
        // From package.json
        version: require('./package.json').version
      };
      
      try {
        return template(templateData);
      } catch (error) {
        loaderContext.emitError(new Error(`Handlebars error: ${error.message}`));
        return content;
      }
    }
  }
}

Mustache Integration:

const Mustache = require("mustache");

{
  test: /\.mustache$/i,
  loader: "html-loader",
  options: {
    preprocessor: (content, loaderContext) => {
      const view = {
        title: "My Application",
        items: ['Item 1', 'Item 2', 'Item 3']
      };
      
      return Mustache.render(content, view);
    }
  }
}

EJS Integration:

const ejs = require("ejs");

{
  test: /\.ejs$/i,
  loader: "html-loader",
  options: {
    preprocessor: async (content, loaderContext) => {
      try {
        return await ejs.render(content, {
          filename: loaderContext.resourcePath,
          title: "My App",
          env: process.env.NODE_ENV
        });
      } catch (error) {
        loaderContext.emitError(error);
        return content;
      }
    }
  }
}

Error Handling

Best practices for error handling in preprocessor and postprocessor functions.

/**
 * Error handling patterns for content processing
 */

Error Handling Examples:

{
  test: /\.html$/i,
  loader: "html-loader",
  options: {
    preprocessor: (content, loaderContext) => {
      try {
        // Your processing logic here
        return processContent(content);
      } catch (error) {
        // Emit error to webpack
        loaderContext.emitError(
          new Error(`Preprocessor error in ${loaderContext.resourcePath}: ${error.message}`)
        );
        
        // Return original content to prevent build failure
        return content;
      }
    },
    
    postprocessor: (content, loaderContext) => {
      try {
        return transformGeneratedCode(content);
      } catch (error) {
        // Log error with context
        const contextualError = new Error(
          `Postprocessor error in ${loaderContext.resourcePath}: ${error.message}\n` +
          `Generated code: ${content.substring(0, 200)}...`
        );
        
        loaderContext.emitError(contextualError);
        return content;
      }
    }
  }
}

// Async error handling
{
  test: /\.html$/i,
  loader: "html-loader",
  options: {
    preprocessor: async (content, loaderContext) => {
      try {
        const result = await asyncProcessing(content);
        return result;
      } catch (error) {
        // Emit async errors properly
        await loaderContext.emitError(error);
        return content;
      }
    }
  }
}

Processing Order

Understanding the order of operations in html-loader.

/**
 * Processing order in html-loader:
 * 1. Preprocessor (if configured)
 * 2. Asset/source processing (src, href, etc.)
 * 3. HTML minification (if enabled)
 * 4. JavaScript code generation
 * 5. Postprocessor (if configured)
 * 6. Module export
 */

Timing Considerations:

// Preprocessor: Modify HTML before any html-loader processing
preprocessor: (content) => {
  // Content is raw HTML
  // Perfect for template compilation, variable substitution
  return processedHtml;
},

// Postprocessor: Modify generated JavaScript
postprocessor: (content) => {
  // Content is generated JavaScript module code
  // Perfect for code transformations, additional exports
  return processedJavaScript;
}

When to Use Each:

  • Preprocessor: Template compilation, conditional content, variable substitution, HTML transformation
  • Postprocessor: JavaScript code modification, adding runtime utilities, changing module format

Integration with Other Loaders:

// Multiple loaders with html-loader preprocessing
{
  test: /\.html$/i,
  use: [
    {
      loader: "html-loader",
      options: {
        preprocessor: (content) => {
          // html-loader preprocessing
          return content;
        }
      }
    }
  ]
},

// Separate preprocessing loader + html-loader
{
  test: /\.template$/i,
  use: [
    "html-loader",
    {
      loader: "template-loader", // Custom loader
      options: { /* template options */ }
    }
  ]
}

docs

asset-processing.md

content-processing.md

index.md

minification.md

runtime-utilities.md

tile.json