Angular2 ngIf not working in deployment environment - gulp

I've written a very simple little Angular2 app that I've built to generate exercise sheets. However it seems that when I deploy the app ngIf doesn't work (either my ISP default webserver or my own Heroku/local deployed node-http-server). When I run the exact same code base on my dev node server (npm start) ngIf works as expected.
If anyone has some guidance on how I can debug this I would be extremely grateful, or if I'm just plain doing something wrong...
Here's the relevant code
src/template.html
Click on the top left word <span *ngIf="word">({{word}})</span><span *ngIf="!word">(<click>)</span>
app.ts
import {bootstrap} from 'angular2/platform/browser'
import {enableProdMode, Component} from 'angular2/core'
enableProdMode()
#Component({
selector: 'app',
templateUrl: 'src/template.html'
})
export class AppComponent {
public word = '';
}
bootstrap(AppComponent)
When the app starts locally I see "Click on the top left word (<click>)" (as seen in this plunker link), however when I deploy the app I just see "Click on the top left word". I have previously found similar issues with ngFor in deployment. I do however see the following code in both dev and deploy
<!--template bindings={}-->
<!--template bindings={}-->
so the template is being processed, at least to some extent. My best guess is that something must be going wrong when I generate the bundle.js or dependencies.js files through gulp. I don't see any Javascript errors on the dev or deploy site via Chrome dev console though.
Here are some of the relevant tasks from my gulpfile.
gulp.task('webpack', ['clean'], function() {
return gulp.src('src/app/app.ts')
.pipe(webpack(require('./webpack.config.js')))
.pipe(gulp.dest('src/'));
});
gulp.task('dependencies', function() {
return gulp.src(['node_modules/reflect-metadata/Reflect.js',
'node_modules/zone.js/dist/zone.js'])
.pipe(concat('dependencies.js'))
.pipe(uglify())
.pipe(gulp.dest('dist/'));
});
I'm using Angular2.0.0-beta.7. My gulp deployment pipeline also uses Webpack1.12.2 with the following config:
webpack.config.js
module.exports = {
entry: './src/app/app',
output: {
path: __dirname + '/src', publicPath: 'src/', filename: 'bundle.js'
},
resolve: {
extensions: ['', '.js', '.ts']
},
module: {
loaders: [{
test: /\.ts/, loaders: ['ts-loader'], exclude: /node_modules/
}]
}
};

Thanks to #EricMartinez's debug suggestion the app now works. The problem lies with the mangling of the uglified javascript code. (I'll try and trace back what actually goes wrong during the processing of the concatenated JavaScript file.) For now turning the mangling off in uglify() does the trick, but of course I don't have obscuration of the code anymore (which isn't an issue for my particular implementation). Here's the fix:
gulpfile.js
gulp.task('js', ['webpack'], function() {
return gulp.src('src/bundle.js')
.pipe(uglify({ mangle: false })) // <- added mangle option set to false
.pipe(gulp.dest('dist/'));
});
The original code looked like this
gulp.task('js', ['webpack'], function() {
return gulp.src('src/bundle.js')
.pipe(uglify())
.pipe(gulp.dest('dist/'));
});
See this issue on github for more.

Related

Webpack source maps does not work properly in chrome

My webpack source maps are having some very unexpected behaviour when debugging in chrome.
When I hover over something I get this odd problem as can be seen in this screenshot (in the picture the mouse is hovering over props in this.props)
Notice how in the image I can type this.props in console and it correctly shows the values.
It also does not put the breakpoints on many lines but rather put them somewhere else.
Finally and maybe most crucially.
On a line like this: <QuizQuestionImage updateQuestionIdHandler={(newQuestionId) => this.updateQuestionIdHandler(newQuestionId)} /> I can put a breakpoint. And when the code is working that triggers as it should when updateQuestionIdHandler is called. However, if the method that is called, this is: this.updateQuestionIdHandler(newQuestionId) has an error, then the breakpoint is not hit correctly but rather the error is spit out in console.
This despit that it should have breaked before entering that function that in turn gave an error.
This is my webpack config.
const path = require('path');
module.exports = {
context: path.join(__dirname, 'Scripts', 'react'),
entry: {
client: './client'
},
output: {
path: path.join(__dirname, 'Scripts', 'app'),
filename: '[name].bundle.min.js'
},
module: {
rules: [
{
test: /\.jsx?$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
plugins: [require('#babel/plugin-proposal-object-rest-spread')],
presets: ["#babel/es2015", "#babel/react", "#babel/stage-0"]
}
}
}
]
},
resolve: {
extensions: ['.js', '.jsx']
},
externals: {
react: 'React'
},
devtool: 'source-map'
};
Running webpack with "-d" param gives a second set of source maps in chrome that tend to work much better.

