CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-svelte-preprocess

A Svelte preprocessor wrapper with baked-in support for commonly used preprocessors

Pending
Overview
Eval results
Files

utility-processing.mddocs/

Utility Processing

String replacement and content manipulation utilities for preprocessing markup and script content.

Capabilities

Replace Processing

String replacement processor for find-and-replace operations on markup content, supporting both string and regex patterns.

/**
 * Creates replace preprocessor for markup blocks
 * @param options - Array of replacement patterns
 * @returns PreprocessorGroup with markup preprocessing
 */
function replace(options: Options.Replace): PreprocessorGroup;

namespace Options {
  type Replace = Array<
    | [string | RegExp, string]
    | [RegExp, (substring: string, ...args: any[]) => string]
  >;
}

Usage Examples:

import { replace } from "svelte-preprocess";

// Basic string replacements
const preprocess = {
  markup: replace([
    // Simple string replacement
    ['__VERSION__', '1.0.0'],
    ['__BUILD_DATE__', new Date().toISOString()],
    
    // Environment variables
    ['process.env.NODE_ENV', JSON.stringify(process.env.NODE_ENV)],
    ['process.env.API_URL', JSON.stringify(process.env.API_URL || 'http://localhost:3000')]
  ])
};

// Regex replacements
const preprocess = {
  markup: replace([
    // Remove debug comments
    [/<!--\s*DEBUG:.*?-->/g, ''],
    
    // Replace placeholder URLs
    [/https?:\/\/placeholder\.com/g, 'https://api.example.com'],
    
    // Transform custom syntax
    [/\{\{(\w+)\}\}/g, '{$1}'] // Convert {{variable}} to {variable}
  ])
};

// Function-based replacements  
const preprocess = {
  markup: replace([
    // Dynamic replacements with custom logic
    [/\{\{DATE:([^}]+)\}\}/g, (match, format) => {
      return new Intl.DateTimeFormat('en-US', { 
        dateStyle: format 
      }).format(new Date());
    }],
    
    // Template processing
    [/\{\{INCLUDE:([^}]+)\}\}/g, (match, filename) => {
      return require('fs').readFileSync(filename, 'utf-8');
    }]
  ])
};

Integration with Auto Preprocessor

The replace processor integrates with the auto preprocessor and is applied early in the processing pipeline:

import { sveltePreprocess } from "svelte-preprocess";

const preprocess = sveltePreprocess({
  // Replace processing happens first, before other markup processing
  replace: [
    ['__VERSION__', process.env.npm_package_version],
    ['__API_URL__', process.env.API_URL],
    [/\{\{(\w+)\}\}/g, '{$1}'] // Template syntax conversion
  ],
  
  // Then other processors
  pug: true,
  typescript: true,
  scss: true
});

Processing order in auto preprocessor:

  1. Replace processing (applied to markup)
  2. Markup processing (Pug, etc.)
  3. Script and style processing

Common Use Cases

Environment Variable Injection

const preprocess = sveltePreprocess({
  replace: [
    // Build-time constants
    ['__VERSION__', JSON.stringify(process.env.npm_package_version)],
    ['__BUILD_TIMESTAMP__', JSON.stringify(Date.now())],
    
    // Environment configuration
    ['__API_BASE_URL__', JSON.stringify(process.env.API_BASE_URL)],
    ['__DEBUG_MODE__', JSON.stringify(process.env.NODE_ENV === 'development')],
    
    // Feature flags
    ['__FEATURE_NEW_UI__', JSON.stringify(process.env.FEATURE_NEW_UI === 'true')]
  ]
});

Then use in components:

<script>
  const apiUrl = __API_BASE_URL__;
  const version = __VERSION__;
  const debugMode = __DEBUG_MODE__;
</script>

<div class="app-info">
  <p>Version: {version}</p>
  {#if debugMode}
    <p>API URL: {apiUrl}</p>
  {/if}
</div>

Template Syntax Conversion

// Convert from other template syntaxes to Svelte
const preprocess = sveltePreprocess({
  replace: [
    // Vue-style template syntax to Svelte
    [/v-if="([^"]+)"/g, '{#if $1}'],
    [/v-for="(\w+) in (\w+)"/g, '{#each $2 as $1}'],
    [/\{\{([^}]+)\}\}/g, '{$1}'],
    
    // Angular-style to Svelte
    [/\*ngIf="([^"]+)"/g, '{#if $1}'],
    [/\*ngFor="let (\w+) of (\w+)"/g, '{#each $2 as $1}'],
    
    // React-style class binding
    [/className=\{([^}]+)\}/g, 'class={$1}']
  ]
});

Content Generation

const fs = require('fs');
const path = require('path');

const preprocess = sveltePreprocess({
  replace: [
    // Include external content
    [/\{\{INCLUDE:([^}]+)\}\}/g, (match, filename) => {
      try {
        return fs.readFileSync(path.resolve(filename), 'utf-8');
      } catch (err) {
        console.warn(`Could not include file: ${filename}`);
        return '';
      }
    }],
    
    // Generate component imports
    [/\{\{AUTO_IMPORTS:([^}]+)\}\}/g, (match, directory) => {
      const files = fs.readdirSync(directory)
        .filter(file => file.endsWith('.svelte'))
        .map(file => {
          const name = path.basename(file, '.svelte');
          return `import ${name} from './${directory}/${file}';`;
        });
      return files.join('\n');
    }],
    
    // Generate type definitions
    [/\{\{TYPE_EXPORTS\}\}/g, () => {
      const types = ['User', 'Product', 'Order']; // from some source
      return types.map(type => `export type { ${type} };`).join('\n');
    }]
  ]
});

