Skip to content
This repository was archived by the owner on Apr 8, 2020. It is now read-only.

HMR no longer working when upgraded to latest version #725

Closed
ttcg opened this issue Mar 1, 2017 · 6 comments
Closed

HMR no longer working when upgraded to latest version #725

ttcg opened this issue Mar 1, 2017 · 6 comments

Comments

@ttcg
Copy link

ttcg commented Mar 1, 2017

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.

Image1

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.

Image2

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.

@MarkPieszak
Copy link
Contributor

I believe there's something wrong with the Templates, can you install the template with the generator instead?

npm i -g generator-aspnetcore-spa

yo aspnetcore-spa

@JohnGalt1717
Copy link

I have the same problem from the generator.

@ttcg
Copy link
Author

ttcg commented 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.

// Enable either Hot Module Reloading or production mode
if (module['hot']) {
    module['hot'].accept();
    module['hot'].dispose(() => {
        // Before restarting the app, we create a new root element and dispose the old one
        const oldRootElem = document.querySelector(rootElemTagName);
        const newRootElem = document.createElement(rootElemTagName);
        oldRootElem.parentNode.insertBefore(newRootElem, oldRootElem);
        platform.destroy();
    });
} else {
    enableProdMode();
}

@ttcg ttcg closed this as completed Mar 2, 2017
@ttcg
Copy link
Author

ttcg commented Mar 2, 2017

@MarkPieszak May I ask some questions regarding with this Template?

  1. Does it mean that ASPNetCoreTemplatePack in VisualStudioMarketPlace is always out-of-date? Is it not going to be upgraded when a new template version is out?

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.

  1. In the new template, webpack.config.vendor.js file contains 2 configs for both Server and Client as in webpack.config.js. vendor.js is generated as 'ClientApp/dist/vendor.js' by Server Config

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
Copy link
Contributor

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
Copy link
Member

Does it mean that ASPNetCoreTemplatePack in VisualStudioMarketPlace is always out-of-date

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 the dotnet 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/

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants