-
Notifications
You must be signed in to change notification settings - Fork 21
Description
Steps to reproduce
- Take ketcher-check.zip from this issue: vite build error epam/ketcher#5565 (comment)
- Run
npm iandnpm run build. You get:
error during build:
[commonjs--resolver] Maximum call stack size exceeded
file: /ketcher-check/node_modules/ketcher-core/dist/index.modern.js
at String.replace (<anonymous>)
at isCommonjs (file:///ketcher-check/node_modules/vite-plugin-commonjs/dist/index.mjs:252:15)
at transformCommonjs (file:///ketcher-check/node_modules/vite-plugin-commonjs/dist/index.mjs:413:8)
at Object.transform (file:///ketcher-check/node_modules/vite-plugin-commonjs/dist/index.mjs:393:14)
at file:///ketcher-check/node_modules/rollup/dist/es/shared/node-entry.js:22451:40
Reason
The issues is with this code when it is applied to a huge file (around 20Mb):
const multilineCommentsRE = /\/\*(.|[\r\n])*?\*\//gm;
const singlelineCommentsRE = /\/\/.*(?=[\n\r])/g;
function isCommonjs(code) {
code = code.replace(multilineCommentsRE, "").replace(singlelineCommentsRE, "");
return /\b(?:require|module|exports)\b/.test(code);
}
ChatGPT analysis:
The reason is catastrophic backtracking caused by the regex:
/\/\*(.|[\r\n])*?\*\//gm
Why this regex blows the stack
The sub-pattern: (.|[\r\n])*? is a catastrophic-backtracking trap:
(.) matches any character except newlines, [\r\n] matches only newlines
Together they form a redundant alternation that can match every character, but in an extremely inefficient way.
When the engine tries to match a long block of code, it repeatedly backtracks through countless combinations of (.) vs [\r\n].
This can grow exponentially and eventually ends in:
RangeError: Maximum call stack size exceeded
How to fix it
Use the standard “match any character” class in JavaScript:
const multilineCommentsRE = /\/\*[\s\S]*?\*\//g;
Or even better:
const multilineCommentsRE = /\/\*[^]*?\*\//g; // [^] = match any char, including newlines
This avoids backtracking traps and will not overflow the stack.