Sourcemaps are detected in chrome but original source is not loaded, using webpack-2

When running an application that is built using webpack 2, sourcemaps are detected in chrome but original source is not loaded.
I'm using webpack beta21.
These files used to be detected automatically, ie when a breakpoint was put in the the output from webpack js file, the source view would jump to the original source input to webpack. But now I am stuck with this screen:
config:
var path = require("path");
var webpack = require("webpack");
var WebpackBuildNotifierPlugin = require('webpack-build-notifier');
const PATHS = {
app: path.join(__dirname, '../client'),
build: path.join(__dirname, '../public')
};
module.exports = {
entry: {
app: PATHS.app + '/app.js'
},
output: {
path: PATHS.build,
filename: '[name].js'
},
devtool: "source-map",
module: {
loaders: [
{
test: /\.js?$/,
loader: 'babel-loader',
include: [
path.resolve(__dirname, 'client'),
],
exclude: /node_modules/
},
{
test: /\.css/,
loader: "style!css"
}
]
},
resolve: {
// you can now require('file') instead of require('file.js')
extensions: ['', '.js', '.json']
} ,
plugins: [
new WebpackBuildNotifierPlugin()
]
};
Generated files with source maps won't automatically redirect to their original files, because there's potentially a 1-to-many relationship.
If you see the message Source Map Detected, the original file should already appear on the side file tree or the file explorer via Crl + P. If you don't know the original file name, you can open the source map file itself.
The source map path can be identified by a //# sourceMappingURL= comment or the X-SourceMap header:
Open up the source map via url and look for the sources property for the original file name:
The original file should be visible in the sources panel:
If you don't see the message Source Map Detected
You can manually add an external source map by right clicking and selecting Add Source Map:
Additional Resources
If that still doesn't work, you can try a Source Map Validator
For webpack specifically, you can configure the devtool property
If you're mapping to a workspace, that means you already have the source code. Including the source code in your source map is creating an unnecessary redundancy.
Use nosources-source-map instead.
The issue with external source maps was fixed in Chrome 52 but it looks like you've got your devtool set differently from mine, I use:
devtool: '#source-maps'
How are you building your source? If you're running with -d it will switch to inline source maps

Source Maps with Gulp, Browserify, Babel, ES6, and React

I am using Gulp with Browserify, and Babelify for ES6 and JSX-React transpiling. Despite numerous examples online, I can't figure out how to generate source-maps that point to the original pre-transpiled ES6/JSX files.
Here is my current gulp browserify task, which is based on this example:
gulp.task('browserify', function() {
browserify({ entries: './src/js/main.jsx', extensions: ['.jsx'], debug: true })
.transform(babelify, {presets: ["es2015", "react"]})
.bundle()
.pipe(source('main.js'))
.pipe(buffer())
.pipe(sourcemaps.init({loadMaps: true}))
.pipe(sourcemaps.write('./'))
.pipe(gulp.dest('dist/js'));
});
All this does is create a main.js.map file that seems to have the exact same content as the bundled main.js file. In Chrome it looks like this:
But I want to debug the original source .jsx and .js (with ES6 syntax) files. They look like this in my IDE:
How can I do this?
Add sourcemaps:true to babelify options
{presets: ["es2015", "react"],sourcemaps:true}
I simply had to change the settings in webpack.config.js
{
devtool: 'source-map', // Or some other option that generates the original source as seen from https://webpack.github.io/docs/configuration.html#devtool
...
}
You don't have to modify the sourceMap query param in Babel Loader because it is inferred from the devtool option of the Webpack config.

