javascript - Números de línea incorrectos-Sourcemaps, Webpack 2 Typescript
angular google-chrome (1)
Es un problema conocido que muchas personas enfrentaron anteriormente en el pasado sin resolución. Parece que el depurador de Chrome tiene algunos errores abiertos con respecto al comportamiento similar:
https://github.com/karma-runner/karma/issues/1141
o
https://groups.google.com/forum/#!topic/google-chrome-developer-tools/n4A0WemZhHc
o
Chrome parece informar una línea incorrecta por error
Sugiero en tales casos, use Firefox.
Este problema ocurre en Chrome 59.0.3071.115 y Firefox 54.0.1
He estado investigando mucho para tratar de obtener los números de línea correctos para mi código fuente de Typescript usando Webpack 2.2.1 y el open-browser-webpack-plugin
. He intentado configurar devtool para las siguientes opciones diferentes:
//https://webpack.js.org/configuration/devtool/
//devtool: ''eval'', //eval vert fast but line numbers will be wrong
//devtool: ''eval-source-map'', //starts off slow but fast rebuild speed and correct line numbers, supposedly, not correct line numbers for typescript
//devtool: ''source-map'', //very slow, for production, most accurate source maps
//devtool: ''cheap-module-eval-source-map'',
//devtool: ''inline-source-map'',
Ninguna opción devtool
anterior proporciona el número de línea correcto de mi código fuente.
Aquí hay un ejemplo en Chrome F12 Tools, esto es con la opción devtool de devtool
"eval-source-map" que es lo mismo para "cheap-module-eval-source-map" también:
Ese es el archivo de código fuente correcto, número de línea incorrecta:
Y aquí está Firefox con un número de línea incorrecto:
Y aquí está login.component.ts, console.log console.log("hello world");
es la línea 32:
import { Component, OnDestroy, OnInit, EventEmitter, Input, Output } from ''@angular/core'';
import { Http } from ''@angular/http'';
import { ActivatedRoute, Router } from ''@angular/router'';
import { FormBuilder, FormGroup, FormControl, Validators, AbstractControl, ValidatorFn, FormArray } from ''@angular/forms'';
import { User } from ''./login.interface'';
import ''rxjs/add/operator/debounceTime'';
//Services
import { LoginService } from ''./login.service'';
import { SpinnerService } from ''../core/spinner/spinner.service'';
import { DialogService } from "ng2-bootstrap-modal";
import { LoginModal } from ''./modal/modal.component'';
//Animations
import { pageTransition } from ''../animation'';
import { Animate } from ''../core/const/animation.const'';
@Component({
templateUrl: ''./login.component.html'',
animations: [pageTransition]
})
export class LoginComponent implements OnInit {
/////////////////
// CONSTRUCTOR //
/////////////////
constructor(
private spinnerService: SpinnerService,
private router: Router,
public http: Http,
private _fb: FormBuilder,
private loginService: LoginService,
private dialogService: DialogService) { console.log("hello world"); }
//////////////
// BINDINGS //
//////////////
////////////
// FIELDS //
////////////
private state: string = Animate.in;
private background = require(''../assets/images/construction-background.jpg'');
private loginForm: FormGroup;
//Username
private userNameMessage: any[];
private userNameError: boolean = false;
//password
private passwordMessage: any[];
private passwordError: boolean;
private NgbModalOptions = { closeByClickingOutside: true, size: "lg" };
//ANY VALIDATION OBJECT
private validationMessages = {
// Note: these validation messages could easily be populated with a backend server.
required: ''This field is required'',
pattern: ''please enter a valid email address'',
minlength: ''I need more letters please''
}
ngOnInit() {
//view animations.
this.state = (this.state === Animate.in ? Animate.out : Animate.in);
// Creating the Form Group and Form Controls
this.loginForm = this._fb.group({
userName: ['''', [Validators.minLength(2)]],
password: ['''', [Validators.required]],
});
const userNameControl = this.loginForm.get(''userName'');
const passwordControl = this.loginForm.get(''password'');
//Watch User Name Control
userNameControl.valueChanges
.debounceTime(1000)
.subscribe(value => this.userNameMessage = this.setMessage(userNameControl, this.validationMessages, ''userNameError''));
//Watch Password Control
passwordControl.valueChanges
.debounceTime(1000)
.subscribe(value => this.passwordMessage = this.setMessage(passwordControl, this.validationMessages, ''passwordError''));
// Mock Spinner wait time - http call starts
this.spinnerService.display(true);
//http call ends
setTimeout(() => {
this.spinnerService.display(false);
}, 2000);
}//end ngOnInit
// LOGIN
login(resp: boolean): void {
if (resp) {
this.router.navigate([''dashboard'']);
} else {
this.dialogService.addDialog(LoginModal, { message: ''Username or password are not correct'' }, this.NgbModalOptions);
}
}
//CLEAR FORM AFTER SUMBIT CLICK
clearData() {
const loginForm = this.loginForm;
loginForm.setValue({
userName: '''',
password: ''''
})
}
//LOGIN CLICK
loginClick() {
// GET USER NAME AND PASSWORD TO SEND TO SERVER.
let body = {
''username'': this.loginForm.get(''userName'').value,
''password'': this.loginForm.get(''password'').value
};
this.loginService.validateUser(body).subscribe(
// do something with response , just logging in and routing for now.
response => this.login(true),
error => this.login(error)
);
//Clear Form
this.clearData();
}
// SET FIELD CONTROLL ERROR MESSAGES
setMessage(control: AbstractControl, messages: any, errorId: string): any[] {
//clear left over messages. If is has one
this[errorId] = false;
if ((control.touched || control.dirty) && control.errors) {
this[errorId] = true;
// Maps error type to string and returns array of appropriate error messages.
return Object.keys(control.errors).map(key => messages[key])
}
}
}// End Class
Y aquí está mi webpack.config.js
:
var webpack = require(''webpack''),
htmlPlugin = require(''html-webpack-plugin''),
revPlugin = require(''webpack-rev-replace-plugin''),
config = require(''./build.config.json''),
path = require(''path''),
extendedDefinePlugin = require(''extended-define-webpack-plugin''),
webpackDelPlugin = require(''webpack-del-plugin'');
OpenBrowserPlugin = require(''open-browser-webpack-plugin'');
output = require(''to-string-loader'');
//Note : in package.json the last variable (dev) is the param delivered to this function { env: ''dev'' }.
module.exports = function (env) {
// Note : ''__dirname'' is the root file path.
const ROOT_DIR = path.resolve(__dirname);
const DIST_DIR = path.join(ROOT_DIR, config.dist);
console.log(__dirname);
// If no env make it the dev
if (!env) {
env = {};
env.env = config.envDev;
}
console.log(''env configuration'', env.env);
// this takes path variables from build.config.json and builds it with given env
var appConfigPath = config.envs + config.appConfig.replace(''{env}'', env.env);
return {
entry: config.src + config.entry,//main.ts
output: {
path: path.join(__dirname, config.dist),
filename: config.buildjs,
sourceMapFilename: config.buildjsmap
},
module: {
loaders: [
{ test: //.html$/, use: ''raw-loader'' },
{ test: //.css$/, use: ''raw-loader'' },
{ test: //.ts$/,
loaders: [
''ts-loader'',
''angular2-template-loader'',
''angular-router-loader'']
},
{ test: //.scss$/,
exclude: /node_modules/,
loaders: [''style-loader'', ''css-loader'', ''sass-loader''],
},
//For images.
{ test: //.(jpe?g|png|gif|svg)$/i, loader: "file-loader?name=app/assets/images/[name].[ext]"},
{ test: //.(ttf|eot|woff|woff2)$/,
loader: ''file-loader''
},
]
},
//https://webpack.js.org/configuration/devtool/
//devtool: ''eval'', //eval vert fast but line numbers will be wrong
devtool: ''eval-source-map'', //starts off slow but fast rebuild speed and correct line numbers, supposedly, not correct line numbers for typescript
//devtool: ''source-map'', //very slow, for production, most accurate source maps
//devtool: ''cheap-module-eval-source-map'',
//devtool: ''inline-source-map'',
//
resolve: {
extensions: [''.js'', ''.ts'',''.scss'',''.css'']
},
plugins: [
new htmlPlugin({
template: config.src + config.index
}),
// Not in use from what I can see - Nick July 9th 2017
new revPlugin({
cwd: config.src,
files: ''**/*.html'',
outputPageName: function (filename) {
return filename;
},
modifyReved: function (filename) {
return filename.replace(/(//style//|//script//)/, '''')
}
}),
//Makes AppConfig variable available in the application code.
new extendedDefinePlugin({
AppConfig: require(appConfigPath)
}),
//Usefull if you need remove some files or folders before compilation processes.
//currently not used (no dist file).
new webpackDelPlugin({match: path.join(DIST_DIR, ''*.*'')}),
//opens browser after compilation.
new OpenBrowserPlugin({ url: ''http://localhost:8080'' })
]
}
}
Y aquí está mi tsconfig.json
:
{
"compilerOptions": {
"target": "es5", //most browsers currently understand this version of Javascript
"experimentalDecorators": true, //Angular2 uses Component,Injectable etc
"emitDecoratorMetadata": true, //Required for Angular2 to use the metadata in our components
"sourceMap": true,
"types": [
"node",
"jasmine"
]
}
}
Y aquí está mi package.json
npm.json
{
"name": "angular2-starter",
"version": "0.1.0",
"scripts": {
"test": "karma start",
"build-dev": "webpack --progress --colors --env.env dev",
"build-qa": "webpack --progress --colors --env.env qa",
"build-prd": "webpack -p --progress --colors --env.env prd",
"postinstall": "typings install",
"serve": "webpack-dev-server --inline --progress --colors --env.env dev"
},
"dependencies": {
"@angular/animations": "^4.1.3",
"@angular/common": "^4.1.3",
"@angular/compiler": "^4.1.3",
"@angular/compiler-cli": "^4.1.3",
"@angular/core": "^4.1.3",
"@angular/forms": "^4.1.3",
"@angular/http": "^4.1.3",
"@angular/material": "^2.0.0-beta.5",
"@angular/platform-browser": "^4.1.3",
"@angular/platform-browser-dynamic": "^4.1.3",
"@angular/platform-server": "^4.1.3",
"@angular/router": "^4.1.3",
"@angular/cdk": "^2.0.0-beta.8",
"@ng-bootstrap/ng-bootstrap": "^1.0.0-alpha.26",
"angular2-jwt": "^0.2.3",
"angular2-wizard": "^0.3.0",
"bootstrap": "^4.0.0-alpha.6",
"core-js": "2.4.1",
"font-awesome": "^4.7.0",
"hammerjs": "^2.0.8",
"ng2-bootstrap-modal": "1.0.1",
"ng2-drag-drop": "^2.0.1",
"reflect-metadata": "0.1.8",
"rxjs": "^5.0.0-beta.12",
"systemjs": "0.19.40",
"typescript": "^2.4.1",
"zone.js": "^0.7.8"
},
"devDependencies": {
"@types/jasmine": "^2.5.53",
"angular-router-loader": "^0.6.0",
"angular2-router-loader": "^0.3.5",
"angular2-template-loader": "^0.6.2",
"css-loader": "^0.27.3",
"extended-define-webpack-plugin": "^0.1.3",
"file-loader": "^0.10.1",
"html-webpack-plugin": "^2.28.0",
"install": "^0.8.7",
"jasmine": "^2.6.0",
"karma": "^1.7.0",
"karma-sourcemap-loader": "^0.3.7",
"karma-webpack": "^2.0.4",
"node-sass": "^4.5.0",
"npm": "^4.4.1",
"open-browser-webpack-plugin": "0.0.5",
"path": "^0.12.7",
"prepack-webpack-plugin": "^1.1.0",
"raw-loader": "^0.5.1",
"sass-loader": "^6.0.3",
"style-loader": "^0.13.2",
"to-string-loader": "^1.1.5",
"ts-loader": "^2.0.1",
"typings": "^2.1.0",
"webpack": "^2.2.1",
"webpack-del-plugin": "0.0.1",
"webpack-dev-server": "^2.4.1",
"webpack-merge": "^4.1.0",
"webpack-rev-replace-plugin": "^0.1.1"
}
}
Entiendo que estoy viendo el número de línea de la versión login.component.ts
de mi archivo login.component.ts
, login.component.ts
en las Herramientas para desarrolladores de Chrome, así que me pregunto si hay una forma de cambiar la configuración del mapa de fuentes de mi Webpack para ver el número de línea real de login.component.ts
de login.component.ts
antes de la compilación de login.component.ts
?