Sharing My Findings
Here is how I set up a VSCode environment for developing and debugging n8n and a custom nodes package.
Many of it is based on the post https://community.n8n.io/t/how-to-run-n8n-in-debug-mode-with-vscode/, but with a lot of things that I had figured out, partially for not being a skilled Typescript programmer.
There are 2 different parts: the n8n itself, and a custom module that I will call n8n-nodes-custom
(from here).
So, I created a folder to keep everything in, and inside I cloned n8n repo, installed its’s dependencies, then created the n8n-nodes-custom
from the template repo.
The actual commands are something like this (I don’t remember exactly how I did it). It assumes to have all dev dependencies installed (npm, lerna, dev tools) from the contributing guide.
mkdir n8n-root
cd n8n-root
git clone https://github.com/n8n-io/n8n.git
git clone https://github.com/n8n-io/n8n-nodes-starter.git n8n-nodes-custom
cd n8n
lerna bootstrap --hoist
npm run build
# link the custom module here, so n8n can detect and load it
ln -sr ../n8n-nodes-custom ./node_modules
cd ../n8n-nodes-custom
npm install
npm run build
# now we can run it like
cd ..
./n8n/packages/cli/bin/n8n
VSCode setup
Just reminding, the n8n project is composed by many node packages in the folder packages
. Running lerna exec npm run build
will run, sequentially, the npm run build
command for every package that has the build command in its package.json
. Some packages are faster to build (like cli
) and some of them can be very time consuming, like the editor-ui
. So depending on what you are working on, it’s better to just build what you need.
With above setup, here is the VSCode config for it:
n8n-root/n8n.code-workspace
To be saved in the n8n-root folder
{
"folders": [
{
"path": "."
},
{
"path": "n8n"
},
{
"path": "n8n-nodes-custom"
}
],
"settings": {}
}
n8n-root/.vscode/tasks.json
(for build tasks)
3 tasks and 1 group:
- One for building (compiling) the whole n8n package.
- As the build of some parts are slow, there is an example of tash to build one specific part of the n8n, in this case, the
cli
. - And the third one is to build the custom package.
- The last one is a group of tasks. You can group all tasks that you want to run before a debug session, like building all components that you are actively developing. It can be done in parallel (
"dependsOrder": "parallel"
), or sequential ("dependsOrder": "sequence"
).
{
"version": "2.0.0",
"tasks": [
{
"type": "npm",
"script": "build",
"group": "build",
"label": "npm: build n8n",
"detail": "lerna exec npm run build",
"problemMatcher": [ "$tsc" ],
"options": {"cwd": "${workspaceFolder}/n8n"},
"path": "n8n",
},
{
"type": "npm",
"script": "build",
"group": "build",
"label": "npm: build cli",
"detail": "npm run build [cli]",
"problemMatcher": [ "$tsc" ],
"options": {"cwd": "${workspaceFolder}/n8n/packages/cli"},
"path": "n8n/packages/cli"
},
{
"type": "npm",
"script": "build",
"group": "build",
"label": "npm: build n8n-nodes-custom",
"detail": "npm run build [custom]",
"problemMatcher": [ "$tsc" ],
"options": {"cwd": "${workspaceFolder}/n8n-nodes-custom"},
"path": "n8n-nodes-custom"
},
{
"label": "build all",
"dependsOrder": "parallel",
"dependsOn": [
"npm: build n8n-nodes-custom",
]
}
]
}
n8n-root/.vscode/launch.json
(for debugging)
There are 3 options here for debugging:
- The last one will run in dev mode. It means it will automatically watch for changes in the code and recompile it. Usually, it has poor debug integrations. It’s better for running in the terminal. I leave it here just in case.
- The other 2 are almost the same, but one will run a task defined in
tasks.json
that will run the build scripts that are needed. In particular, intasks.json
, thebuild all
is a task group, that you will name all the other tasks you want to run. If you are just developing custom nodes, the n8n itself, or both, you can choose there. Reminding that building all n8n is time-consuming, so it’s better explicitly to tell which parts of the n8n you want to build for efficiency. - The
"env": { "EXECUTIONS_PROCESS": "main" }
was taken from here
I have a lot of headaches trying to debug the Typescript code. There were a few tricks that proved to be useful:
-
In the
package.json
n8n
part where you add the nodes and credentials, you can add the.ts
file instead of the compiled.js
. E.g. instead of"dist/nodes/Cron.node.js"
, you can add"nodes/Cron.node.ts"
(without thedist/
in the path, and using.ts
extension). The loading time will be a lot slower, as it seems that it compiles the TS file and it’s requirements when importing the file. But if you are having issues with debugging (like being able to put a breakpoint in the code), this may help. Adding it together with the JS version (both the.js
and the.ts
files) in it at the same time seems to works fine, and it’s easier than rewrite the path every time. -
Another way I found out to debug the typescript code is using the
*.ts
instead of.js
files in thelaunch.json
:outFiles
. Why? I don’t know, but it works. From what I have understood, here you are supposed o put the paths to the.js
files generated by the transpiler. But when I do that, it debugs the.js
files, not the original.ts
ones. I.e., breakpoints or stepping through works only with the generated.js
files, and setting a breakpoint in the.ts
file will show a grayed out circle instead of a full red one indicating it’s not working. But listing the.ts
files in theoutFiles
instead makes the debug to work the original input files in Typescript. If you know why, please tell me! As it works I’m just sticking with it .
{
"version": "0.2.0",
"configurations": [
{
"type": "pwa-node",
"request": "launch",
"name": "n8n: build & start",
"preLaunchTask": "build all",
"cwd": "${workspaceFolder}/n8n",
"program": "${workspaceFolder}/n8n/packages/cli/bin/n8n",
"skipFiles": [ "<node_internals>/**" ],
"outFiles": [
"${workspaceFolder}/n8n/packages/**/*.ts",
"${workspaceFolder}/n8n-nodes-*/**/*.ts",
"!**/node_modules/**"
],
"env": { "EXECUTIONS_PROCESS": "main" },
},
{
"type": "pwa-node",
"request": "launch",
"name": "n8n: start",
"cwd": "${workspaceFolder}/n8n",
"program": "${workspaceFolder}/n8n/packages/cli/bin/n8n",
"skipFiles": [ "<node_internals>/**" ],
"outFiles": [
"${workspaceFolder}/n8n/packages/**/*.ts",
"${workspaceFolder}/n8n-nodes-*/**/*.ts",
"!**/node_modules/**"
],
"env": {
"EXECUTIONS_PROCESS": "main",
},
},
{
"type": "node-terminal",
"request": "launch",
"name": "n8n: dev",
"command": "npm run dev",
"cwd": "${workspaceFolder}/n8n",
"skipFiles": [ "<node_internals>/**" ],
"outFiles": [
"${workspaceFolder}/n8n/packages/**/*.ts",
"${workspaceFolder}/n8n-nodes-*/**/*.ts",
"!**/node_modules/**"
],
"env": { "EXECUTIONS_PROCESS": "main" },
}
],
}
I hope this may be helpful for someone passing by what I did, so I’m sharing it here. I may update it as I go, if I find more gotchas. Also, everything that I wrote here is in the public domain (CC0) and can be copied and shared freely.