Development Markers
Oidis supports development-only code blocks using /* dev:start */ and /* dev:end */ markers. Code between these markers is completely stripped from the compiled JavaScript output in production builds.
Syntax
/* dev:start */
// This code only exists in development
import { RuntimeTestViewer } from "./RuntimeTests/RuntimeTestViewer.js";
LogIt.Info("Development mode active");
/* dev:end */
How It Works
- In development, the code between markers runs normally
- During production build, the Builder removes everything between
/* dev:start */and/* dev:end */from the compiled JS output - The markers are removed from JS — not from TypeScript source. Your
.tsfiles always contain the markers.
Critical Safety Rule
Variables and references used outside a dev block must be declared outside it:
// ✅ Correct — variable declared outside, modified inside
let content = "";
/* dev:start */
content = "<div>Debug Panel</div>";
/* dev:end */
// content is "" in production, "<div>Debug Panel</div>" in dev
// ❌ WRONG — variable only exists inside dev block
/* dev:start */
let debugContent = "<div>Debug Panel</div>";
/* dev:end */
console.log(debugContent); // ReferenceError in production!
Why? In production, everything between the markers is gone. If you declare a variable inside a dev block and reference it outside, production code will crash with a ReferenceError.
Two Usage Patterns
Pattern 1: Partial Content
A dev block adds content to an existing variable. In production, the variable exists but with a different value:
// Index.ts pattern
let additionalRoutes = "";
/* dev:start */
additionalRoutes += '<route path="/tests" component="TestViewer" />';
additionalRoutes += '<route path="/debug" component="DebugPanel" />';
/* dev:end */
// In production: additionalRoutes is ""
// In development: additionalRoutes has test routes
Pattern 2: Whole File
The entire file is wrapped in dev markers. The file exists in source but produces no output in production:
// RuntimeTests/SomeTest.ts
/* dev:start */
import { BaseTestRunner } from "@io-oidis-hub/.../Testing/BaseTestRunner.js";
import { Test } from "@io-oidis-hub/.../Testing/Decorators.js";
export class SomeTest extends BaseTestRunner {
@Test()
public async TestSomething() : Promise<void> {
// Test logic
}
}
/* dev:end */
Imports inside dev blocks are also stripped — this is safe because the entire block (including imports) is removed together.
ResolverScope.DEV
A related mechanism: @Resolver with ResolverScope.DEV creates a resolver that exists in the source but is never matched in production routing:
@Resolver("/runtime-tests", { scope: ResolverScope.DEV })
export class RuntimeTestViewerController extends BasePageController<RuntimeTestViewer> {
// Only accessible in development mode
}
This is complementary to dev markers — the controller class exists in the bundle but the routing framework ignores it in production.
What Gets Stripped
| Content | Stripped in Production? |
|---|---|
Code between /* dev:start */ and /* dev:end */ | Yes |
| The markers themselves | Yes (from JS) |
| TypeScript source files | No — markers stay in .ts |
| Imports inside dev blocks | Yes |
| Variables declared inside dev blocks | Yes |
ResolverScope.DEV resolvers | No — class exists, but routing ignores it |
Best Practices
- Declare variables outside dev blocks if they're used outside
- Whole-file wrapping is safe — imports and all code are stripped together
- Use for: test pages, debug panels, development utilities, runtime test runners
- Don't use for: feature flags, A/B testing, conditional business logic (those should use proper config)
- Combine with
ResolverScope.DEVfor development-only pages
See also: ForceCompile | Testing | Routing