|
#!/usr/bin/env python3 |
|
"""Generate module-loading benchmark fixtures.""" |
|
import json, os, shutil, sys |
|
|
|
ROOT = os.path.dirname(os.path.abspath(__file__)) |
|
|
|
def write(p, content): |
|
os.makedirs(os.path.dirname(p), exist_ok=True) |
|
with open(p, 'w') as f: |
|
f.write(content) |
|
|
|
# --------------------------------------------------------------- |
|
# Fixture 1: cjs-app — monorepo-ish app, deep dirs, relative requires |
|
# --------------------------------------------------------------- |
|
def gen_cjs_app(root, nfiles=3000, fanout=10): |
|
shutil.rmtree(root, ignore_errors=True) |
|
# tree of modules: module i requires children i*fanout+1 .. i*fanout+fanout |
|
def fname(i): |
|
# nest dirs to create realistic deep paths |
|
d1, d2 = i % 13, i % 7 |
|
return f"src/d{d1}/e{d2}/m{i}.js" |
|
for i in range(nfiles): |
|
kids = [k for k in range(i * fanout + 1, i * fanout + fanout + 1) if k < nfiles] |
|
def rel(k, i): |
|
r = os.path.relpath(os.path.join(root, fname(k)), os.path.join(root, os.path.dirname(fname(i)))).replace(os.sep, '/') |
|
return r if r.startswith('.') else './' + r |
|
reqs = "\n".join(f"exports.k{k} = require('{rel(k, i)}');" for k in kids) |
|
body = f"""'use strict'; |
|
{reqs} |
|
exports.id = {i}; |
|
exports.fn = function () {{ return {i}; }}; |
|
""" |
|
write(os.path.join(root, fname(i)), body) |
|
write(os.path.join(root, "package.json"), json.dumps({"name": "cjs-app", "private": True})) |
|
write(os.path.join(root, "main.js"), """'use strict'; |
|
const t0 = process.hrtime.bigint(); |
|
require('./src/d0/e0/m0.js'); |
|
const t1 = process.hrtime.bigint(); |
|
console.log(Number(t1 - t0) / 1e6); |
|
""") |
|
|
|
# --------------------------------------------------------------- |
|
# Fixture 2: cjs-pkgs — many node_modules packages, bare requires |
|
# --------------------------------------------------------------- |
|
def gen_cjs_pkgs(root, npkgs=150, files_per_pkg=12): |
|
shutil.rmtree(root, ignore_errors=True) |
|
for p in range(npkgs): |
|
pdir = os.path.join(root, "node_modules", f"pkg{p}") |
|
deps = [f"pkg{d}" for d in (p * 2 + 1, p * 2 + 2) if d < npkgs] |
|
write(os.path.join(pdir, "package.json"), json.dumps({ |
|
"name": f"pkg{p}", "version": "1.0.0", "main": "./lib/index.js"})) |
|
internal = "\n".join(f"exports.f{j} = require('./f{j}.js');" for j in range(1, files_per_pkg)) |
|
bare = "\n".join(f"exports.d{i} = require('{d}');" for i, d in enumerate(deps)) |
|
write(os.path.join(pdir, "lib", "index.js"), f"'use strict';\n{internal}\n{bare}\nexports.name='pkg{p}';\n") |
|
for j in range(1, files_per_pkg): |
|
write(os.path.join(pdir, "lib", f"f{j}.js"), f"'use strict';\nexports.v={j};\n") |
|
write(os.path.join(root, "package.json"), json.dumps({"name": "cjs-pkgs", "private": True})) |
|
write(os.path.join(root, "main.js"), """'use strict'; |
|
const t0 = process.hrtime.bigint(); |
|
require('pkg0'); |
|
const t1 = process.hrtime.bigint(); |
|
console.log(Number(t1 - t0) / 1e6); |
|
""") |
|
|
|
# --------------------------------------------------------------- |
|
# Fixture 3: esm-app — same shape as fixture 1 but ESM |
|
# --------------------------------------------------------------- |
|
def gen_esm_app(root, nfiles=3000, fanout=10): |
|
shutil.rmtree(root, ignore_errors=True) |
|
def fname(i): |
|
d1, d2 = i % 13, i % 7 |
|
return f"src/d{d1}/e{d2}/m{i}.mjs" |
|
for i in range(nfiles): |
|
kids = [k for k in range(i * fanout + 1, i * fanout + fanout + 1) if k < nfiles] |
|
def rel(k, i): |
|
r = os.path.relpath(os.path.join(root, fname(k)), os.path.join(root, os.path.dirname(fname(i)))).replace(os.sep, '/') |
|
return r if r.startswith('.') else './' + r |
|
imports = "\n".join(f"import * as k{k} from '{rel(k, i)}';" for k in kids) |
|
uses = ", ".join(f"k{k}" for k in kids) |
|
body = f"""{imports} |
|
export const id = {i}; |
|
export const deps = [{uses}]; |
|
export function fn() {{ return {i}; }} |
|
""" |
|
write(os.path.join(root, fname(i)), body) |
|
write(os.path.join(root, "package.json"), json.dumps({"name": "esm-app", "private": True, "type": "module"})) |
|
write(os.path.join(root, "main.mjs"), """const t0 = process.hrtime.bigint(); |
|
await import('./src/d0/e0/m0.mjs'); |
|
const t1 = process.hrtime.bigint(); |
|
console.log(Number(t1 - t0) / 1e6); |
|
""") |
|
|
|
# --------------------------------------------------------------- |
|
# Fixture 4: cjs-pkgs-esm — packages with exports maps, required from CJS |
|
# --------------------------------------------------------------- |
|
def gen_cjs_exports(root, npkgs=150, files_per_pkg=8): |
|
shutil.rmtree(root, ignore_errors=True) |
|
for p in range(npkgs): |
|
pdir = os.path.join(root, "node_modules", f"epkg{p}") |
|
deps = [f"epkg{d}" for d in (p * 2 + 1, p * 2 + 2) if d < npkgs] |
|
write(os.path.join(pdir, "package.json"), json.dumps({ |
|
"name": f"epkg{p}", "version": "1.0.0", |
|
"exports": { |
|
".": {"require": "./lib/index.js", "default": "./lib/index.js"}, |
|
"./sub/*": "./lib/sub/*.js", |
|
}})) |
|
subs = "\n".join(f"exports.s{j} = require('epkg{p}/sub/s{j}');" for j in range(files_per_pkg)) |
|
bare = "\n".join(f"exports.d{i} = require('{d}');" for i, d in enumerate(deps)) |
|
write(os.path.join(pdir, "lib", "index.js"), f"'use strict';\n{subs}\n{bare}\nexports.name='epkg{p}';\n") |
|
for j in range(files_per_pkg): |
|
write(os.path.join(pdir, "lib", "sub", f"s{j}.js"), f"'use strict';\nexports.v={j};\n") |
|
write(os.path.join(root, "package.json"), json.dumps({"name": "cjs-exports", "private": True})) |
|
write(os.path.join(root, "main.js"), """'use strict'; |
|
const t0 = process.hrtime.bigint(); |
|
require('epkg0'); |
|
const t1 = process.hrtime.bigint(); |
|
console.log(Number(t1 - t0) / 1e6); |
|
""") |
|
|
|
gen_cjs_app(os.path.join(ROOT, "fixtures", "cjs-app")) |
|
gen_cjs_pkgs(os.path.join(ROOT, "fixtures", "cjs-pkgs")) |
|
gen_esm_app(os.path.join(ROOT, "fixtures", "esm-app")) |
|
gen_cjs_exports(os.path.join(ROOT, "fixtures", "cjs-exports")) |
|
print("done") |