Skip to main content

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​

  1. In development, the code between markers runs normally
  2. During production build, the Builder removes everything between /* dev:start */ and /* dev:end */ from the compiled JS output
  3. The markers are removed from JS — not from TypeScript source. Your .ts files 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​

ContentStripped in Production?
Code between /* dev:start */ and /* dev:end */Yes
The markers themselvesYes (from JS)
TypeScript source filesNo — markers stay in .ts
Imports inside dev blocksYes
Variables declared inside dev blocksYes
ResolverScope.DEV resolversNo — class exists, but routing ignores it

Best Practices​

  1. Declare variables outside dev blocks if they're used outside
  2. Whole-file wrapping is safe — imports and all code are stripped together
  3. Use for: test pages, debug panels, development utilities, runtime test runners
  4. Don't use for: feature flags, A/B testing, conditional business logic (those should use proper config)
  5. Combine with ResolverScope.DEV for development-only pages

See also: ForceCompile | Testing | Routing