I try to learn how to use the debugger in VS Code for my Node.js application. I've found quite a few posts here and there about this, but I can't manage to have things work smoothly.
The end goal is to have a Typescript project with Babel 7 handling the compilation. And I want it to run on the latest version of Node.js (11.0.0).
I had average results so far, but I found a very good article on Medium which presents exactly what I want to do, except that it doesn't have typescript and it runs on Babel 6. But I figure that it is a great starting point to learn, so I try to reproduce it ... and I find that it doesn't behave the same way depending on the version of Node.js that I am running.
Here is what I do...
Running Node.js 8.12.0 and VS Code 1.28, I create a new project folder and I run the commands npm init -y and npm install --save-dev babel-cli babel-preset-es2015.
I update my package.json as follows:
// package.json
"devDependencies": {
"babel-cli": "^6.26.0",
"babel-preset-es2015": "^6.24.1"
},
"babel": {
"presets": [
"es2015"
]
}
I then create 2 javascript files containing my code:
// src/app.js
import {add, multiply} from './math';
const num1 = 5, num2 = 10; // breakpoint on this line
console.log('Add: ', add(num1, num2));
console.log('Multiply: ', multiply(num1, num2));
// src/math.js
export function add(num1, num2) {
return num1 + num2; // breakpoint on this line
}
export function multiply(num1, num2) {
return num1 * num2; // breakpoint on this line
}
I update the package.json file with the following script
// package.json
"scripts": {
"compile": "babel src --out-dir .compiled --source-maps --watch"
},
When I run npm run compile, 4 files are created in the ./.compile/ folder, 2 of which are .map files.
Until now, everything goes fine. I then proceed with configuring the debugger in VS Code.
I create a .vscode/launch.json file and I edit it as follows:
{
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "Launch App.js",
"program": "${workspaceRoot}/src/app.js",
"outFiles": [
"${workspaceRoot}/.compiled/**/*.js"
]
}
]
}
After placing 3 breakpoints (see my comments in the code above) in my code, I run the debugger which stops on all 3 breakpoints.
Happy with my results, I update Node.js to v9.11.2. I run the debugger again, and it performs the same. Good.
Then, I update Node.js v10.13.0. Without modifying anything in VS Code or in my code, I run the debugger again. This time, only the breakpoint in src/app.js is considered. The 2 breakpoints in src/math.js are ignored. Why?
When updating Node.js to v11.0.0, I make the same observation.
I figure that something has changed in the way Node.js performs the debugging when they updated from v9.x.x to v10.x.x, but I can't find what.
I believe that I just need to configure launch.json a bit differently, and I have tried many things without success. My current launch.json is the following:
{
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "Launch App.js",
"program": "${workspaceFolder}/src/app.js",
"outFiles": [
"${workspaceFolder}/.compiled/**/*.js"
],
"sourceMaps": true,
"protocol": "inspector"
}
]
}
Any idea why it doesn't work with Node v10.x and above, and how I can fix this?
Many thanks!
Related
I am working on the Odin project and I have arrived at the test driven part.
I am on windows, installed everything as instructed and I use VS code as my IDE.
Now, I use VS code debugger to run the tests i.e. for the first case hello world I run the debugger on the helloWorld.spec.js file.
The tests runs as expected ... but in fact it runs all the 14 tests not only the one I am working on. As I am curious to understand how it works I would like to succeed running only the test I am working on.
I searched on Google but I couldn't find an answer that make my quest a success.
Do you know how to achieve this ? My configuration is shown herebelow.
First, my structure :
Then, my debug config file
"version": "1.0.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "Jest: current file",
//"env": { "NODE_ENV": "test" },
"program": "${workspaceFolder}/node_modules/.bin/jest",
"args": ["--runInBand", "--no-cache", "--watchAll=false"],
"console": "integratedTerminal",
"disableOptimisticBPs": true,
"windows": {
"program": "${workspaceFolder}/node_modules/jest/bin/jest"
}
}
]
}
I also installed jest extension in VS code, in the hope to solve my issues and here are the settings for that extension :
"jest.autoRun": {
"watch": false,
"onSave": "test-src-file",
"onStartup": [
"all-tests"
]
},
"jest.debugCodeLens.showWhenTestStateIn": [
"pass",
"fail",
"unknown"
],
"jest.coverageFormatter": "GutterFormatter",
I have two js files : play.js and myStore.js.
I want to import code from myStore.js into play.js and use it there. I'm using es2015 plugin for the import, But it makes my es2017 friendly code fail, even though I have es2017 setup.
play.js:
import G from '../functions/myStore.js'; // import needs es2015
// this works with es2017, but not when es2015 is also included
for(k in [1,2,3]) console.log(k)
myStore.js
var G = {}
export default G
Output: If I did not import anything, and just used the es2017 preset, this would run fine, but using es2015 along with es2017 makes this fail as below:
for (k in [1, 2, 3]) {
^
ReferenceError: k is not defined
I'm executing this from terminal via npm start . Here's my package.json:
{
"name": "functions",
"version": "1.0.0",
"description": "",
"main": "play.js",
"scripts": {
"start": "babel-node play.js"
},
"author": "Somjit",
"license": "ISC",
"devDependencies": {
"babel-cli": "^6.24.0",
"babel-preset-es2015": "^6.24.0",
"babel-preset-es2015-node5": "^1.2.0",
"babel-preset-es2017": "^6.22.0"
}
}
and my babel.rc:
{ "presets": ["es2015", "es2017"] }
Ok. My short answer would be...
1) Babel reads your code and if it sees some new js feature it translate it to regular js by using presets. For example, if it sees let a = 1 Babel uses preset-es2015 (that knows what let is) and translate this line into var a = 1 so your browser could understand this line.
2) If you look to the docs of babel-preset-es2017 you'll see that it supports only two features. You have not this features in your code. So babel don't use this preset while reading code that you've provided. So es2017 don't matter in your problem.
3) If you run your code without es2015 it allows you to declare variables without var (because you can do this in js without strict mode). But when you use this preset Babel reads your code and trows an Error because according to new js standarts you need to declare variables with var, let or const and can't just write a = 1;
when I started with babel even small stuff where taking too much time to understand.
then I found this tutorial which helped me a lot.
In Your case, absolutely your problem is not babel-preset-es2017. you must install babel-plugin-transform-runtime and put it in your .babelrc file as plugin.
installing:
npm install --save-dev babel-plugin-transform-runtime
setting .babelrc file:
{
"presets": [
"es2015",
"es2017"
],
"plugins": [
"transform-runtime"
]
}
I create a directory test and npm init in it. I write a simple code to index.js:
'use strict';
let i = 3*4;
console.log("HELLO TEST");
console.log("HELLO TEST");
With this in package.json:
{
"version": "0.2.0",
"configurations": [
{
"name": "Launch",
"type": "node",
"request": "launch",
"program": "${workspaceRoot}/index.js",
"stopOnEntry": false,
"args": [],
"cwd": "${workspaceRoot}",
"preLaunchTask": null,
"runtimeExecutable": null,
"runtimeArgs": [
"--nolazy"
],
"env": {
"NODE_ENV": "development"
},
"externalConsole": false,
"sourceMaps": false,
"outDir": null
}
]
}
Now, I put a breakpoint at line two and run the code. Everything works as expected, I can step through the code line by line and see the values update (in this case, the value i updates) and write to the console after
Now I install npm install --save-dev babel-cli and modify the launch.json: "runtimeExecutable": "${workspaceRoot}/node_modules/.bin/babel-node",
Now the debug line isn't aligned, it starts off here, and i isn't defined
The problem worsens when I add more lines:
i is still not defined!
A few days ago, I didn't have problems like this. I didn't change node versions. I might have changed VS code versions. Currently, I installed the latest version (1.3.1) and I get this problem. I also tried to revert to 1.2.1 and still have this problem.
I don't understand how I can get this to work again. It was perfect before! It's a big pain not to be able to debug correctly.
I am trying to run the babel-preset-es2015 on my JavaScript using gulp, but it takes forever even on one line of code. I originally tried with my script bundle that is about 700 loc, and then with a dummy script that is 1 line. The first case takes about 9s - with 1 line i takes 8.38s.
This is my exact setup:
package.json:
{
"devDependencies": {
"gulp": "^3.9.0",
"gulp-babel": "^6.1.1",
"babel": "^6.3.26",
"babel-preset-es2015": "^6.3.13"
},
"babel": {
"presets": [ "es2015" ]
}
}
gulpfile.js:
gulp.task('js', function () {
return gulp.src('dummyscript.js')
.pipe(concat('site.bundle.js'))
.pipe(babel())
.pipe(gulp.dest(paths.dest.scripts));
});
dummy.js:
console.log('dummy script');
I'm running node v4.2.4 and npm v2.14.12.
Other operations like gulp-react and gulp-uglify all take about 180ms combined.
What is going on?
Babel 6 has many highly-nested subdependencies. This can be quite slow if you have a non-flattened dependency tree. In your case, you are using npm 2, you will need to either npm dedupe or install npm#3 and reinstall so that your dependencies are flattened.
I've been reading articles on this all morning trying to get my environment setup correctly. But for some reason I'm not getting it. My setup-
/app
... source (mixed js and ts)
/scripts
... copied source (js)
typescripts.js // transpiled typescript with inline mapping
Tests run fine, and with the mapping debugging in the chrome debugger is mapped correctly. But Istanbul sees the typescripts.js file as one file instead of the concatenation of dozens of other files.
To generate the typescript source I'm using gulp-typescript. The source (excluding tests) are transpiled to the aforementioned typescripts.js, and the tests are transpiled individually and copied to /scripts.
var ts = require('gulp-typescript');
var sourcemaps = require('gulp-sourcemaps');
var concat = require('gulp-concat');
module.exports = function (gulp, config) {
'use strict';
// Runs dot ts files found in `www` through the typescript compiler and copies them as js
// files to the scripts directory
gulp.task('typescript', ['typescript:tests'], function () {
return gulp.src(config.paths.typescript) // [ './www/app/**/*.ts', '!./www/app/**/*.test.ts', '!./www/app/**/*.mock.ts' ]
.pipe(sourcemaps.init())
.pipe(ts(ts.createProject(config.paths.tsConfig))) // './tsconfig.json'
.js
.pipe(concat(config.sourcemaps.dest)) // typescripts.js
.pipe(sourcemaps.write(config.sourcemaps)) // { includeContent: false, sourceRoot: '/app' } - i've also tried absolute local path
.pipe(gulp.dest(config.paths.tmpScripts)); // ./www/scripts
});
gulp.task('typescript:tests', [], function() {
return gulp.src(config.paths.typescriptTests) // [ './www/app/**/*.test.ts', './www/app/**/*.mock.ts' ]
.pipe(ts(ts.createProject(config.paths.tsConfig))) // './tsconfig.json'
.pipe(gulp.dest(config.paths.tmpScripts)); // ./www/scripts
});
};
The resulting typescripts.js has the inline sourcemap. With the sourcemap, the dozen or so ts files results in 106kb.
So from here tests and debugging works fine.
Now in an attempt to get Istanbul code coverage working properly i've installed karma-sourcemap-loader and added it to the preprocessors.
preprocessors: {
'www/scripts/typescripts.js': ['sourcemap'],
'www/scripts/**/*.js': ['coverage']
},
I'd think this is what I'd need to do. But it does not show code coverage on the source files. I tried the absolute path from C:/ but that didn't work either. I also tried the different options in gulp-sourcemaps like adding source (which pushed the file to 160kb) but no like either.
Has anyone gotten this to work? Any ideas what I could be doing wrong?
TL;DR: There is a tool: https://github.com/SitePen/remap-istanbul described as A tool for remapping Istanbul coverage via Source Maps
The article on Sitepan describes it in more detail:
Intern as well as other JavaScript testing frameworks utilise Istanbul
for their code coverage analysis. As we started to adopt more and more
TypeScript for our own projects, we continued to struggle with getting
a clear picture of our code coverage as all the reports only included
the coverage of our emitted code. We had to try to use the compilers
in our minds to try to figure out where we were missing test coverage.
We also like to set metrics around our coverage to let us track if we
are headed the right direction.
A couple of us started exploring how we might be able to accomplish
mapping the coverage report back to its origins and after a bit of
work, we created remap-istanbul, a package that allows Istanbul
coverage information to be mapped back to its source when there are
Source Maps available. While we have been focused on TypeScript, it
can be used wherever the coverage is being produced on emitted code,
including the tools mentioned above!
How to use the tool with gulp: https://github.com/SitePen/remap-istanbul#gulp-plugin
If you want source map support with Istanbul, you can use the 1.0 alpha release as the current release does not support source maps. I have it set up using ts-node in http://github.com/typings/typings (see https://github.com/typings/typings/blob/bff1abad91dabec1cd8a744e0dd3f54b613830b5/package.json#L19) and source code is being mapped. It looks great and is nice to have my tests and code coverage all running in-process with zero transpilation. Of course, you can use Istanbul 1.0 with the transpiled JavaScript.
For the browser implementation you're using, I'd have to see more of code of what you're doing to see this'll just work for you, but try the 1.0.0-alpha.2 and see what happens.
As blakeembrey mentioned. Istanbul 1.x handles it well.
Below an example of pure npm script that does it with Jasmine.
See https://github.com/Izhaki/Typescript-Jasmine-Istanbul-Boilerplate.
package.json (the relevant stuff)
{
"scripts": {
"postinstall": "typings install dt~jasmine --save --global",
"test": "ts-node node_modules/.bin/jasmine JASMINE_CONFIG_PATH=jasmine.json",
"test:coverage": "ts-node node_modules/istanbul/lib/cli.js cover -e .ts -x \"*.d.ts\" -x \"*.spec.ts\" node_modules/jasmine/bin/jasmine.js -- JASMINE_CONFIG_PATH=jasmine.json"
},
"devDependencies": {
"istanbul": "^1.1.0-alpha.1",
"jasmine": "^2.4.1",
"ts-node": "^0.9.3",
"typescript": "^1.8.10",
"typings": "^1.3.1"
},
}
Output
This is repo works. I ran the repo and can see the tests running. Html view is also generated.
https://github.com/Izhaki/Typescript-Jasmine-Istanbul-Boilerplate
None of the examples provided worked for my Node.JS project (written in TypeScript). I wanted to run unit tests in Jasmine, and covered by Istanbul.
I ended up getting it working with the following.
package.json:
{
"scripts": {
"lint": "tslint 'src/**/*.ts'",
"remap": "./node_modules/.bin/remap-istanbul -i ./coverage/coverage-final.json -t html -o ./coverage && rimraf ./coverage/dist",
"test": "npm run lint && rimraf dist coverage && tsc --project tsconfig-test.json && ./node_modules/.bin/istanbul cover ./node_modules/.bin/jasmine JASMINE_CONFIG_PATH=jasmine.json && npm run remap"
},
"devDependencies": {
"#types/jasmine": "2.8.6",
"#types/node": "9.6.6",
"istanbul": "0.4.5",
"jasmine": "3.1.0",
"remap-istanbul": "0.11.1",
"rimraf": "2.6.2",
"tslint": "5.9.1",
"typescript": "2.8.1"
}
}
jasmine.json
{
"spec_dir": "dist",
"spec_files": [
"**/*.spec.js"
],
"stopSpecOnExpectationFailure": false,
"random": false
}
.istanbul.yml
instrumentation:
root: ./dist
excludes: ['**/*.spec.js', '**/fixtures/*.js']
include-all-sources: true
reporting:
reports:
- html
- json
- text-summary
dir: ./coverage
tsconfig-test.json
{
"compilerOptions": {
"declaration": true,
"lib": [
"dom",
"es6"
],
"module": "commonjs",
"noImplicitAny": true,
"outDir": "dist",
"sourceMap": true,
"target": "es5"
},
"include": [
"src/**/*.ts"
],
"exclude": [
"node_modules"
]
}