ES6 module import is not defined during debugger

While playing around with Babel and Webpack I stumbled into some really weird behavior today.
I threw a debugger in my main.js to see if I was importing correctly, but Chrome's console kept yelling that the module I was trying to import was not defined. I try console logging the same module instead, and I see it printed to my console.
What gives? I've pasted the relevant code snippets below:
main.js
import Thing from './Thing.js';
debugger // if you type Thing into the console, it is not defined
console.log(new Thing()); // if you let the script finish running, this works
thing.js
class Thing {
}
export default Thing;
webpack.config.js
var path = require('path');
module.exports = {
entry: './js/main.js',
output: {
path: __dirname,
filename: 'bundle.js'
},
module: {
loaders: [
{ test: path.join(__dirname, 'js'), loader: 'babel-loader' }
]
}
};
tl;dr: Babel does not necessarily preserve variables names.
If we look at the code generated from
import Thing from './Thing.js';
debugger;
console.log(new Thing());
namely:
'use strict';
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
var _ThingJs = require('./Thing.js');
var _ThingJs2 = _interopRequireDefault(_ThingJs);
debugger;
console.log(new _ThingJs2['default']());
We see that Things is not defined indeed. So Chrome is correct.
In some debugging scenarios, it may be sufficient to assign the imported variable to a new variable in local scope. For example:
import Thing from './Thing.js';
const TestThing = Thing;
debugger; // although Thing will not be defined, TestThing will be defined
console.log(new TestThing());
This doesn't fix the core issue at hand, but it can be a workaround for debugging in certain situations.
You can try my webpack plugin which defines debug vars for imports so that they are available in the debugger.
https://github.com/trias/debug-import-vars-webpack-plugin

Building durandaljs with gulp fails for external modules

I'm using gulp-durandal to build our durandal app. It fails on our first module which has a depeendecy to knockout through:
define(['knockout',....
[09:35:27] Durandal Error: ENOENT, no such file or directory 'C:\xxxxx\app\knockout.js'
In module tree:
company/viewmodels/edit
at Object.fs.openSync (fs.js:438:18)
I have knockout defined as a patch in config.js (standard requirejs way) but it seems gulp-durandal does not resolve paths from config.js ?
'knockout': '../Scripts/lib/knockout/knockout-2.3.0',
How do you get gulp-durandal to use our config paths instead of trying to resolve the modules directly under the app folder ? I tried using options.extraModules but that only allows you to add paths to modules, not symbolic names for the module so that doesn't seem to be the correct way.
The basic structure of my durandaljs app follows the standard guidelines I believe, I have a config.js and main.js under the App folder.
My config.js:
define([], function() {
return {
paths: {
'text': '../Scripts/lib/require/text',
'durandal': '../Scripts/durandal',
'plugins': '../Scripts/durandal/plugins',
My main.js
require(['config'], function(config) {
require.config(config);
require(['durandal/system', 'durandal/app', 'durandal/viewLocator', 'plugins/widget', 'custombindings'],
function(system, app, viewLocator, widget) {
..... app code here.....
}
gulpfile.js:
var gulp = require('gulp');
var durandal = require('gulp-durandal');
require(['App/config'], function(config){
console.log('loaded config');
});
gulp.task('durandal', function(){
durandal({
baseDir: 'app', //same as default, so not really required.
main: 'main.js', //same as default, so not really required.
output: 'main.js', //same as default, so not really required.
almond: true,
minify: true,
require:true
})
.pipe(gulp.dest('dir/to/save/the/output'));
});
I guess the question is how do I load my config.js paths into gulp so the paths are resolved correctly ? I tried:
var gulp = require('gulp');
var durandal = require('gulp-durandal');
require(['App/config'], function(config){
console.log('loaded config');
});
But it seems require only wants a string as input (I guess require function in gulp != require from require.js)
I believe the issue is that your gulp-durandal task needs configuration to mimic the config.js file. If you need further assistance please provide more code from your gulp-durandal task.