A Svelte preprocessor wrapper with baked-in support for commonly used preprocessors
—
String replacement and content manipulation utilities for preprocessing markup and script content.
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');
}]
])
};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:
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>// 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}']
]
});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');
}]
]
});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 */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>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, '']
]
});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;
}]
]
});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)
});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;
}]
]
});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