RobertDyball / A2SPA

SPA with ASP.NetCore 2 + Angular 4 + Bootstrap 4+ OpenIdDict
https://www.codeproject.com/Articles/1148767/SPA-using-ASP-Net-Core-plus-Angular-part
91 stars 43 forks source link

Not displaying component html plus Unhandled Promise rejection: Unexpected token #7

Closed Xoadra closed 6 years ago

Xoadra commented 6 years ago

I'm working with a cli-generated project for both the ASP.NET Core and Angular parts using Visual Studio Code, so in essence I'm retracing the steps you originally took in your part 1 tutorial but within VSCode instead and with the current versions of ASP.NET Core (2.0.0) and Angular (5.2.2). However, I've consistently ran into the same issue even after trying and testing with older versions to retrace the steps you took in your tutorial.

While I've been successfully able to display ASP.NET Core pages from both the root route (prior to overriding it) and /home/index and the Angular index.html page from the root route (after overriding ASP.NET Core) and /index.html, I cannot get the AppComponent template to display as you do in your tutorial, only the loader text still.

My errors have been pretty consistent despite making a variety of edits to try and diagnose the issue, but my primary error is Unhandled Promise rejection: Unexpected token <. In full, I get:

Unhandled Promise rejection: Unexpected token <                                     zone.js:672 
  Evaluating http://localhost:5000/wwwroot/app
  Loading app ; Zone: <root> ; Task: Promise.then ; Value: Error: Unexpected token <
  Evaluating http://localhost:5000/wwwroot/app
  Loading app
    at eval (<anonymous>)
    at evaluate (evaluate.js:106)
    at instantiate.js:394
    at dynamicExecute (register-loader.js:665)
    at doEvaluate (register-loader.js:612)
    at ensureEvaluate (register-loader.js:520)
    at register-loader.js:133
    at ZoneDelegate.invoke (zone.js:388)
    at Zone.run (zone.js:138)
    at zone.js:858 SyntaxError: Unexpected token <
    at eval (<anonymous>)
    at evaluate (http://localhost:5000/node_modules/systemjs/dist/system.src.js:2818:16)
    at http://localhost:5000/node_modules/systemjs/dist/system.src.js:3621:21
    at dynamicExecute (http://localhost:5000/node_modules/systemjs/dist/system.src.js:1142:26)
    at doEvaluate (http://localhost:5000/node_modules/systemjs/dist/system.src.js:1089:13)
    at ensureEvaluate (http://localhost:5000/node_modules/systemjs/dist/system.src.js:997:13)
    at http://localhost:5000/node_modules/systemjs/dist/system.src.js:610:14
    at ZoneDelegate.invoke (http://localhost:5000/node_modules/zone.js/dist/zone.js:388:26)
    at Zone.run (http://localhost:5000/node_modules/zone.js/dist/zone.js:138:43)
    at http://localhost:5000/node_modules/zone.js/dist/zone.js:858:57

Now, I am aware that ultimately you end up resorting to using ASP.NET Core templates instead for the SPA behavior and Angular integration, but I'm concerned that it may still be important to get this kind of project to work down the line, especially considering that you're still using those SystemJS files despite no longer having an index.html file.

For reference, here are some of the relevent files in my project:

Program.cs:

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;

namespace NgCore3
{
    public class Program
    {
        public static void Main(string[] args)
        {
            BuildWebHost(args).Run();
        }

        public static IWebHost BuildWebHost(string[] args) =>
            WebHost.CreateDefaultBuilder(args)
                .UseStartup<Startup>()
                .Build();
    }
}

Startup.cs:

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.FileProviders;

namespace NgCore3
{
  public class Startup
  {
      public Startup(IConfiguration configuration)
      {
          Configuration = configuration;
      }

      public IConfiguration Configuration { get; }

      // This method gets called by the runtime. Use this method to add services to the container.
      public void ConfigureServices(IServiceCollection services)
      {
          services.AddMvc();
      }

      // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
      public void Configure(IApplicationBuilder app, IHostingEnvironment env)
      {
          if (env.IsDevelopment())
          {
              app.UseDeveloperExceptionPage();
          }
          else
          {
              app.UseExceptionHandler("/Home/Error");
          }

          app.UseDefaultFiles();
            app.UseStaticFiles();
            app.UseStaticFiles(new StaticFileOptions
            {
                FileProvider = new PhysicalFileProvider(Path.Combine(env.ContentRootPath, "node_modules")),
                RequestPath = "/node_modules"
            });

          app.UseMvc(routes =>
          {
              routes.MapRoute(
                  name: "default",
                  template: "{controller=Home}/{action=Index}/{id?}");
              routes.MapSpaFallbackRoute("spa-fallback", new { controller = "home", action = "index" });
          });
      }
  }
}

index.html:

<!doctype html>

<html lang="en">

  <head>
      <meta charset="utf-8">
      <title>NgCore3</title>
      <!-- <base href="/"> -->

      <meta name="viewport" content="width=device-width, initial-scale=1">
      <link rel="icon" type="image/x-icon" href="favicon.ico">

      <script src="node_modules/core-js/client/shim.min.js"></script>
      <script src="node_modules/zone.js/dist/zone.js"></script>
      <script src="node_modules/systemjs/dist/system.src.js"></script>
      <script src="systemjs.config.js"></script>

      <script>
          SystemJS.import( 'app' )
              //.catch( function ( err ) { console.error( err ) } )
              //.then( function ( m ) { console.log( m ) } )
      </script>
  </head>

  <body>
      <app-root> Loading AppComponent content here... </app-root>
  </body>

</html>

systemjs.config.js:

//import { System } from 'systemjs'
//var SystemJS = require( 'systemjs' )

( function ( global ) {
  SystemJS.config( {
      //baseURL: '/',
      //transpiler: 'typescript',
      paths: {
          'root:': 'wwwroot/',
          'npm:': 'node_modules/'
      },
      map: {
          'app': 'root:app',
          '@angular/core': 'npm:@angular/core/',
          '@angular/common': 'npm:@angular/common/',
          '@angular/animations': 'npm:@angular/animations/',
          '@angular/animations/browser': 'npm:@angular/animations/',
          '@angular/platform-browser/animations': 'npm:@angular/platform-browser/',
          '@angular/compiler': 'npm:@angular/compiler/',
          '@angular/platform-browser': 'npm:@angular/platform-browser/',
          '@angular/platform-browser-dynamic': 'npm:@angular/platform-browser-dynamic/',
          '@angular/common/http': 'npm:@angular/common/http/',
          '@angular/http': 'npm:@angular/http/',
          '@angular/router': 'npm:@angular/router/',
          '@angular/forms': 'npm:@angular/forms/',
      },
      packages: {
          app: {
              defaultExtension: 'ts',
              //meta: { './*.js': { loader: 'systemjs-angular-loader.js' } }
          },
          rxjs: {
              defaultExtension: 'js'
          }
      }
  } )
} )( this )

*.csproj:

<Project Sdk="Microsoft.NET.Sdk.Web">
  <PropertyGroup>
    <TargetFramework>netcoreapp2.0</TargetFramework>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.0" />
    <PackageReference Include="Microsoft.AspNetCore.SpaServices" Version="2.0.2" />
    <PackageReference Include="Microsoft.DotNet.Watcher.Tools" Version="2.0.0" />
  </ItemGroup>
  <ItemGroup>
    <DotNetCliToolReference Include="Microsoft.DotNet.Watcher.Tools" Version="2.0.0" />
    <DotNetCliToolReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Tools" Version="2.0.0" />
  </ItemGroup>
</Project>

package.json:

{
  "name": "ng-core3",
  "version": "0.0.0",
  "license": "MIT",
  "scripts": {
    "ng": "ng",
    "start": "ng serve --port 5000",
    "build": "ng build --prod",
    "test": "ng test",
    "lint": "ng lint",
    "e2e": "ng e2e"
  },
  "private": true,
  "dependencies": {
    "@angular/animations": "^5.2.0",
    "@angular/common": "^5.2.0",
    "@angular/compiler": "^5.2.0",
    "@angular/core": "^5.2.0",
    "@angular/forms": "^5.2.0",
    "@angular/http": "^5.2.0",
    "@angular/platform-browser": "^5.2.0",
    "@angular/platform-browser-dynamic": "^5.2.0",
    "@angular/router": "^5.2.0",
    "core-js": "^2.4.1",
    "rxjs": "^5.5.6",
    "systemjs": "^0.20.19",
    "zone.js": "^0.8.19"
  },
  "devDependencies": {
    "@angular/cli": "1.6.6",
    "@angular/compiler-cli": "^5.2.0",
    "@angular/language-service": "^5.2.0",
    "@types/jasmine": "~2.8.3",
    "@types/jasminewd2": "~2.0.2",
    "@types/node": "^6.0.96",
    "codelyzer": "^4.0.1",
    "jasmine-core": "~2.8.0",
    "jasmine-spec-reporter": "~4.2.1",
    "karma": "~2.0.0",
    "karma-chrome-launcher": "~2.2.0",
    "karma-coverage-istanbul-reporter": "^1.2.1",
    "karma-jasmine": "~1.1.0",
    "karma-jasmine-html-reporter": "^0.2.2",
    "protractor": "^5.3.0",
    "ts-node": "~4.1.0",
    "tslint": "~5.9.1",
    "typescript": "^2.6.2"
  }
}

tsconfig.json:

{
  "compileOnSave": false,
  "compilerOptions": {
  "declaration": false,
  "diagnostics": true,
    "emitDecoratorMetadata": true,
  "experimentalDecorators": true,
  "module": "commonjs",
  "moduleResolution": "node",
  "outDir": "./wwwroot",
  "removeComments": false,
  "rootDir": "wwwroot",
  "sourceMap": true,
  "suppressImplicitAnyIndexErrors": true,
    "target": "es5",
    "typeRoots": [
      "node_modules/@types"
    ],
    "lib": [
      "es2017",
      "dom"
    ]
  },
  "exclude": [
    "node_modules"
  ]
}

Hopefully that includes everything you might need from me. Let me know if there's anything else you need to take a look at.

RobertDyball commented 6 years ago

Hi Ian, sorry didn't get to your issue earlier; would I be correct in assuming you are using ng to serve up your site from "ng serve --port 5000" below ... hence the line in error saying: Evaluating http://localhost:5000/wwwroot/app

this project instead needs to be served through Kestrel or IIS/PWS. I'm making use of the ASP.Net Core templates with some modifications to serve the angular SPA. I have kept many of the page names, just for familiarity.

index.html is a hangover from the original ng code, the work it does in a flat-file based traditional setup gets split between index.cshtml, app.cshtml and_layout.cshtml- this allows server side code to be executed and served up to the client.

Have a look in the branch Angular5 https://github.com/RobertDyball/A2SPA/tree/Angular5 as this is using Angular 5.2.x and .Net core 2.x

or a more recent version (a bit rough) where I'm switching to ngx-bootstrap, the branch is here: https://github.com/RobertDyball/A2SPA/tree/ngx-bootstrap

If I have this wrong, please PM me a zipped up copy of your code, you can reach me at robert.dyball at gmail dot com

Xoadra commented 6 years ago

No problem!

I'm actually not, since running my dotnet server also uses that port so it wouldn't work. I did try serving it up from its default port at 4200 but unsurprisingly that didn't work either. Then again I don't know if that means of linking the two separate frameworks would be a wise or even workable solution when it comes time for production and deployment.

So I did notice you had settings in some projects whereby you had additional settings configured in your Program.cs and Startup.cs files. I've given those a shot as well but I was still unable to get the original AppComponent template app.component.html to appear. I will take a loot at some of the earlier commits in both of those branches to see if any of the solutions there resolve the issue I'm currently wrestling with.

I'll also send you a copy of my most up-to-date version so hopefully that helps!

RobertDyball commented 6 years ago

Hi Ian,

Got it working, the error you had originally was because the app component being fetched was actually a default HTML page, not being a partial component, but tags etc.

Next looked at how the code was set up (and forgetting you’d simply started at part 1) I replaced out the index.html (as a default it stops index.cshtml getting a look in), then moved the contents of index.cshtml, the partial shared layout file _Layout.cshtml and realized there was no view controller there yet to serve up server side .cshtml as partials. (probably me skipping to part 2or 4 or something ..again sorry much of my dev time = commute time = little or not internet access) perils of mountains, tunnels and lazy telcos.).

Anyway added a partial controller, moved the mvc views that would become angular templates (partial views) into a partial directory to get served up by the partial controller.

Edited the angular component (added a couple of extra ones) to point to the partial mvc views and not flat html as it was.

Had to alter systemconfig.js to pick up the umd bundles, along the way disabled environment.ts (sorry for you to fix again now 😊 ), and added some missing scripts to the script block in _Layout.cshtml

Lastly moved the asp.netcore tag helper version of the bootstrap nav/menu to app.component.cshtml, and added angular routing in .

Now index.cshtml loads app component, and the router tag there is where angular then loads the partials.

When I get home I’ll zip up the source and get back to you.

Xoadra commented 6 years ago

My original issue was ultimately resolved so I suppose there's no reason to keep this up anymore. Thanks for your help!