next.js/crates/next-code-frame/benches/code_frame_bench.rs
code_frame_bench.rs208 lines6.7 KB
use criterion::{Criterion, black_box, criterion_group, criterion_main};
use next_code_frame::{CodeFrameLocation, CodeFrameOptions, Language, Location, render_code_frame};

/// Generate a realistic small TypeScript/React file (~300 lines).
fn generate_small_file() -> String {
    let mut lines = Vec::with_capacity(300);

    lines.push("import React, { useState, useEffect, useCallback, useMemo } from 'react'");
    lines.push("import { useRouter } from 'next/router'");
    lines.push("import Link from 'next/link'");
    lines.push("");
    lines.push("interface User {");
    lines.push("  id: string");
    lines.push("  name: string");
    lines.push("  email: string");
    lines.push("  avatar?: string");
    lines.push("  role: 'admin' | 'user' | 'moderator'");
    lines.push("  createdAt: Date");
    lines.push("}");
    lines.push("");

    // Pad with realistic component code
    for i in 0..40 {
        lines.push("function ComponentPart() {");
        // Use a leaked string so we get &'static str
        let s: &'static str =
            Box::leak(format!("  const [state{i}, setState{i}] = useState(null)").into_boxed_str());
        lines.push(s);
        lines.push("  useEffect(() => {");
        let s: &'static str = Box::leak(
            format!("    fetch('/api/data/{i}').then(r => r.json()).then(setState{i})")
                .into_boxed_str(),
        );
        lines.push(s);
        lines.push("  }, [])");
        lines.push("  return (");
        lines.push("    <div className=\"flex items-center justify-center p-4\">");
        let s: &'static str =
            Box::leak(format!("      <span>{{state{i}?.name}}</span>").into_boxed_str());
        lines.push(s);
        lines.push("    </div>");
        lines.push("  )");
        lines.push("}");
        lines.push("");
    }

    lines.join("\n")
}

/// Generate a large bundled JS file (~30k lines) mimicking react-dom.development.js.
fn generate_large_file(minified: bool) -> String {
    let mut lines = Vec::with_capacity(30_000);

    lines.push("/**");
    lines.push(" * @license React");
    lines.push(" * react-dom.development.js");
    lines.push(" *");
    lines.push(" * Copyright (c) Meta Platforms, Inc. and affiliates.");
    lines.push(" */");
    lines.push("'use strict';");
    lines.push("");
    lines.push("(function (global, factory) {");
    lines.push(
        "  typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, \
         require('react')) :",
    );
    lines.push(
        "  typeof define === 'function' && define.amd ? define(['exports', 'react'], factory) :",
    );
    lines.push("  (global = global || self, factory(global.ReactDOM = {}, global.React));");
    lines.push("}(this, (function (exports, React) { 'use strict';");
    lines.push("");

    // Generate ~30k lines of realistic bundled code
    for i in 0..3000 {
        lines.push(
            "function reconcileChildFibers(returnFiber, currentFirstChild, newChild, lanes) {",
        );
        // Leaked strings for &'static str
        let s: &'static str = Box::leak(
            format!(
                "  var isUnkeyedTopLevelFragment = typeof newChild === 'object' && newChild !== \
                 null && newChild.type === REACT_FRAGMENT_TYPE_{i} && newChild.key === null;"
            )
            .into_boxed_str(),
        );
        lines.push(s);
        lines.push("  if (isUnkeyedTopLevelFragment) {");
        lines.push("    newChild = newChild.props.children;");
        lines.push("  }");
        lines.push("  if (typeof newChild === 'object' && newChild !== null) {");
        lines.push("    switch (newChild.$$typeof) {");
        lines.push("      case REACT_ELEMENT_TYPE:");
        lines.push(
            "        return placeSingleChild(reconcileSingleElement(returnFiber, \
             currentFirstChild, newChild, lanes));",
        );
        lines.push("    }");
        lines.push("  }");
        lines.push("}");
        lines.push("");
    }

    lines.push("})));");
    lines.join(if minified { " " } else { "\n" })
}

fn bench_small_file(c: &mut Criterion) {
    let source = generate_small_file();
    let line_count = source.lines().count();
    let mid = line_count / 2;

    let location = CodeFrameLocation {
        start: Location {
            line: mid,
            column: Some(10),
        },
        end: None,
    };

    let options = CodeFrameOptions {
        highlight_code: true,
        color: true,
        max_width: 100,
        language: Language::JavaScript,
        ..Default::default()
    };

    c.bench_function(&format!("rust: small file ({line_count} lines)"), |b| {
        b.iter(|| {
            let result = render_code_frame(black_box(&source), black_box(&location), &options);
            black_box(result).unwrap();
        });
    });
}

fn bench_large_file(c: &mut Criterion) {
    let source = generate_large_file(false);
    let line_count = source.lines().count();
    let mid = line_count / 2;

    let location = CodeFrameLocation {
        start: Location {
            line: mid,
            column: Some(10),
        },
        end: None,
    };

    let options = CodeFrameOptions {
        highlight_code: true,
        color: true,
        max_width: 100,
        language: Language::JavaScript,
        ..Default::default()
    };

    c.bench_function(&format!("rust: large file ({line_count} lines)"), |b| {
        b.iter(|| {
            let result = render_code_frame(black_box(&source), black_box(&location), &options);
            black_box(result).unwrap();
        });
    });
}

fn bench_minified_file(c: &mut Criterion) {
    // Take the large file and collapse lines by stripping whitespace after `;`
    // to simulate a minified bundle with very long lines.
    let source = generate_large_file(true);
    let line_count = source.lines().count();
    // Point at a column somewhere in the middle of the long line
    let mid_col = source.lines().next().map_or(100, |l| l.len() / 2);

    let location = CodeFrameLocation {
        start: Location {
            line: 1,
            column: Some(mid_col),
        },
        end: None,
    };

    let options = CodeFrameOptions {
        highlight_code: true,
        color: true,
        max_width: 100,
        language: Language::JavaScript,
        ..Default::default()
    };

    c.bench_function(
        &format!("rust: minified file ({line_count} lines, ~{mid_col} col)"),
        |b| {
            b.iter(|| {
                let result = render_code_frame(black_box(&source), black_box(&location), &options);
                black_box(result).unwrap();
            });
        },
    );
}

criterion_group!(
    benches,
    bench_small_file,
    bench_large_file,
    bench_minified_file
);
criterion_main!(benches);
Quest for Codev2.0.0
/
SIGN IN