Conditional Compilation

const preprocess = sveltePreprocess({
  replace: [
    // Development-only code blocks
    [/\/\* DEV_START \*\/[\s\S]*?\/\* DEV_END \*\//g, 
      process.env.NODE_ENV === 'development' ? '$&' : ''
    ],
    
    // Production-only code blocks  
    [/\/\* PROD_START \*\/([\s\S]*?)\/\* PROD_END \*\//g,
      process.env.NODE_ENV === 'production' ? '$1' : ''
    ],
    
    // Feature flag blocks
    [/\/\* FEATURE:(\w+)_START \*\/([\s\S]*?)\/\* FEATURE:\1_END \*\//g, 
      (match, featureName, content) => {
        return process.env[`FEATURE_${featureName.toUpperCase()}`] === 'true' ? content : '';
      }
    ]
  ]
});

Then use in templates:

<!-- This block only appears in development -->
/* DEV_START */
<div class="debug-panel">
  <h3>Debug Information</h3>
  <pre>{JSON.stringify($page, null, 2)}</pre>
</div>
/* DEV_END */

<!-- This block only appears in production -->
/* PROD_START */
<script async src="https://analytics.example.com/script.js"></script>
/* PROD_END */

<!-- Feature flag controlled content -->
/* FEATURE:NEW_HEADER_START */
<header class="new-header">
  <h1>New Design</h1>
</header>
/* FEATURE:NEW_HEADER_END */

CSS Custom Property Injection

const preprocess = sveltePreprocess({
  replace: [
    // Inject CSS custom properties
    ['/* CSS_VARS */', () => {
      const theme = require('./theme.json');
      return Object.entries(theme)
        .map(([key, value]) => `--${key}: ${value};`)
        .join('\n    ');
    }]
  ]
});
<style>
  :root {
    /* CSS_VARS */
  }
</style>

Advanced Patterns

Multi-step Processing

const preprocess = sveltePreprocess({
  replace: [
    // Step 1: Process includes
    [/\{\{INCLUDE:([^}]+)\}\}/g, (match, file) => fs.readFileSync(file, 'utf-8')],
    
    // Step 2: Process variables (after includes)
    [/__(\w+)__/g, (match, varName) => process.env[varName] || match],
    
    // Step 3: Clean up markers
    [/\/\* MARKER:.*?\*\//g, '']
  ]
});

Internationalization

const translations = require('./i18n/en.json');

const preprocess = sveltePreprocess({
  replace: [
    // Replace translation keys
    [/\{\{t:([^}]+)\}\}/g, (match, key) => {
      return translations[key] || key;
    }],
    
    // Replace pluralization
    [/\{\{plural:(\w+):(\d+)\}\}/g, (match, key, count) => {
      const pluralKey = count === '1' ? key : `${key}_plural`;
      return translations[pluralKey] || key;
    }]
  ]
});

Build Optimization

const preprocess = sveltePreprocess({
  replace: [
    // Remove console.log in production
    process.env.NODE_ENV === 'production' && [/console\.log\([^)]*\);?/g, ''],
    
    // Remove comments in production
    process.env.NODE_ENV === 'production' && [/\/\*[\s\S]*?\*\//g, ''],
    process.env.NODE_ENV === 'production' && [/\/\/.*$/gm, ''],
    
    // Minify whitespace in production
    process.env.NODE_ENV === 'production' && [/\s{2,}/g, ' ']
  ].filter(Boolean)
});

Error Handling

const preprocess = sveltePreprocess({
  replace: [
    // Safe file inclusion with error handling
    [/\{\{SAFE_INCLUDE:([^}]+)\}\}/g, (match, filename) => {
      try {
        return fs.readFileSync(filename, 'utf-8');
      } catch (error) {
        console.warn(`Warning: Could not include ${filename}: ${error.message}`);
        return `<!-- Could not include ${filename} -->`;
      }
    }],
    
    // Environment variable with fallback
    [/__ENV:(\w+)(?::([^_]+))?__/g, (match, varName, fallback = '') => {
      const value = process.env[varName];
      if (value === undefined) {
        console.warn(`Warning: Environment variable ${varName} is not defined`);
        return fallback;
      }
      return value;
    }]
  ]
});

Types

type Replace = Array<
  | [string | RegExp, string]
  | [RegExp, (substring: string, ...args: any[]) => string]
>;

interface ReplacementPattern {
  /** String or RegExp to match */
  0: string | RegExp;
  
  /** Replacement string or function */
  1: string | ((substring: string, ...args: any[]) => string);
}

Install with Tessl CLI

npx tessl i tessl/npm-svelte-preprocess

docs

auto-preprocessing.md

css-preprocessing.md

index.md

javascript.md

postcss.md

template-processing.md

typescript.md

utility-processing.md

tile.json