Setting the file. One moment.
Edge Heavy Import · Vercel Optimize · vercel-labs/agent-skills · Skills Docs
ContentsBack to the top of the page lib/scanners/edge-heavy-import.mjs
lib/scanners/ edge-heavy-import.mjs
JavaScript · 94 lines · 4 KB
^
\s
*
import
\s
+
(?:type
\s
+
)
?
(?:
[
^
'"]
*
\s
+
from
\s
+
)
?
['"]
(
[
^
'"]
+
)
['"]
/
gm
;
9 const DYNAMIC_IMPORT_RE = / \b import \( \s * ['"] ( [ ^ '"] + ) ['"]\s * \) / g ;
10 const REQUIRE_RE = / \b require \( \s * ['"] ( [ ^ '"] + ) ['"]\s * \) / g ;
11 const TYPE_IMPORT_RE = / ^ \s * import \s + type \s + / ;
12
13 const HEAVY_PATTERNS = [
14 / ^ node:/ ,
15 / ^ sharp $ / ,
16 / ^ @aws-sdk \/ / ,
17 / ^ @prisma \/ client $ / ,
18 / ^ prisma $ / ,
19 / ^ pg $ / ,
20 / ^ mysql2(?: \/ |$ )/ ,
21 / ^ puppeteer(?:-core) ? (?: \/ |$ )/ ,
22 / ^ playwright(?:-core) ? (?: \/ |$ )/ ,
23 / ^ bcrypt $ / ,
24 / ^ jsonwebtoken $ / ,
25 / ^ canvas $ / ,
26 / ^ @google-cloud \/ / ,
27 ];
28
29 export const metadata = {
30 id: 'edge-heavy-import' ,
31 title: 'Heavy / node-only import inside edge-runtime file' ,
32 severity: 'high' ,
33 billingDimension: 'function-duration' ,
34 trafficIndependent: true ,
35 description:
36 'Edge runtime is a constrained sandbox with no node: builtins and a much smaller cold-start budget than Node functions. Heavy SDKs (sharp, @aws-sdk/*, @prisma/client, pg, puppeteer) either fail at deploy or inflate cold-start latency. Move the import to a Node runtime function, or replace with an edge-compatible alternative (e.g., neon-driver instead of pg).' ,
37 fix:
38 'Either (a) drop the `export const runtime = \' edge \' ` so the route runs on Node (default in 2026), or (b) replace the heavy import with an edge-compatible alternative. For DB: use @neondatabase/serverless or @planetscale/database instead of pg/mysql2. For image: do the work in a Node route handler. For auth signing: use jose (Web Crypto) instead of jsonwebtoken.' ,
39 citations: [
40 'https://vercel.com/docs/functions/runtimes/edge-runtime' ,
41 'https://vercel.com/docs/fluid-compute' ,
42 ],
43 excludeGlobs: [ 'node_modules/**' , '.next/**' , 'dist/**' , '__tests__/**' , '**/*.test.*' , '**/*.spec.*' ],
44 includeGlobs: [ '**/*.{ts,tsx,js,mjs}' ],
45 };
46
47 export function scan ({ files }) {
48 const out = [];
49 for ( const { path , content } of files) {
50 if ( ! isEdgeRuntimeFile (path, content)) continue ;
51 const lines = content. split ( ' \n ' );
52 for ( let i = 0 ; i < lines. length ; i ++ ) {
53 const line = lines[i];
54 // Type-only imports are erased at compile, never reach runtime.
55 if ( TYPE_IMPORT_RE . test (line)) continue ;
56 const specifiers = extractSpecifiers (line);
57 for ( const spec of specifiers) {
58 const match = HEAVY_PATTERNS . find (( re ) => re. test (spec));
59 if ( ! match) continue ;
60 out. push ({
61 pattern: metadata.id,
62 file: path,
63 line: i + 1 ,
64 evidence: `import "${ spec }" in edge-runtime file` ,
65 edgeReason: isMiddleware (path) ? 'middleware (always edge)' : 'export const runtime = "edge"' ,
66 importedModule: spec,
67 trafficIndependent: metadata.trafficIndependent,
68 });
69 }
70 }
71 }
72 return out;
73 }
74
75 function isEdgeRuntimeFile ( path , content ) {
76 return isMiddleware (path) || EDGE_RUNTIME_RE . test (content);
77 }
78
79 function isMiddleware ( path ) {
80 return /(?: ^| \/ )middleware \. (ts | tsx | js | mjs) $ / . test (path);
81 }
82
83 function extractSpecifiers ( line ) {
84 const out = new Set ();
85 // IMPORT_RE has `gm` flag — reset lastIndex per call.
86 IMPORT_RE .lastIndex = 0 ;
87 let m;
88 while ((m = IMPORT_RE . exec (line)) !== null ) out. add (m[ 1 ]);
89 DYNAMIC_IMPORT_RE .lastIndex = 0 ;
90 while ((m = DYNAMIC_IMPORT_RE . exec (line)) !== null ) out. add (m[ 1 ]);
91 REQUIRE_RE .lastIndex = 0 ;
92 while ((m = REQUIRE_RE . exec (line)) !== null ) out. add (m[ 1 ]);
93 return [ ... out];
94 }