How to be able to set up breakpoints correctly when using VS Code to debug a TypeScript app run using ts-node in a Docker container? : <p>Our app is written in TypeScript and uses Docker, and to avoid round-tripping through .js files, we're running it with <a href="https://github.com/TypeStrong/ts-node" rel="noreferrer">ts-node</a> to load the .ts files directly.</p>

<p>Unfortunately this seems to make VSCode confused as to where valid lines of code are for setting breakpoints.</p>

<p>This problem manifests with the following setup:</p>

<h1>/package.json</h1>

<pre class="lang-json prettyprint-override"><code>{
  "scripts": {
    "start": "node --inspect=0.0.0.0 --require ts-node/register src/index.ts"
  },
  "dependencies": {
    "@types/node": "^10.1.2",
    "ts-node": "^6.0.3",
    "typescript": "^2.8.3"
  }
}
</code></pre>

<h1>/tsconfig.json</h1>

<pre class="lang-json prettyprint-override"><code>{
  "compilerOptions": {
    "target": "ES2017",
    "module": "commonjs", 
    "outDir": "./dist",
    "rootDir": "./src",    
    "esModuleInterop": true
  }
}
</code></pre>

<h1>/Dockerfile</h1>

<pre><code>FROM node

RUN mkdir /home/node/app
WORKDIR /home/node/app
COPY package.json /home/node/app
RUN npm install &amp;&amp; npm cache clean --force
COPY . /home/node/app
CMD [ "npm", "start" ]
</code></pre>

<h1>/docker-compose.yml</h1>

<pre class="lang-yaml prettyprint-override"><code>version: "3.4"

services:
  http:
    build: .
    ports:
      - "8000:8000"
      - "9229:9229"
</code></pre>

<h1>/.vscode/launch.json</h1>

<pre class="lang-json prettyprint-override"><code>{
    "version": "0.2.0",
    "configurations": [
        {
            "type": "node",
            "request": "attach",
            "name": "Attach",
            "address": "localhost",
            "port": 9229,
            "protocol": "inspector",
            "localRoot": "${workspaceFolder}/src",
            "remoteRoot": "/home/node/app/src"
        }
    ]
}
</code></pre>

<h1>/src/index.ts</h1>



<pre><code>import {createServer} from "http";








const server = createServer((msg, res) =&gt; {
    res.writeHead(200, {'Content-Type': 'text/plain'})
    res.end(msg.url)
    debugger
})

server.listen(8000)
</code></pre>

<p>(The blank lines are significant for reasons I'll show later, about ten of them does the job.)</p>

<p>You can also fetch the whole thing here: <a href="https://github.com/millimoose/ts-node-breakpoints" rel="noreferrer">https://github.com/millimoose/ts-node-breakpoints</a></p>

<p>I run this with <code>docker-compose --up</code>, then attach to that with the debugger using the above launch configuration. When I try to set breakpoints in <code>/src/index.ts</code> on any of the lines inside the <code>createServer()</code> call, they're reported as invalid; while I can set breakpoints in the blank lines. This is presumably because TypeScript compilation strips the blank lines, and for some reason, VSCode will only recognize line numbers from the generated JS as valid:</p>

<p><a href="https://i.stack.imgur.com/g4YWo.png" rel="noreferrer"><img src="https://i.stack.imgur.com/g4YWo.png" alt="line number mismatch between TS and JS"></a></p>

<p>This is a contrived example for ease of reproduction, but in general there'll be a mismatch between where I think I'm setting breakpoints, and where they're actually set.</p>

<p>However, when I break on the <code>debugger</code> statement, VSCode fetches the TypeScript file (the tab says something along the lines of "read-only inlined from sourcemap" when newly opened) from the server, and I can then set breakpoints correctly in it:</p>

<p><a href="https://i.stack.imgur.com/rRDu9.png" rel="noreferrer"><img src="https://i.stack.imgur.com/rRDu9.png" alt="breakpoints in local vs. remote file"></a></p>

<p>This is an unsatisfying situation for reasons I shouldn't have to explain: juggling a local file I can edit and a remote file where breakpoints work is a hassle, and adding <code>debugger</code> statements would involve reloading the app everytime I need a new breakpoint.</p>

<p>I've searched around for the issue, but the keywords give me at least ten lengthy GitHub issues ranging as far as years back. Since I'm not intimately familiar with the internals of ts-node, transpilation, and sourcemaps, I'm having a hard time reasoning through what's going on here, much less how to fix it. From what I understand, what happens is that ts-node compiles TS to JS and generates sourcemaps in temporary files inside the Docker container where VSCode can't access them. (This is why I've no idea how to set e.g. <code>outFiles</code>.) There were also some allusions to my scenario being already supported if set up correctly in closed issues, but no clue as to how to do it.</p>

<p>Is there a way to get this working so that I can actually set a breakpoint in my local sources when remote-debugging, and have them hit in said files, without having to revert to precompiling TS to JS and sourcemaps so I have the latter available locally?</p>
