A lightweight, zero-dependency universal preprocessor that enables conditional compilation through feature flags. Built for developers who need to maintain multiple builds or feature variants of their codebase without complex build tooling.
⚠ Testing Disclaimer: While this universal-preprocessor supports multiple file formats (JavaScript, TypeScript, Python, HTML, CSS, and plain text), it has been thoroughly tested only with JavaScript and JSX files. Other file types are supported but may require additional testing in your specific use case.
universal-preprocessor provides a simple yet powerful way to conditionally include or exclude code blocks based on feature flags. It supports multiple file formats and comment styles, making it versatile for various project types.
- Zero Dependencies: No external libraries required
- Multiple File Format Support: Works with JavaScript, TypeScript, Python, HTML, CSS, and plain text files
- Robust Error Handling: Comprehensive validation with helpful error messages
- Nested Directives: Full support for nested conditional blocks
- CLI Integration: Easy integration into build pipelines
- Cross-Platform: Works on Windows, macOS, and Linux
You can run the preprocessor directly using npx
— no need to install globally:
npx @aliflux/universal-preprocessor ./src ./dist FEATURE_AUTH
git clone https://github.com/AliFlux/universal-preprocessor.git
cd universal-preprocessor
npm i
npm link
Process an entire project directory:
preprocessor ./src ./dist FEATURE_AUTH,FEATURE_CHAT,DEBUG_MODE
Syntax:
preprocessor <source_directory> <output_directory> <feature1,feature2,...>
npx @aliflux/universal-preprocessor ./src ./dist FEATURE_AUTH,FEATURE_CHAT,DEBUG_MODE
You can ignore specific files and folders from being processed or copied to the output directory by using a .preprocessorignore
file.
This works similar to .gitignore
.
- Create a
.preprocessorignore
file in the same directory as yoursourceDir
. - List files or folders (one per line) you want to exclude like:
node_modules
dev
secrets.txt
Source-Project
├── .preprocessorignore
├── main.js
├── dev/
│ └── test.js
├── package.json
├── secrets.txt
└── node_modules/
import universalPreprocess from "universal-preprocessor";
const input = `
// #if FEATURE_A
console.log("Feature A");
// #else
console.log("Fallback");
// #endif
`;
const output = universalPreprocess(input, ["FEATURE_A"]);
console.log(output);
// console.log("Feature A");
universal-preprocessor supports conditional compilation using three primary directives:
Directive | Purpose | Example |
---|---|---|
#if FEATURE_NAME |
Start conditional block | // #if FEATURE_AUTH |
#else |
Alternative block (optional) | // #else |
#endif |
End conditional block | // #endif |
The preprocessor automatically detects and supports multiple comment styles:
Language/Format | Comment Style | Example |
---|---|---|
JavaScript/TypeScript | // |
// #if FEATURE_NAME |
JavaScript/CSS | /* */ |
/* #if FEATURE_NAME */ |
HTML | <!-- --> |
<!-- #if FEATURE_NAME --> |
Python/Shell/Text | # |
# #if FEATURE_NAME |
// #if FEATURE_PREMIUM
class PremiumFeatures {
constructor() {
this.analyticsEnabled = true;
this.advancedReporting = true;
}
generateAdvancedReport() {
// Premium feature implementation
}
}
// #else
class PremiumFeatures {
constructor() {
this.analyticsEnabled = false;
this.advancedReporting = false;
}
generateAdvancedReport() {
throw new Error('Premium features not available');
}
}
// #endif
// #if DEVELOPMENT
const API_BASE_URL = 'http://localhost:3000/api';
const DEBUG_ENABLED = true;
// #else
const API_BASE_URL = 'https://api.production.com';
const DEBUG_ENABLED = false;
// #endif
// #if DEBUG_ENABLED
function debugLog(message) {
console.log(`[DEBUG] ${message}`);
}
// #endif
// #if FEATURE_CHAT
class ChatService {
// #if FEATURE_ENCRYPTION
encryptMessage(message) {
return encrypt(message);
}
// #else
encryptMessage(message) {
return message; // No encryption in basic version
}
// #endif
sendMessage(message) {
const processedMessage = this.encryptMessage(message);
// Send message logic
}
}
// #endif
Python Example:
# #if DEBUG_MODE
def debug_print(message):
print(f"DEBUG: {message}")
# #endif
class DataProcessor:
def process(self, data):
# #if DEBUG_MODE
debug_print(f"Processing {len(data)} items")
# #endif
return self._process_data(data)
HTML Example:
<!DOCTYPE html>
<html>
<head>
<title>My App</title>
<!-- #if ANALYTICS_ENABLED -->
<script src="analytics.js"></script>
<!-- #endif -->
</head>
<body>
<!-- #if FEATURE_BANNER -->
<div class="promotional-banner">
<h2>Special Offer!</h2>
</div>
<!-- #endif -->
</body>
</html>
Processes source code and returns filtered content based on enabled features.
Parameters:
-
content
(string): Source code to process -
enabledFeatures
(Array): Array of feature names to enable
Returns:
-
string
: Processed source code
Throws:
-
Error
: For malformed directives or unmatched blocks
Example:
import universalPreprocess from "universal-preprocessor";
try {
const result = universalPreprocess(sourceCode, ['FEATURE_A', 'FEATURE_B']);
console.log(result);
} catch (error) {
console.error('Preprocessing failed:', error.message);
}
The preprocessor provides comprehensive error detection and reporting:
Error Type | Description | Example |
---|---|---|
Missing Feature |
#if directive without feature name |
// #if |
Unmatched #if
|
Missing corresponding #endif
|
// #if FEATURE without // #endif
|
Unmatched #endif
|
#endif without corresponding #if
|
// #endif without // #if
|
Unexpected #else
|
#else without corresponding #if
|
// #else without // #if
|
Duplicate #else
|
Multiple #else in same block |
Two // #else in one #if block |
Add to your package.json
:
{
"scripts": {
"build:dev": "npx @aliflux/universal-preprocessor ./src ./dist DEVELOPMENT,DEBUG_MODE",
"build:prod": "npx @aliflux/universal-preprocessor ./src ./dist PRODUCTION,ANALYTICS",
"build:premium": "npx @aliflux/universal-preprocessor ./src ./dist PRODUCTION,PREMIUM_FEATURES,ANALYTICS"
}
}
name: Build Multiple Variants
on: [push, pull_request]
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
variant: [
{ name: "basic", features: "BASIC_FEATURES" },
{ name: "premium", features: "PREMIUM_FEATURES,ANALYTICS" },
{ name: "enterprise", features: "ENTERPRISE_FEATURES,ANALYTICS,PREMIUM_FEATURES" }
]
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
with:
node-version: '16'
- name: Install dependencies
run: npm install
- name: Build ${{ matrix.variant.name }}
run: npx @aliflux/universal-preprocessor ./src ./dist-${{ matrix.variant.name }} ${{ matrix.variant.features }}
- name: Upload artifacts
uses: actions/upload-artifact@v2
with:
name: build-${{ matrix.variant.name }}
path: dist-${{ matrix.variant.name }}
The preprocessor automatically processes files with these extensions:
-
.js
- JavaScript -
.ts
- TypeScript -
.jsx
- React JSX -
.py
- Python -
.txt
- Plain text -
.html
- HTML -
.css
- CSS
The following directories are automatically skipped:
node_modules
dist
.git
.DS_Store
Create different builds for different clients:
npx @aliflux/universal-preprocessor ./src ./dist-client-a CLIENT_A_FEATURES,BASIC_FEATURES
npx @aliflux/universal-preprocessor ./src ./dist-client-b CLIENT_B_FEATURES,PREMIUM_FEATURES
# Development build with debugging
npx @aliflux/universal-preprocessor ./src ./dist-dev DEVELOPMENT,DEBUG_MODE,MOCK_DATA
# Production build
npx @aliflux/universal-preprocessor ./src ./dist-prod PRODUCTION,ANALYTICS,OPTIMIZATIONS
Gradually enable features across different builds:
# Beta release
npx @aliflux/universal-preprocessor ./src ./dist-beta STABLE_FEATURES,BETA_FEATURES
# Stable release
npx @aliflux/universal-preprocessor ./src ./dist-stable STABLE_FEATURES
We welcome contributions! Please see our Contributing Guide for details.
git clone https://github.com/AliFlux/universal-preprocessor.git
cd universal-preprocessor
npm install
npm test
npm test
This project is licensed under the MIT License - see the LICENSE file for details.
- Issues: GitHub Issues
See CHANGELOG.md for a list of changes and version history.
Built with ❤️ by Visor Dynamics
Major work done by MaazAhmadDeveloper supported by AliFlux