Repository navigation
HMR no longer working when upgraded to latest version #725
Description
Firstly, this project is based on famous .Net Core and ng2 template for Visual Studio 2015 Link to VS 2015 Template Tutorial
The problem started when I decided to upgrade all libraries to latest version (@angular:^2.4.8 and WebPack:^2.2.1). I got so many errors coz of major breaking changes in this upgrade journey. I managed to sort out almost all and got the app up and running as usual except this final issue.
It doesn't load the changes anymore by using HotModuleReplacement (HMR). All the changes reflect on the page, when I refresh (F5) on the browser. It just stops automatic updating.
We can see here that it does know the changes, compiled and returned the latest (correct) html codes, but it couldn't load it back on the page.
I have double checked that the new file is generated for 'dist/main-client.js' and it is re-generated every time I change something in html/ts file. However, it keeps saying that Selector 'app' did not match any elements.
webpack.config.vendor.js
I have included aspnet-prerendering in the vendor entry.
var isDevBuild = process.argv.indexOf('--env.prod') < 0;
var path = require('path');
var webpack = require('webpack');
const ContextReplacementPlugin = require('webpack/lib/ContextReplacementPlugin');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
module.exports = {
resolve: {
extensions: [ '*', '.js' ]
},
module: {
loaders: [
{ test: /\.(png|woff|woff2|eot|ttf|svg)(\?|$)/, loader: 'url-loader?limit=100000' },
{ test: /\.css(\?|$)/, loader: ExtractTextPlugin.extract("css-loader") }
]
},
entry: {
vendor: [
'@angular/common',
'@angular/compiler',
'@angular/core',
'@angular/http',
'@angular/platform-browser',
'@angular/platform-browser-dynamic',
'@angular/router',
'@angular/platform-server',
'angular2-universal',
'angular2-universal-polyfills',
'bootstrap',
'bootstrap/dist/css/bootstrap.css',
'es6-shim',
'es6-promise',
'jquery',
'zone.js',
'aspnet-prerendering'
]
},
output: {
path: path.join(__dirname, 'wwwroot', 'dist'),
filename: '[name].js',
library: '[name]_[hash]',
},
plugins: [
//extractCSS,
new ExtractTextPlugin({
filename: "vendor.css",
allChunks: true
}),
new webpack.ProvidePlugin({ $: 'jquery', jQuery: 'jquery' }), // Maps these identifiers to the jQuery package (because Bootstrap expects it to be a global variable)
new webpack.optimize.OccurrenceOrderPlugin(),
new webpack.ContextReplacementPlugin(/\@angular\b.*\b(bundles|linker)/, path.join(__dirname, './Client')), // Workaround for https://github.com/angular/angular/issues/11580
new webpack.DllPlugin({
path: path.join(__dirname, 'wwwroot', 'dist', '[name]-manifest.json'),
name: '[name]_[hash]'
})
].concat(isDevBuild ? [] : [
new webpack.optimize.UglifyJsPlugin({ compress: { warnings: false } })
])
};
webpack.config.js
var isDevBuild = process.argv.indexOf('--env.prod') < 0;
var path = require('path');
var webpack = require('webpack');
var nodeExternals = require('webpack-node-externals');
var merge = require('webpack-merge');
var allFilenamesExceptJavaScript = /\.(?!js(\?|$))([^.]+(\?|$))/;
// Configuration in common to both client-side and server-side bundles
var sharedConfig = {
resolve: { extensions: [ '.js', '.ts' ] },
output: {
filename: '[name].js',
publicPath: '/dist/' // Webpack dev middleware, if enabled, handles requests for this URL prefix
},
module: {
loaders: [
{ // TypeScript files
test: /\.ts$/,
include: /ClientApp/,
exclude: [/\.(spec|e2e)\.ts$/], // Exclude test files | end2end test spec files etc
loaders: [
'awesome-typescript-loader?silent=true', // Amazing TS loader
'angular2-template-loader' // Handles templateUrl stylesUrl and automatically just inserts them into the template|styles
// instead of having the module resource loader handle it
]
},
{ test: /\.html$/, loader: 'raw-loader' },
{ test: /\.css$/, loader: 'raw-loader' },
{ test: /\.(png|jpg|jpeg|gif|svg)$/, loader: 'url-loader', query: { limit: 25000 } }
]
}
};
// Configuration for client-side bundle suitable for running in browsers
var clientBundleConfig = merge(sharedConfig, {
entry: { 'main-client': './ClientApp/boot-client.ts' },
output: { path: path.join(__dirname, './wwwroot/dist') },
devtool: isDevBuild ? 'inline-source-map' : null,
plugins: [
new webpack.DllReferencePlugin({
context: __dirname,
manifest: require('./wwwroot/dist/vendor-manifest.json')
})
].concat(isDevBuild ? [] : [
// Plugins that apply in production builds only
new webpack.optimize.OccurenceOrderPlugin(),
new webpack.optimize.UglifyJsPlugin()
])
});
// Configuration for server-side (prerendering) bundle suitable for running in Node
var serverBundleConfig = merge(sharedConfig, {
entry: { 'main-server': './ClientApp/boot-server.ts' },
output: {
libraryTarget: 'commonjs',
path: path.join(__dirname, './ClientApp/dist')
},
target: 'node',
devtool: 'inline-source-map',
externals: [nodeExternals({ whitelist: [allFilenamesExceptJavaScript] })] // Don't bundle .js files from node_modules
});
module.exports = [clientBundleConfig, serverBundleConfig];
boot-server.ts
import 'angular2-universal-polyfills';
import 'zone.js';
import './__2.1.1.workaround.ts'; // temporary until 2.1.1 things are patched in Core
import { enableProdMode } from '@angular/core';
import { platformNodeDynamic } from 'angular2-universal';
import { AppModule } from './app/app.module';
enableProdMode();
const platform = platformNodeDynamic();
import { createServerRenderer, RenderResult } from 'aspnet-prerendering';
export default createServerRenderer(params => {
const doc = '<app></app>';
return new Promise((resolve, reject) => {
const requestZone = Zone.current.fork({
name: 'angular-universal request',
properties: {
baseUrl: '/',
ngModule: AppModule,
requestUrl: params.url,
originUrl: params.origin,
preboot: false,
// TODO: Render just the <app> component instead of wrapping it inside an extra HTML document
// Waiting on https://github.com/angular/universal/issues/347
document: '<!DOCTYPE html><html><head></head><body><app></app></body></html>'
},
onHandleError: (parentZone, currentZone, targetZone, error) => {
// If any error occurs while rendering the module, reject the whole operation
reject(error);
return true;
}
});
return requestZone.run<Promise<string>>(() => platform.serializeModule(AppModule)).then(html => {
resolve({ html: html });
}, reject);
});
});
Could you guys please help me to make it work again? Everything except this feature is missing after the upgrade.


