-
-
Notifications
You must be signed in to change notification settings - Fork 4.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Max Stack Size Exceeded for huge HTML #4694
Comments
the compiling process involves push spreading all nodes into another array at some point and the v8 engine does not support spreading that many items |
Interesting. I've run into this before in V8 and ended up using an array spread and a reassignment, rather than an argument spread in I'm not sure how many places we're doing |
Same issue when using Tailwind UI. In a regular svelte + tailwindcss project if I add in the Could we update the issue name as well to include tailwindUI word? @siebeneicher |
same here im building a large single page app / single file app, with many many html nodes error is
with
chunks.push(
c(') '),
...handle(node.body, state)
); .... as expected, using push instead of reassign compiles to const chunks = [c('for (')];
//
chunks.push(
c(') '),
...handle(node.body, state)
); todo: push ----> reassign like let chunks = [c('for (')];
//
chunks = [
...chunks,
c(') '),
...handle(node.body, state)
]; |
fixed : ) here is a quick-and-dirty patch script, to replace push with reassign patch-svelte-compiler.mjs/*
patch-svelte-compiler.mjs
replace push with reassign to fix https://github.com/sveltejs/svelte/issues/4694
1. save this script in your project folder - note the extension mjs
2. make sure this file exists: node_modules/svelte/compiler.js
3. run: node patch-svelte-compiler.mjs
*/
// npm install acorn estree-walker magic-string
import {parse as acorn_parse} from "acorn";
import {walk as estree_walk} from "estree-walker";
import magicString from "magic-string";
import * as fs from "fs";
// replaceMethod
// origin: a.push(...a1, ...a2, e, ...a3); // error: Max Stack Size Exceeded
// spread: a = [...a1, ...a2, e, ...a3];
// concat: a = a1.concat(a2, [e], a3);
// performance is equal on nodejs
const replaceMethod = "spread";
//const replaceMethod = "concat";
var base_file = process.argv[2] || "node_modules/svelte/compiler";
const base_file_list = [
`${base_file}.js`, // "type": "commonjs"
`${base_file}.mjs`, // "type": "module"
];
for (const base_file of base_file_list) {
const backup_file = base_file + ".bak";
const temp_file = base_file + ".tmp";
if (fs.existsSync(backup_file)) {
console.log(`error: backup file exists (${backup_file}). run this script only onc`);
continue;
}
if (fs.existsSync(temp_file)) {
console.log(`error: temporary file exists (${temp_file}). run this script only onc`);
continue;
}
// input
const content = fs.readFileSync(base_file, 'utf8');
// output
let code = new magicString(content);
const ast = acorn_parse(
content, {
ecmaVersion: 2020,
sourceType: 'module',
});
const funcName = "push";
let arrayNameList = [];
estree_walk( ast, {
enter: function ( node, parent, prop, index ) {
// node must be array.push()
if (
node.type !== 'CallExpression' ||
node.callee === undefined ||
node.callee.property === undefined ||
node.callee.property.name !== funcName
) { return; }
// argument list must include spread operators
if (node.arguments.find(
a => (a.type == 'SpreadElement')) === undefined)
{ return; }
const nodeSrc = content.substring(node.start, node.end);
const pushObj = node.callee.object;
const arrayName = content.substring(pushObj.start, pushObj.end);
const pushProp = node.callee.property;
arrayNameList.push(arrayName);
// patch .push(
if (replaceMethod == "spread") {
// push --> assign array
// find "(" bracket after .push
const pushPropLen = content.substring(pushProp.start, node.end).indexOf("(");
code.overwrite(
(pushProp.start - 1),
(pushProp.start + pushPropLen + 1),
" /* PATCHED */ = [..."+arrayName+", "
);
// patch closing bracket
const closeIdx = node.start + nodeSrc.lastIndexOf(")");
code.overwrite(closeIdx, (closeIdx + 1), "]");
}
if (replaceMethod == "concat") {
// push --> assign concat
// ".push" --> " = array.concat"
code.overwrite(
(pushProp.start - 1),
pushProp.end,
" /* PATCHED */ = "+arrayName+".concat");
// patch arguments of .concat()
node.arguments.forEach(a => {
if (a.type == 'SpreadElement') {
// unspread: ...array --> array
const spreadArgSrc = content.substring(a.argument.start, a.argument.end);
//console.log('spread argument: '+spreadArgSrc);
code.overwrite(a.start, a.end, spreadArgSrc);
} else {
// enlist: element --> [element]
const argSrc = content.substring(a.start, a.end);
//console.log('non spread argument: '+argSrc);
code.overwrite(a.start, a.end, "["+argSrc+"]");
}
});
}
}});
code = code.toString();
function filterUnique(value, index, array) {
return array.indexOf(value) === index;
}
// replace const with let
arrayNameList.filter(filterUnique).forEach(arrayName => {
console.log(`arrayName = ${arrayName}`)
code = code.replace(
new RegExp("const "+arrayName+" = ", 'g'), // global = replace all
"/* PATCHED const "+arrayName+" */ let "+arrayName+" = "
);
})
fs.writeFileSync(temp_file, code);
console.log(`move file: ${base_file} --> ${backup_file}`)
fs.renameSync(base_file, backup_file);
console.log(`move file: ${temp_file} --> ${base_file}`)
fs.renameSync(temp_file, base_file);
}
console.log(`\n\nundo:\n`);
for (const base_file of base_file_list) {
console.log(`mv ${base_file}.bak ${base_file}`);
}
console.log(`\n\ncompare:\n`);
for (const base_file of base_file_list) {
console.log(`git diff ${base_file}.bak ${base_file}`);
}
console.log(`\n\ncreate patch:\n`);
console.log(`npx patch-package svelte`); edit: included patch by rhythm-section |
@milahu Thank you for the compiler patch. It works great. With version
Because of the tertiary operator the Not sure if it is a good solution or if it leads to other issues with other svelte versions, but the following worked for me. I changed the regex from:
to:
Hope this helps someone still having troubles. |
Is there any CI-able solution? |
you mean patching the typescript source files? here is a start: todo:
cosmetic:
|
the problem with concat is: concat is slower than push this should be fastest: Array.prototype._concat_inplace = function(other) { // aka _push_array
for (let i = 0; i < other.length; i++) {
this.push(other[i]);
}
return this; // chainable
};
array1._concat_inplace(array2)._concat_inplace(array3); its even faster than |
This issue is affecting working with .svg aswell. I have a bunch of huge SVGs that I want to animate with Svelte (in Sapper). Unfortunately I run into
My workaround is to downsize the svg, by reducing the complexity of paths used in it. |
Is there any fix available for this? I'm also facing the max stack size issue while importing the big SVG file as svelte component. |
there is a fix hidden 7 posts above but it may be better to outsource static parts, at least the svg |
@milahu My SVG is a svelte component (converted from .svg to .svelte) as I have to attach the multiple events like open a pop-up if anyone clicks on any specific area or show a image slider on screen (dynamically using the api data) inside that SVG. |
you can get it running with my patch, but development will be slower than with smaller components another solution: https://svelte.dev/repl/b0910aa018514053ae798250e17faa7a |
This should really be fixed. Much thanks to @milahu for the excellent workaround |
Discovered this whilst evaluating SvelteKit (my issue was closed above). Trying to convert a large static HTML theme. @NetOperatorWibby - I've attempted to use the patch here (https://gist.github.com/NetOperatorWibby/8515baa503ccc7b60189c6871c2c6096). I ran all 4 commands without error but I am still seeing the 'maximum call stack size' error. I'm not a front-end engineer at heart so I'm not sure how to proceed with this. The original patch was submitted over a year ago. Breaking it down and composing smaller components doesn't appear to have any effect. System: |
whats the exact error trace? maybe your node uses compiler.mjs which is not patched |
Yeah, looks like compiler.mjs. My original issue with the details is here: (sveltejs/kit#2061). |
ive updated my //var base_file = "compiler.mjs"; // "type": "module" // TODO verify uncomment that line, run the script and hope for the best ; ) |
@milahu Haven't been able to get back to this for a few days. Thanks a lot - that works great and the error is no longer present. |
I encountered this one today. Just wanted to ask if there is a specific reason, why there seems to be a working patch but no pr to bring that fix into svelte? Several hundret html-tags on a page don't seem that unreasonable to me today and if this is really a |
this would require patching multiple packages (svelte, code-red, ...) which is ... work |
The crash(!) occurs with no special prerequisites in quite simple, normal usecases and without documentation or warning (see my repro https://svelte.dev/repl/0a52a75c95d34423bf6d328ca4e1db88?version=3.42.4). The problem worsens as svelte is advertised to be especially able to handle very large node-counts for visualization etc better than react & co. Imho(!), apart from being a nasty bug, the problem with the patch-solution, which I appreciate(!), is, that it has no contract or guarantees inside the actual svelte-code. It could break anytime. Or you might have something better to do. Or whatever. In the end you can't simply upgrade packages without manual testing and patching - which you might eagerly need to for some reasons. I get that this is a volunteer-driven-project and that its much hard work to develop and maintain this project (which I, again, very much appreciate!) but I'm arguing from a standpoint where one might decide to run user-facing production-code on the basis of svelte. And from that standpoint this is quite a big (undocumented) problem. |
not really : P https://github.com/milahu/random/tree/master/svelte/patch-svelte-compiler-sources current output
feel free to continue |
@milahu I was referring to svelte(kit) as a whole ;) |
@milahu Thanks for the effort on this. Is there a step 1-2-3 to use the code here: https://github.com/milahu/random/tree/master/svelte/patch-svelte-compiler-sources |
i made for users of svelte, its easier to patch the bundled javascript sources of svelte ( |
I haven't found this in this issue, was it discussed some where else? |
thats cos i made it up ; ) a more truthful summary would be: "this is a rare issue, so it has low priority. (again, this was never said explicitly, its just my attempt to rationalize the situation.) if you want this fixed in svelte, feel free to continue #6716 and Rich-Harris/code-red#64 |
@milahu thanks for providing the script. I'm unable to run it though, I'm getting the following error:
I had to downgrade estree to v2 for this to work. |
thanks, fixed in patch-svelte-compiler.mjs |
… exceeded error Fixes Rich-Harris#40 Alternative to Rich-Harris#64 Part of sveltejs/svelte#4694
… exceeded error Part of sveltejs#4694 Also related: Rich-Harris/code-red#71
This should be good now in 3.46.4 - https://svelte.dev/repl/a9dfcc17551c4aeb95e8fe748a97061d?version=3.46.4 |
Thanks @milahu for all the investigation and driving a fix on this one! |
Describe the bug
The content of the the svelte file is a large HTML chunk, without any script logic or styling being involved. Max stack size exceeded error while compiling.
To Reproduce
https://svelte.dev/repl/a9dfcc17551c4aeb95e8fe748a97061d?version=3.20.1
Expected behavior
Compiling should not break
Information about your Svelte project:
Svelte 3.20.1, Rollup, Windows
Severity
Its probably an uncommon case for most people. I ran into it, when using a generated data privacy HTML template. I would not see this as a priority. Workaround for me: copy the HTML into a JS template literal variable and inject it via @html: https://svelte.dev/repl/1ab32c5a3c2c426e973512cfc8da023c?version=3.20.1
The text was updated successfully, but these errors were encountered: