Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 9102c6698a | |||
| 6cc8833b2a | |||
| 787e791aba | |||
| 781f571474 |
@@ -0,0 +1,34 @@
|
||||
---
|
||||
description: Ban dynamic import() in production code — use static imports instead
|
||||
globs: packages/*/src/**/*.ts
|
||||
alwaysApply: true
|
||||
---
|
||||
|
||||
# No Dynamic Import in Production Code
|
||||
|
||||
## Rule
|
||||
|
||||
Do NOT use `await import()` or dynamic `import()` expressions in production source code.
|
||||
Always use static top-level `import` statements.
|
||||
|
||||
## Why
|
||||
|
||||
- Static imports enable tree-shaking and bundler optimizations
|
||||
- They make dependencies explicit and discoverable at a glance
|
||||
- Dynamic imports of Node built-ins or project modules add unnecessary async overhead
|
||||
|
||||
## Exceptions (must include a comment explaining why)
|
||||
|
||||
1. **`sense-runtime.ts`** — loads user-authored sense modules whose paths are only known at runtime
|
||||
2. **`workflow-worker.ts`** — loads user-authored workflow modules whose paths are only known at runtime
|
||||
|
||||
When suppressing, add a comment directly above:
|
||||
|
||||
```ts
|
||||
// Dynamic import required: user module path resolved at runtime
|
||||
const mod = await import(senseIndexPath);
|
||||
```
|
||||
|
||||
## Test Files
|
||||
|
||||
Test files (`__tests__/**`) are exempt — dynamic import after `vi.mock()` is standard vitest practice.
|
||||
@@ -1,5 +1,7 @@
|
||||
import { spawn, execFile } from "node:child_process";
|
||||
import { existsSync, mkdirSync, writeFileSync } from "node:fs";
|
||||
import { dirname, join } from "node:path";
|
||||
import { promisify } from "node:util";
|
||||
|
||||
import { defineCommand } from "citty";
|
||||
|
||||
@@ -42,6 +44,8 @@ const GITIGNORE = `data/
|
||||
node_modules/
|
||||
`;
|
||||
|
||||
const execFileAsync = promisify(execFile);
|
||||
|
||||
const CPU_SCHEMA_TS = `import { integer, real, sqliteTable, text } from "drizzle-orm/sqlite-core";
|
||||
|
||||
export const cpuUsage = sqliteTable("cpu_usage", {
|
||||
@@ -90,7 +94,6 @@ function writeFile(filePath: string, content: string): void {
|
||||
}
|
||||
|
||||
async function runCommand(cmd: string, args: string[], cwd: string): Promise<void> {
|
||||
const { spawn } = await import("node:child_process");
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
const child = spawn(cmd, args, { cwd, stdio: "inherit" });
|
||||
child.on("close", (code) => {
|
||||
@@ -102,10 +105,6 @@ async function runCommand(cmd: string, args: string[], cwd: string): Promise<voi
|
||||
}
|
||||
|
||||
async function detectPackageManager(): Promise<{ cmd: string; installArgs: string[] }> {
|
||||
const { execFile } = await import("node:child_process");
|
||||
const { promisify } = await import("node:util");
|
||||
const execFileAsync = promisify(execFile);
|
||||
|
||||
for (const pm of ["pnpm", "yarn", "npm"]) {
|
||||
try {
|
||||
await execFileAsync(pm, ["--version"]);
|
||||
@@ -223,9 +222,6 @@ async function tryRequireSqlite(nerveRoot: string): Promise<boolean> {
|
||||
try {
|
||||
const modulePath = join(nerveRoot, "node_modules", "better-sqlite3");
|
||||
// Use a child process to test if the native module loads
|
||||
const { execFile } = await import("node:child_process");
|
||||
const { promisify } = await import("node:util");
|
||||
const execFileAsync = promisify(execFile);
|
||||
await execFileAsync("node", ["-e", `require(${JSON.stringify(modulePath)})`], {
|
||||
cwd: nerveRoot,
|
||||
timeout: 10_000,
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { spawn } from "node:child_process";
|
||||
import { createWriteStream, existsSync } from "node:fs";
|
||||
import { mkdir } from "node:fs/promises";
|
||||
import { dirname, join } from "node:path";
|
||||
@@ -8,6 +9,7 @@ import { defineCommand } from "citty";
|
||||
import {
|
||||
getLogPath,
|
||||
getNerveRoot,
|
||||
getSocketPath,
|
||||
isRunning,
|
||||
readPidFile,
|
||||
removePidFile,
|
||||
@@ -64,7 +66,6 @@ async function runDaemon(nerveRoot: string): Promise<void> {
|
||||
const logPath = getLogPath();
|
||||
await mkdir(join(nerveRoot, "logs"), { recursive: true });
|
||||
|
||||
const { spawn } = await import("node:child_process");
|
||||
const logStream = createWriteStream(logPath, { flags: "a" });
|
||||
await new Promise<void>((resolve) => {
|
||||
if (logStream.pending) logStream.once("open", () => resolve());
|
||||
@@ -90,7 +91,6 @@ async function runDaemon(nerveRoot: string): Promise<void> {
|
||||
|
||||
writePidFile(pid);
|
||||
|
||||
const { getSocketPath } = await import("../workspace.js");
|
||||
const ready = await waitForSocket(getSocketPath(), 5000);
|
||||
|
||||
if (!ready || !isRunning()) {
|
||||
|
||||
@@ -173,6 +173,7 @@ export async function loadComputeFn(senseIndexPath: string): Promise<Result<Comp
|
||||
let mod: unknown;
|
||||
|
||||
try {
|
||||
// Dynamic import required: user-authored sense module, path resolved at runtime
|
||||
mod = await import(senseIndexPath);
|
||||
} catch (e) {
|
||||
const msg = e instanceof Error ? e.message : String(e);
|
||||
|
||||
@@ -197,6 +197,7 @@ async function loadWorkflowDefinition(
|
||||
);
|
||||
}
|
||||
|
||||
// Dynamic import required: user-authored workflow module, path resolved at runtime
|
||||
const mod = await import(indexPath);
|
||||
const def: unknown = mod.default ?? mod;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user