Activity
MarkPieszak commentedon Mar 1, 2017
I believe there's something wrong with the Templates, can you install the template with the generator instead?
npm i -g generator-aspnetcore-spayo aspnetcore-spaJohnGalt1717 commentedon Mar 2, 2017
I have the same problem from the generator.
ttcg commentedon Mar 2, 2017
Thanks @MarkPieszak . You are right. I am using very very old template version in VS2015 Template Pack which is with angular 2.0.0.
I didn't know that I can get the latest template in this way. Whenever I create a new project, I use VS2015 >> New Project >> Angular 2 Template SPA >> Create procedures.
I downloaded the latest template as instructed, created a new project, compared the files and finally, HMR is working now.
I just need to copy the following block in boot-client.js and all sorted.
ttcg commentedon Mar 2, 2017
@MarkPieszak May I ask some questions regarding with this Template?
As a beginner to ng2, I used this template to start my ng2 journey. I didn't know that latest version of template is out and how to get it. There will be many newbies like me who wants to learn ng2 and thought that it's the best template to use and learn.
May I know where that file is referenced? I couldn't find it anywhere in the code. In the old template, we didn't have that server/vendor.js file. It used to be generated only in wwwroot.
Thanks for your help.
MarkPieszak commentedon Mar 3, 2017
I'm not sure exactly but I believe to update those it's not as easy as win a generator. @SteveSandersonMS does all the publishing he could help give a better answer about the Pack templates.
They come from webpack.config.vendor.js file, there's 2 bundle configurations there as well.
SteveSandersonMS commentedon Mar 7, 2017
Pretty much, yes. We are likely to deprecate and remove that template soon, in favour of shipping via
dotnet new. I'd strongly recommend using thedotnet new(or Yeoman) templates instead, as described at https://blogs.msdn.microsoft.com/webdev/2017/02/14/building-single-page-applications-on-asp-net-core-with-javascriptservices/