Open CallumVass opened 11 months ago
I think the real error is "The command line is too long." which is printed before the process exits (or never even starts). Since the library passes an internal script on the command line, the command line will be quite long already, maybe on your system it gets too long
What OS are you running on? Is the path name to your application and to the node executable very long?
Hiya, thanks for the reply - I'm on Windows 11 and the project isn't nested very deep: C:\Dev\JsSample\JsSample.csproj
But it works fine with 6.3.1, as soon as I upgrade to version 7 thats when the error occurs
I am on MacOS and I am also experiencing this. Tested both static and DI-approach, which not surprisingly, fails in the same way.
@CallumVass what about the path to the node executable?
@ZeldaIV do you also see the "command line too long" error in the log output?
@aKzenT Likewise, my node executable isn't very deep either: C:\Program Files\nodejs\node.exe
Something happened between 7.0.0-beta.4 and 7.0.0-beta.5 which is causing the issue. It works all the way up to installing beta 5, then I get that error. If I go back to beta 4 it works fine.
@CallumVass Thanks for the details. We did make changes from beta 4 to 5 that affected script length:
PR: https://github.com/JeringTech/Javascript.NodeJS/pull/173
We need to check how the length of the script changed after these changes.
If it got longer we should shorten it to no longer than before, perhaps more aggressive minification with Vite (if possible) or manual code simplification.
@aKzenT would you like to handle this issue?
In beta 4 we were passing the configuration to the webpack script. Webpack was automatically minifying when mode was "release":
In beta 5 we are no longer minifying:
I've verified that:
import { defineConfig } from "vite";
export default defineConfig({
build: {
minify: true,
emptyOutDir: false,
ssr: true,
},
});
as suggested by @CallumVass minifies adequately:
We just need to pass the configuration to vite.config. I'm not familiar with Vite though, @CallumVass would you like to create a pull request with the necessary changes?
I've minified it locally using minify: true
but it still doesn't work, here is what I see in the console:
dbug: Jering.Javascript.NodeJS.HttpNodeJSService[0]
Waiting on process connection semaphore, processID: 112264, thread ID: 9, thread is ThreadPool thread : True.
fail: Jering.Javascript.NodeJS.HttpNodeJSService[0]
Starting inspector on 127.0.0.1:9229 failed: address already in use
file:///C:/Dev/csharp/JavascriptTest/JavascriptTest/[eval1]:1
import T from"module";import*as E from"http2";import*as d from"path";import*as I from"stream";var f=(e=>(e[e.Cache=0]="Cache",e[e.File=1]="File",e[e.String=2]="String",e[e.Stream=3]="Stream",e))(f||{});function N(){co
nst e=P(process.argv);S(process.stdout),S(process.stderr),k(parseInt(e.parentPid),!0,1e3);const t=process.cwd(),o=b(t);return O(t),[e,t,o]}function a(e,t){const o=typeof t=="string";e.statusCode=500,e.end(JSON.stringify({er
rorMessage:o?t:t.message,errorStack:o?null:t.stack}))}function p(e){return e.cacheIdentifier==null?`"${e.moduleSource.substring(0,25)}..."`:e.cacheIdentifier}function b(e){const t=[d.join(e,"node_modules")];let o=e,i;for(;(
o=d.dirname(o))!==i;)t.push(d.join(o,"node_modules")),i=o;return t}function P(e){let t=null;const o={};return e.forEach(i=>{if(i.indexOf("--")===0){const c=i.substring(2);o[c]=void 0,t=c}else t!==null&&(o[t]=i,t=null)}),o}f
unction k(e,t,o){setInterval(()=>{w(e)||(console.log(`[Node.js HTTP server] Parent process (pid: ${e}) exited. Exiting this process...`),process.exit())},o),t&&process.on("SIGINT",()=>{console.log("[Node.js HTTP server] Rec
eived SIGINT. Waiting for .NET process to exit...")})}function w(e){try{return process.kill(e,0),!0}catch(t){if(t.code==="EPERM")throw new Error(`Attempted to check whether process ${e} was running, but got a permissions er
ror.`);return!1}}function O(e){function t(c,n){try{return i.apply(this,arguments)}catch(s){if(s.message.startsWith("EPERM")&&typeof o=="string"&&o.startsWith(c)&&s.stack.indexOf("Object.realpathSync ")>=0)return i.call(this
,e,n);throw s}}let o=null,i=null;if(/^win/.test(process.platform))try{o=d._makeLong(e);const c=process.binding("fs");i=c.lstat,typeof i=="function"&&(c.lstat=t)}catch{}}function S(e){const t=e.write;e.write=function(o){typeof o=="string"&&(arguments[0]=o.slice(0,o.length-1)+`\0
SyntaxError: Unexpected end of input
at DefaultModuleLoader.evalInstance (node:internal/modules/esm/loader:104:22)
at new ModuleJob (node:internal/modules/esm/module_job:63:26)
at DefaultModuleLoader.eval (node:internal/modules/esm/loader:115:17)
at node:internal/process/execution:51:55
at loadESM (node:internal/process/esm_loader:40:13)
at evalModule (node:internal/process/execution:51:28)
at node:internal/main/eval_string:29:3
Node.js v20.5.1
Looking at the generated script, it doesnt match what is being passed above, the last few characters: +`\0 Are at the end of the first line in the minified script, so it seems to be missing the rest of it?
Odd that it is getting truncated. After changing minify to true, how are you running it locally?
Could you try running the test suite? It passes on my windows 11 machine with minify set to true.
@JeremyTCD - Yeah I get the same error in tests, using Windows 11 also:
[xUnit.net 00:00:00.92] SyntaxError: Unexpected end of input
Its the same as above, the script seems truncated. It looks like vite isnt minifying across a single line like the webpack one was doing and that is causing an issue somewhere
The library escapes the script before starting the node process:
This is where the process start info is created:
Could you place breakpoints and take a closer look at nodeServerScript
?
I can't reproduce the issue on my machine so it's definitely a system-specific problem:
https://github.com/JeringTech/Javascript.NodeJS/assets/11733898/8dc729d2-5297-4767-a740-3d3497b28086
This is what is passed as arguments to the process via startInfo:
--inspect-brk --input-type=module -e "import T from\"module\";import*as I from\"http\";import*as d from\"path\";import*as E from\"stream\";var f=(e=>(e[e.Cache=0]=\"Cache\",e[e.File=1]=\"File\",e[e.String=2]=\"String\",e[e.Stream=3]=\"Stream\",e))(f||{});function b(){const e=P(process.argv);S(process.stdout),S(process.stderr),$(parseInt(e.parentPid),!0,1e3);const t=process.cwd(),n=N(t);return w(t),[e,t,n]}function c(e,t){const n=typeof t==\"string\";e.statusCode=500,e.end(JSON.stringify({errorMessage:n?t:t.message,errorStack:n?null:t.stack}))}function p(e){return e.cacheIdentifier==null?`\"${e.moduleSource.substring(0,25)}...\"`:e.cacheIdentifier}function N(e){const t=[d.join(e,\"node_modules\")];let n=e,i;for(;(n=d.dirname(n))!==i;)t.push(d.join(n,\"node_modules\")),i=n;return t}function P(e){let t=null;const n={};return e.forEach(i=>{if(i.indexOf(\"--\")===0){const l=i.substring(2);n[l]=void 0,t=l}else t!==null&&(n[t]=i,t=null)}),n}function $(e,t,n){setInterval(()=>{k(e)||(console.log(`[Node.js HTTP server] Parent process (pid: ${e}) exited. Exiting this process...`),process.exit())},n),t&&process.on(\"SIGINT\",()=>{console.log(\"[Node.js HTTP server] Received SIGINT. Waiting for .NET process to exit...\")})}function k(e){try{return process.kill(e,0),!0}catch(t){if(t.code===\"EPERM\")throw new Error(`Attempted to check whether process ${e} was running, but got a permissions error.`);return!1}}function w(e){function t(l,r){try{return i.apply(this,arguments)}catch(s){if(s.message.startsWith(\"EPERM\")&&typeof n==\"string\"&&n.startsWith(l)&&s.stack.indexOf(\"Object.realpathSync \")>=0)return i.call(this,e,r);throw s}}let n=null,i=null;if(/^win/.test(process.platform))try{n=d._makeLong(e);const l=process.binding(\"fs\");i=l.lstat,typeof i==\"function\"&&(l.lstat=t)}catch{}}function S(e){const t=e.write;e.write=function(n){typeof n==\"string\"&&(arguments[0]=n.slice(0,n.length-1)+`\0
`),t.apply(this,arguments)}}const m=T,[O,j,C]=b();J();function J(){const e=I.createServer(L);e.setTimeout(0),e.keepAliveTimeout=0,e.headersTimeout=2147483647,e.on(\"timeout\",_),e.on(\"clientError\",R),e.listen(parseInt(O.port),\"localhost\",()=>{let t=e.address();console.log(`[Jering.Javascript.NodeJS: HttpVersion - HTTP/1.1 Listening on IP - ${t.address} Port - ${t.port}]`)})}function L(e,t){const n=[];e.on(\"data\",i=>n.push(i)).on(\"end\",async()=>{var i;try{const l=Buffer.concat(n).toString();let r;if(e.headers[\"content-type\"]===\"multipart/mixed\"){const o=l.split(\"--Uiw6+hXl3k+5ia0cUYGhjA==\");r=JSON.parse(o[0]),r.moduleSource=o[1]}else r=JSON.parse(l);let s;if(r.moduleSourceType===f.Cache){const o=m._cache[r.moduleSource];if(o==null){t.statusCode=404,t.end();return}s=o.exports}else if(r.moduleSourceType===f.Stream||r.moduleSourceType===f.String){if(r.cacheIdentifier!=null){const o=m._cache[r.cacheIdentifier];o!=null&&(s=o.exports)}if(s==null){const o=new m(\"\",null);o.paths=C,o._compile(r.moduleSource,\"anonymous\"),r.cacheIdentifier!=null&&(m._cache[r.cacheIdentifier]=o),s=o.exports}}else if(r.moduleSourceType===f.File)s=await import(\"file:///\"+d.resolve(j,r.moduleSource).replaceAll(\"\\\\\",\"/\"));else{c(t,`Invalid module source type: ${r.moduleSourceType}.`);return}if(s==null||typeof s==\"object\"&&Object.keys(s).length===0){c(t,`The module ${p(r)} has no exports. Ensure that the module assigns a function or an object containing functions to module.exports.`);return}let a;if(r.exportName!=null){if(a=s[r.exportName]??((i=s.default)==null?void 0:i[r.exportName]),a==null){let o=Object.keys(s).join(\", \");c(t,`The module ${p(r)} has no export named ${r.exportName}. Available exports are: ${o}`);return}if(typeof a!=\"function\"){c(t,`The export named ${r.exportName} from module ${p(r)} is not a function.`);return}}else if(typeof s==\"function\")a=s;else if(typeof s.default==\"function\")a=s.default;else{c(t,`The module ${p(r)} does not export a function.`);return}let g=!1;const y=(o,u,h)=>{if(!g&&(g=!0,o!=null&&c(t,o),!(h!=null&&h(t))))if(u instanceof E.Readable)u.pipe(t);else if(typeof u==\"string\")t.end(u);else{let x;try{x=JSON.stringify(u)}catch(v){c(t,v);return}t.end(x)}};if(a.constructor.name===\"AsyncFunction\")y(null,await a.apply(null,r.args));else{const o=[y];a.apply(null,o.concat(r.args))}}catch(l){c(t,l)}})}function R(e,t){let n=JSON.stringify({errorMessage:e.message,errorStack:e.stack}),i=`HTTP/1.1 500 Internal Server Error\r
Content-Length: ${Buffer.byteLength(n,\"utf8\")}\r
Content-Type: text/html\r
\r
${n}`;t.end(i)}function _(e){console.log(`[Node.js HTTP server] Ignoring unexpected socket timeout for address ${e.remoteAddress}, port ${e.remotePort}`)}
" -- --parentPid 132476 --port 0
It looks like its going over multiple lines so I suspect thats the issue? The \r
seems to be causing issues I think
Yes it looks like line endings are the issue. Managed to repro with the script you pasted:
VM88 [eval1]:1 Uncaught SyntaxError: Unexpected end of input
at ModuleLoader.evalInstance (VM83 loader:203:22)
at new ModuleJob (VM87 module_job:65:26)
at ModuleLoader.eval (VM83 loader:215:17)
at node:internal/process/execution:56:55
at loadESM (VM82 esm_loader:34:13)
at evalModule (node:internal/process/execution:56:28)
at VM80 eval_string:30:3
When you open Http11Server.js, are your line endings crlf or lf?
@CallumVass good catch, I've checked on my machine, the script you pasted has "\r\r\n" line endings.
The original (pre-Vite minification) line:
Not sure what is causing "\r\n"s to become "\r\r\n"s. I can't look too deeply into this right now, but at first glance I think we can just remove the carriage return characters from that string literal.
@CallumVass what about the path to the node executable?
@ZeldaIV do you also see the "command line too long" error in the log output?
No it just throws ConnectionException
on line 445, doesn't really have any details about path in it.
Yes it looks like line endings are the issue. Managed to repro with the script you pasted:
VM88 [eval1]:1 Uncaught SyntaxError: Unexpected end of input at ModuleLoader.evalInstance (VM83 loader:203:22) at new ModuleJob (VM87 module_job:65:26) at ModuleLoader.eval (VM83 loader:215:17) at node:internal/process/execution:56:55 at loadESM (VM82 esm_loader:34:13) at evalModule (node:internal/process/execution:56:28) at VM80 eval_string:30:3
When you open Http11Server.js, are your line endings crlf or lf?
It says LF:
@CallumVass good catch, I've checked on my machine, the script you pasted has "\r\r\n" line endings.
The original (pre-Vite minification) line:
Not sure what is causing "\r\n"s to become "\r\r\n"s. I can't look too deeply into this right now, but at first glance I think we can just remove the carriage return characters from that string literal.
Remove the "\r"s and run the tests
Its still not working, the Http11Server.js
is still not on a single line
It works fine on my machine even though it's not on a single line. It's some other problem. If it's not the extra '\r's, I'm not sure what it is.
Can you try Node 20.10.0?
To add to @JeremyTCD comment, some programs like Visual Studio like to install their own node versions, which might have precedence over the installed version. The library has an option to specify the path to the executable. You could try to set that to your installed Node 20 version just to make sure it is executing the correct one.
Thanks guys for your help but I'm unable to resolve it, the version of Node I'm using is 20.5.1 as seen by one of the errors above.
I've decided to implement my own hosted node server within my .NET app to perform my JS function instead which is working fine, feel free to close this.
@CallumVass
\0
I noticed that in the script you pasted, the line actually ends with \0 which in Windows often indicates the end of a string. So I suspsect that this is the real problem rather than the new lines. @JeremyTCD do you also have the \0 present locally?
@CallumVass apologies on not having a solution.
@aKzenT Yes I do. In the script the \0 is used to demarcate the end of log messages. Agree that it's suspicious his script ends there.
On Mon, 4 Dec 2023, 17:53 aKzenT, @.***> wrote:
@CallumVass https://github.com/CallumVass
\0
I noticed that in the script you pasted, the line actually ends with \0 which in Windows often indicates the end of a string. So I suspsect that this is the real problem rather than the new lines. @JeremyTCD https://github.com/JeremyTCD do you also have the \0 present locally?
— Reply to this email directly, view it on GitHub https://github.com/JeringTech/Javascript.NodeJS/issues/186#issuecomment-1838192444, or unsubscribe https://github.com/notifications/unsubscribe-auth/ACZQXCVFJUOEGU577EHNPULYHWMQ7AVCNFSM6AAAAABABXVOXSVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMYTQMZYGE4TENBUGQ . You are receiving this because you were mentioned.Message ID: @.***>
@CallumVass apologies on not having a solution. @aKzenT Yes I do. In the script the \0 is used to demarcate the end of log messages. Agree that it's suspicious his script ends there. … On Mon, 4 Dec 2023, 17:53 aKzenT, @.> wrote: @CallumVass https://github.com/CallumVass \0 I noticed that in the script you pasted, the line actually ends with \0 which in Windows often indicates the end of a string. So I suspsect that this is the real problem rather than the new lines. @JeremyTCD https://github.com/JeremyTCD do you also have the \0 present locally? — Reply to this email directly, view it on GitHub <#186 (comment)>, or unsubscribe https://github.com/notifications/unsubscribe-auth/ACZQXCVFJUOEGU577EHNPULYHWMQ7AVCNFSM6AAAAABABXVOXSVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMYTQMZYGE4TENBUGQ . You are receiving this because you were mentioned.Message ID: @.>
No worries, thanks for your help. It looks like a great library but unfortunately it wasn't working for me, and my need is quite simple so it wasn't too difficult to implement, thanks again.
@JeremyTCD I am not sure if this is the same issue, or if I should open a new issue. I successfully implemented the library, and ran the node command in my dev environment, but after deploying to production I am getting the following error:
Process with ID XXXXX exited before connecting. at Jering.Javascript.NodeJS.OutOfProcessNodeJSService.CreateNewProcessAndConnectAsync() at Jering.Javascript.NodeJS.OutOfProcessNodeJSService.ConnectIfNotConnectedAsync(CancellationToken cancellationToken) at Jering.Javascript.NodeJS.OutOfProcessNodeJSService.TryInvokeCoreAsync[T](InvocationRequest invocationRequest, CancellationToken cancellationToken) at Jering.Javascript.NodeJS.OutOfProcessNodeJSService.InvokeFromFileAsync[T](String modulePath, String exportName, Object[] args, CancellationToken cancellationToken)
The code invoking the library is: res.html = (await _nodeService.InvokeFromFileAsync<MJMLRes>("./Services/Node/mjmlServices.js", "default", [mjml.mjml])).html;
and the code in the file is:
var _ = require('mjml');
module.exports = function (callback, mjml) {
callback(null, _(mjml, "{\"minify\": true, \"minifyOptions\":{\"collapseWhitespace\": true, \"minifyCSS\": true, \"removeEmptyAttributes\": true}}"));
}
I cannot figure out why I can get this to work in dev but not prod.
Node version is 20.13.1
Hi, I've noticed a pattern.
I have nvm for windows, and i have installed node versions (10.16.3, 18.19.0).. then when the current version is (10.16.3) and tries run InvokeFromStringAsync, the error is: Process with ID XXXX exited before connecting.
then stop my netcore application and changed to node version 18.19.0 (nvm use 18.19.0) and the script work well.
Is it possible to include a node version in my netcore to fix the node version to be used and configure the jering library to use it?
@JeremyTCD I am not sure if this is the same issue, or if I should open a new issue. I successfully implemented the library, and ran the node command in my dev environment, but after deploying to production I am getting the following error:
Process with ID XXXXX exited before connecting. at Jering.Javascript.NodeJS.OutOfProcessNodeJSService.CreateNewProcessAndConnectAsync() at Jering.Javascript.NodeJS.OutOfProcessNodeJSService.ConnectIfNotConnectedAsync(CancellationToken cancellationToken) at Jering.Javascript.NodeJS.OutOfProcessNodeJSService.TryInvokeCoreAsync[T](InvocationRequest invocationRequest, CancellationToken cancellationToken) at Jering.Javascript.NodeJS.OutOfProcessNodeJSService.InvokeFromFileAsync[T](String modulePath, String exportName, Object[] args, CancellationToken cancellationToken)
The code invoking the library is:
res.html = (await _nodeService.InvokeFromFileAsync<MJMLRes>("./Services/Node/mjmlServices.js", "default", [mjml.mjml])).html;
and the code in the file is:
var _ = require('mjml');
module.exports = function (callback, mjml) {
callback(null, _(mjml, "{\"minify\": true, \"minifyOptions\":{\"collapseWhitespace\": true, \"minifyCSS\": true, \"removeEmptyAttributes\": true}}"));
}
I cannot figure out why I can get this to work in dev but not prod.
Node version is 20.13.1
It is necessary that the machine used in production has node installed, in your case (20.13.1)
Hi,
I'm trying to use this library but I keep facing this exception when using version 7 of this library, if I downgrade to 6.3.1 it works fine?
For the avoidance of doubt, I can run node just fine from command line so its definitely on my PATH. I am using .NET 8 (I've tried in .NET 6 and 7 too) and Node 20:
Here is my log output from a small repro:
Log: