Replace Angular, React, ReactRedux templates with new CLI based ones
This commit is contained in:
parent
726da0f11f
commit
1d9585b69d
|
|
@ -6,16 +6,23 @@
|
|||
<TypeScriptCompileBlocked>true</TypeScriptCompileBlocked>
|
||||
<TypeScriptToolsVersion>Latest</TypeScriptToolsVersion>
|
||||
<IsPackable>false</IsPackable>
|
||||
<SpaRoot>ClientApp\</SpaRoot>
|
||||
<DefaultItemExcludes>$(DefaultItemExcludes);$(SpaRoot)node_modules\**</DefaultItemExcludes>
|
||||
|
||||
<!-- Set this to true if you enable server-side prerendering -->
|
||||
<BuildServerSideRenderer>false</BuildServerSideRenderer>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup Condition="'$(TargetFrameworkOverride)' == ''">
|
||||
<PackageReference Include="Microsoft.AspNetCore.All" Version="${MicrosoftAspNetCoreAllPackageVersion}" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.SpaServices.Extensions" Version="${MicrosoftAspNetCoreSpaServicesExtensionsPackageVersion}" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Condition="'$(TargetFrameworkOverride)' != ''">
|
||||
<PackageReference Include="Microsoft.AspNetCore" Version="${MicrosoftAspNetCorePackageVersion}" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.HttpsPolicy" Version="${MicrosoftAspNetCoreHttpsPolicyPackageVersion}" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="${MicrosoftAspNetCoreMvcPackageVersion}" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.SpaServices" Version="${MicrosoftAspNetCoreSpaServicesPackageVersion}" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.SpaServices.Extensions" Version="${MicrosoftAspNetCoreSpaServicesExtensionsPackageVersion}" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.StaticFiles" Version="${MicrosoftAspNetCoreStaticFilesPackageVersion}" />
|
||||
</ItemGroup>
|
||||
|
||||
|
|
@ -24,35 +31,32 @@
|
|||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<!-- Files not to publish (note that the 'dist' subfolders are re-added below) -->
|
||||
<Content Remove="ClientApp\**" />
|
||||
<!-- Don't publish the SPA source files, but do show them in the project files list -->
|
||||
<Content Remove="$(SpaRoot)**" />
|
||||
<None Include="$(SpaRoot)**" Exclude="$(SpaRoot)node_modules\**" />
|
||||
</ItemGroup>
|
||||
|
||||
<!--/-:cnd:noEmit -->
|
||||
<Target Name="DebugRunWebpack" BeforeTargets="Build" Condition=" '$(Configuration)' == 'Debug' And !Exists('wwwroot\dist') ">
|
||||
<Target Name="DebugEnsureNodeEnv" BeforeTargets="Build" Condition=" '$(Configuration)' == 'Debug' And !Exists('$(SpaRoot)node_modules') ">
|
||||
<!-- Ensure Node.js is installed -->
|
||||
<Exec Command="node --version" ContinueOnError="true">
|
||||
<Output TaskParameter="ExitCode" PropertyName="ErrorCode" />
|
||||
</Exec>
|
||||
<Error Condition="'$(ErrorCode)' != '0'" Text="Node.js is required to build and run this project. To continue, please install Node.js from https://nodejs.org/, and then restart your command prompt or IDE." />
|
||||
|
||||
<!-- In development, the dist files won't exist on the first run or when cloning to
|
||||
a different machine, so rebuild them if not already present. -->
|
||||
<Message Importance="high" Text="Performing first-run Webpack build..." />
|
||||
<Exec Command="node node_modules/webpack/bin/webpack.js --config webpack.config.vendor.js" />
|
||||
<Exec Command="node node_modules/webpack/bin/webpack.js" />
|
||||
<Message Importance="high" Text="Restoring dependencies using 'npm'. This may take several minutes..." />
|
||||
<Exec WorkingDirectory="$(SpaRoot)" Command="npm install" />
|
||||
</Target>
|
||||
<!--/+:cnd:noEmit -->
|
||||
|
||||
<Target Name="PublishRunWebpack" AfterTargets="ComputeFilesToPublish">
|
||||
<!-- As part of publishing, ensure the JS resources are freshly built in production mode -->
|
||||
<Exec Command="npm install" />
|
||||
<Exec Command="node node_modules/webpack/bin/webpack.js --config webpack.config.vendor.js --env.prod" />
|
||||
<Exec Command="node node_modules/webpack/bin/webpack.js --env.prod" />
|
||||
<Exec WorkingDirectory="$(SpaRoot)" Command="npm install" />
|
||||
<Exec WorkingDirectory="$(SpaRoot)" Command="npm run build -- --prod" />
|
||||
<Exec WorkingDirectory="$(SpaRoot)" Command="npm run build:ssr -- --prod" Condition=" '$(BuildServerSideRenderer)' == 'true' " />
|
||||
|
||||
<!-- Include the newly-built files in the publish output -->
|
||||
<ItemGroup>
|
||||
<DistFiles Include="wwwroot\dist\**; ClientApp\dist\**" />
|
||||
<DistFiles Include="wwwroot\dist\**; $(SpaRoot)dist-server\**" />
|
||||
<ResolvedFileToPublish Include="@(DistFiles->'%(FullPath)')" Exclude="@(ResolvedFileToPublish)">
|
||||
<RelativePath>%(DistFiles.Identity)</RelativePath>
|
||||
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
MicrosoftAspNetCoreHttpsPolicyPackageVersion=$(MicrosoftAspNetCoreHttpsPolicyPackageVersion);
|
||||
MicrosoftAspNetCoreMvcPackageVersion=$(MicrosoftAspNetCoreMvcPackageVersion);
|
||||
MicrosoftAspNetCoreSpaServicesPackageVersion=$(MicrosoftAspNetCoreSpaServicesPackageVersion);
|
||||
MicrosoftAspNetCoreSpaServicesExtensionsPackageVersion=$(MicrosoftAspNetCoreSpaServicesExtensionsPackageVersion);
|
||||
MicrosoftAspNetCoreStaticFilesPackageVersion=$(MicrosoftAspNetCoreStaticFilesPackageVersion);
|
||||
MicrosoftVisualStudioWebCodeGenerationToolsPackageVersion=$(MicrosoftVisualStudioWebCodeGenerationToolsPackageVersion);
|
||||
</GeneratedContentProperties>
|
||||
|
|
|
|||
|
|
@ -6,16 +6,20 @@
|
|||
<TypeScriptCompileBlocked>true</TypeScriptCompileBlocked>
|
||||
<TypeScriptToolsVersion>Latest</TypeScriptToolsVersion>
|
||||
<IsPackable>false</IsPackable>
|
||||
<SpaRoot>ClientApp\</SpaRoot>
|
||||
<DefaultItemExcludes>$(DefaultItemExcludes);$(SpaRoot)node_modules\**</DefaultItemExcludes>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup Condition="'$(TargetFrameworkOverride)' == ''">
|
||||
<PackageReference Include="Microsoft.AspNetCore.All" Version="${MicrosoftAspNetCoreAllPackageVersion}" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.SpaServices.Extensions" Version="${MicrosoftAspNetCoreSpaServicesExtensionsPackageVersion}" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Condition="'$(TargetFrameworkOverride)' != ''">
|
||||
<PackageReference Include="Microsoft.AspNetCore" Version="${MicrosoftAspNetCorePackageVersion}" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.HttpsPolicy" Version="${MicrosoftAspNetCoreHttpsPolicyPackageVersion}" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="${MicrosoftAspNetCoreMvcPackageVersion}" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.SpaServices" Version="${MicrosoftAspNetCoreSpaServicesPackageVersion}" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.SpaServices.Extensions" Version="${MicrosoftAspNetCoreSpaServicesExtensionsPackageVersion}" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.StaticFiles" Version="${MicrosoftAspNetCoreStaticFilesPackageVersion}" />
|
||||
</ItemGroup>
|
||||
|
||||
|
|
@ -24,35 +28,31 @@
|
|||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<!-- Files not to publish (note that the 'dist' subfolders are re-added below) -->
|
||||
<Content Remove="ClientApp\**" />
|
||||
<!-- Don't publish the SPA source files, but do show them in the project files list -->
|
||||
<Content Remove="$(SpaRoot)**" />
|
||||
<None Include="$(SpaRoot)**" Exclude="$(SpaRoot)node_modules\**" />
|
||||
</ItemGroup>
|
||||
|
||||
<!--/-:cnd:noEmit -->
|
||||
<Target Name="DebugRunWebpack" BeforeTargets="Build" Condition=" '$(Configuration)' == 'Debug' And !Exists('wwwroot\dist') ">
|
||||
<Target Name="DebugEnsureNodeEnv" BeforeTargets="Build" Condition=" '$(Configuration)' == 'Debug' And !Exists('$(SpaRoot)node_modules') ">
|
||||
<!-- Ensure Node.js is installed -->
|
||||
<Exec Command="node --version" ContinueOnError="true">
|
||||
<Output TaskParameter="ExitCode" PropertyName="ErrorCode" />
|
||||
</Exec>
|
||||
<Error Condition="'$(ErrorCode)' != '0'" Text="Node.js is required to build and run this project. To continue, please install Node.js from https://nodejs.org/, and then restart your command prompt or IDE." />
|
||||
|
||||
<!-- In development, the dist files won't exist on the first run or when cloning to
|
||||
a different machine, so rebuild them if not already present. -->
|
||||
<Message Importance="high" Text="Performing first-run Webpack build..." />
|
||||
<Exec Command="node node_modules/webpack/bin/webpack.js --config webpack.config.vendor.js" />
|
||||
<Exec Command="node node_modules/webpack/bin/webpack.js" />
|
||||
<Message Importance="high" Text="Restoring dependencies using 'npm'. This may take several minutes..." />
|
||||
<Exec WorkingDirectory="$(SpaRoot)" Command="npm install" />
|
||||
</Target>
|
||||
<!--/+:cnd:noEmit -->
|
||||
|
||||
<Target Name="PublishRunWebpack" AfterTargets="ComputeFilesToPublish">
|
||||
<!-- As part of publishing, ensure the JS resources are freshly built in production mode -->
|
||||
<Exec Command="npm install" />
|
||||
<Exec Command="node node_modules/webpack/bin/webpack.js --config webpack.config.vendor.js --env.prod" />
|
||||
<Exec Command="node node_modules/webpack/bin/webpack.js --env.prod" />
|
||||
<Exec WorkingDirectory="$(SpaRoot)" Command="npm install" />
|
||||
<Exec WorkingDirectory="$(SpaRoot)" Command="npm run build" />
|
||||
|
||||
<!-- Include the newly-built files in the publish output -->
|
||||
<ItemGroup>
|
||||
<DistFiles Include="wwwroot\dist\**; ClientApp\dist\**" />
|
||||
<DistFiles Include="$(SpaRoot)build\**" />
|
||||
<ResolvedFileToPublish Include="@(DistFiles->'%(FullPath)')" Exclude="@(ResolvedFileToPublish)">
|
||||
<RelativePath>%(DistFiles.Identity)</RelativePath>
|
||||
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
|
||||
|
|
|
|||
|
|
@ -6,16 +6,23 @@
|
|||
<TypeScriptCompileBlocked>true</TypeScriptCompileBlocked>
|
||||
<TypeScriptToolsVersion>Latest</TypeScriptToolsVersion>
|
||||
<IsPackable>false</IsPackable>
|
||||
<SpaRoot>ClientApp\</SpaRoot>
|
||||
<DefaultItemExcludes>$(DefaultItemExcludes);$(SpaRoot)node_modules\**</DefaultItemExcludes>
|
||||
|
||||
<!-- Set this to true if you enable server-side prerendering -->
|
||||
<BuildServerSideRenderer>false</BuildServerSideRenderer>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup Condition="'$(TargetFrameworkOverride)' == ''">
|
||||
<PackageReference Include="Microsoft.AspNetCore.All" Version="${MicrosoftAspNetCoreAllPackageVersion}" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.SpaServices.Extensions" Version="${MicrosoftAspNetCoreSpaServicesExtensionsPackageVersion}" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Condition="'$(TargetFrameworkOverride)' != ''">
|
||||
<PackageReference Include="Microsoft.AspNetCore" Version="${MicrosoftAspNetCorePackageVersion}" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.HttpsPolicy" Version="${MicrosoftAspNetCoreHttpsPolicyPackageVersion}" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="${MicrosoftAspNetCoreMvcPackageVersion}" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.SpaServices" Version="${MicrosoftAspNetCoreSpaServicesPackageVersion}" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.SpaServices.Extensions" Version="${MicrosoftAspNetCoreSpaServicesExtensionsPackageVersion}" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.StaticFiles" Version="${MicrosoftAspNetCoreStaticFilesPackageVersion}" />
|
||||
</ItemGroup>
|
||||
|
||||
|
|
@ -24,35 +31,32 @@
|
|||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<!-- Files not to publish (note that the 'dist' subfolders are re-added below) -->
|
||||
<Content Remove="ClientApp\**" />
|
||||
<!-- Don't publish the SPA source files, but do show them in the project files list -->
|
||||
<Content Remove="$(SpaRoot)**" />
|
||||
<None Include="$(SpaRoot)**" Exclude="$(SpaRoot)node_modules\**" />
|
||||
</ItemGroup>
|
||||
|
||||
<!--/-:cnd:noEmit -->
|
||||
<Target Name="DebugRunWebpack" BeforeTargets="Build" Condition=" '$(Configuration)' == 'Debug' And !Exists('wwwroot\dist') ">
|
||||
<Target Name="DebugEnsureNodeEnv" BeforeTargets="Build" Condition=" '$(Configuration)' == 'Debug' And !Exists('$(SpaRoot)node_modules') ">
|
||||
<!-- Ensure Node.js is installed -->
|
||||
<Exec Command="node --version" ContinueOnError="true">
|
||||
<Output TaskParameter="ExitCode" PropertyName="ErrorCode" />
|
||||
</Exec>
|
||||
<Error Condition="'$(ErrorCode)' != '0'" Text="Node.js is required to build and run this project. To continue, please install Node.js from https://nodejs.org/, and then restart your command prompt or IDE." />
|
||||
|
||||
<!-- In development, the dist files won't exist on the first run or when cloning to
|
||||
a different machine, so rebuild them if not already present. -->
|
||||
<Message Importance="high" Text="Performing first-run Webpack build..." />
|
||||
<Exec Command="node node_modules/webpack/bin/webpack.js --config webpack.config.vendor.js" />
|
||||
<Exec Command="node node_modules/webpack/bin/webpack.js" />
|
||||
<Message Importance="high" Text="Restoring dependencies using 'npm'. This may take several minutes..." />
|
||||
<Exec WorkingDirectory="$(SpaRoot)" Command="npm install" />
|
||||
</Target>
|
||||
<!--/+:cnd:noEmit -->
|
||||
|
||||
<Target Name="PublishRunWebpack" AfterTargets="ComputeFilesToPublish">
|
||||
<!-- As part of publishing, ensure the JS resources are freshly built in production mode -->
|
||||
<Exec Command="npm install" />
|
||||
<Exec Command="node node_modules/webpack/bin/webpack.js --config webpack.config.vendor.js --env.prod" />
|
||||
<Exec Command="node node_modules/webpack/bin/webpack.js --env.prod" />
|
||||
<Exec WorkingDirectory="$(SpaRoot)" Command="npm install" />
|
||||
<Exec WorkingDirectory="$(SpaRoot)" Command="npm run build" />
|
||||
<Exec WorkingDirectory="$(SpaRoot)" Command="npm run build:ssr" Condition=" '$(BuildServerSideRenderer)' == 'true' " />
|
||||
|
||||
<!-- Include the newly-built files in the publish output -->
|
||||
<ItemGroup>
|
||||
<DistFiles Include="wwwroot\dist\**; ClientApp\dist\**" />
|
||||
<DistFiles Include="$(SpaRoot)build\**; $(SpaRoot)build-ssr\**" />
|
||||
<ResolvedFileToPublish Include="@(DistFiles->'%(FullPath)')" Exclude="@(ResolvedFileToPublish)">
|
||||
<RelativePath>%(DistFiles.Identity)</RelativePath>
|
||||
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,78 @@
|
|||
{
|
||||
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
|
||||
"project": {
|
||||
"name": "AngularSpa"
|
||||
},
|
||||
"apps": [
|
||||
{
|
||||
"root": "src",
|
||||
"outDir": "../wwwroot/dist",
|
||||
"assets": [
|
||||
"assets"
|
||||
],
|
||||
"index": "index.html",
|
||||
"main": "main.ts",
|
||||
"polyfills": "polyfills.ts",
|
||||
"test": "test.ts",
|
||||
"tsconfig": "tsconfig.app.json",
|
||||
"testTsconfig": "tsconfig.spec.json",
|
||||
"prefix": "app",
|
||||
"styles": [
|
||||
"styles.css",
|
||||
"../node_modules/bootstrap/dist/css/bootstrap.min.css"
|
||||
],
|
||||
"scripts": [],
|
||||
"environmentSource": "environments/environment.ts",
|
||||
"environments": {
|
||||
"dev": "environments/environment.ts",
|
||||
"prod": "environments/environment.prod.ts"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "ssr",
|
||||
"root": "src",
|
||||
"outDir": "dist-server",
|
||||
"assets": [
|
||||
"assets"
|
||||
],
|
||||
"main": "main.server.ts",
|
||||
"tsconfig": "tsconfig.app-ssr.json",
|
||||
"prefix": "app",
|
||||
"scripts": [],
|
||||
"environmentSource": "environments/environment.ts",
|
||||
"environments": {
|
||||
"dev": "environments/environment.ts",
|
||||
"prod": "environments/environment.prod.ts"
|
||||
},
|
||||
"platform": "server"
|
||||
}
|
||||
],
|
||||
"e2e": {
|
||||
"protractor": {
|
||||
"config": "./protractor.conf.js"
|
||||
}
|
||||
},
|
||||
"lint": [
|
||||
{
|
||||
"project": "src/tsconfig.app.json",
|
||||
"exclude": "**/node_modules/**"
|
||||
},
|
||||
{
|
||||
"project": "src/tsconfig.spec.json",
|
||||
"exclude": "**/node_modules/**"
|
||||
},
|
||||
{
|
||||
"project": "e2e/tsconfig.e2e.json",
|
||||
"exclude": "**/node_modules/**"
|
||||
}
|
||||
],
|
||||
"test": {
|
||||
"karma": {
|
||||
"config": "./karma.conf.js"
|
||||
}
|
||||
},
|
||||
"defaults": {
|
||||
"styleExt": "css",
|
||||
"component": {}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
# Editor configuration, see http://editorconfig.org
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[*.md]
|
||||
max_line_length = off
|
||||
trim_trailing_whitespace = false
|
||||
43
src/Microsoft.DotNet.Web.Spa.ProjectTemplates/content/Angular-CSharp/ClientApp/.gitignore
vendored
Normal file
43
src/Microsoft.DotNet.Web.Spa.ProjectTemplates/content/Angular-CSharp/ClientApp/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
# See http://help.github.com/ignore-files/ for more about ignoring files.
|
||||
|
||||
# compiled output
|
||||
/dist
|
||||
/dist-server
|
||||
/tmp
|
||||
/out-tsc
|
||||
|
||||
# dependencies
|
||||
/node_modules
|
||||
|
||||
# IDEs and editors
|
||||
/.idea
|
||||
.project
|
||||
.classpath
|
||||
.c9/
|
||||
*.launch
|
||||
.settings/
|
||||
*.sublime-workspace
|
||||
|
||||
# IDE - VSCode
|
||||
.vscode/*
|
||||
!.vscode/settings.json
|
||||
!.vscode/tasks.json
|
||||
!.vscode/launch.json
|
||||
!.vscode/extensions.json
|
||||
|
||||
# misc
|
||||
/.sass-cache
|
||||
/connect.lock
|
||||
/coverage
|
||||
/libpeerconnection.log
|
||||
npm-debug.log
|
||||
testem.log
|
||||
/typings
|
||||
|
||||
# e2e
|
||||
/e2e/*.js
|
||||
/e2e/*.map
|
||||
|
||||
# System Files
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
# AngularSpa
|
||||
|
||||
This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 1.5.0.
|
||||
|
||||
## Development server
|
||||
|
||||
Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files.
|
||||
|
||||
## Code scaffolding
|
||||
|
||||
Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`.
|
||||
|
||||
## Build
|
||||
|
||||
Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `-prod` flag for a production build.
|
||||
|
||||
## Running unit tests
|
||||
|
||||
Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io).
|
||||
|
||||
## Running end-to-end tests
|
||||
|
||||
Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/).
|
||||
|
||||
## Further help
|
||||
|
||||
To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md).
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
import { NgModule } from '@angular/core';
|
||||
import { BrowserModule } from '@angular/platform-browser';
|
||||
import { AppModuleShared } from './app.shared.module';
|
||||
import { AppComponent } from './components/app/app.component';
|
||||
|
||||
@NgModule({
|
||||
bootstrap: [ AppComponent ],
|
||||
imports: [
|
||||
BrowserModule,
|
||||
AppModuleShared
|
||||
],
|
||||
providers: [
|
||||
{ provide: 'BASE_URL', useFactory: getBaseUrl }
|
||||
]
|
||||
})
|
||||
export class AppModule {
|
||||
}
|
||||
|
||||
export function getBaseUrl() {
|
||||
return document.getElementsByTagName('base')[0].href;
|
||||
}
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
import { NgModule } from '@angular/core';
|
||||
import { ServerModule } from '@angular/platform-server';
|
||||
import { AppModuleShared } from './app.shared.module';
|
||||
import { AppComponent } from './components/app/app.component';
|
||||
|
||||
@NgModule({
|
||||
bootstrap: [ AppComponent ],
|
||||
imports: [
|
||||
ServerModule,
|
||||
AppModuleShared
|
||||
]
|
||||
})
|
||||
export class AppModule {
|
||||
}
|
||||
|
|
@ -1,35 +0,0 @@
|
|||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { HttpModule } from '@angular/http';
|
||||
import { RouterModule } from '@angular/router';
|
||||
|
||||
import { AppComponent } from './components/app/app.component';
|
||||
import { NavMenuComponent } from './components/navmenu/navmenu.component';
|
||||
import { HomeComponent } from './components/home/home.component';
|
||||
import { FetchDataComponent } from './components/fetchdata/fetchdata.component';
|
||||
import { CounterComponent } from './components/counter/counter.component';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
AppComponent,
|
||||
NavMenuComponent,
|
||||
CounterComponent,
|
||||
FetchDataComponent,
|
||||
HomeComponent
|
||||
],
|
||||
imports: [
|
||||
CommonModule,
|
||||
HttpModule,
|
||||
FormsModule,
|
||||
RouterModule.forRoot([
|
||||
{ path: '', redirectTo: 'home', pathMatch: 'full' },
|
||||
{ path: 'home', component: HomeComponent },
|
||||
{ path: 'counter', component: CounterComponent },
|
||||
{ path: 'fetch-data', component: FetchDataComponent },
|
||||
{ path: '**', redirectTo: 'home' }
|
||||
])
|
||||
]
|
||||
})
|
||||
export class AppModuleShared {
|
||||
}
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
<div class='container-fluid'>
|
||||
<div class='row'>
|
||||
<div class='col-sm-3'>
|
||||
<nav-menu></nav-menu>
|
||||
</div>
|
||||
<div class='col-sm-9 body-content'>
|
||||
<router-outlet></router-outlet>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app',
|
||||
templateUrl: './app.component.html',
|
||||
styleUrls: ['./app.component.css']
|
||||
})
|
||||
export class AppComponent {
|
||||
}
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
/// <reference path="../../../../node_modules/@types/jasmine/index.d.ts" />
|
||||
import { assert } from 'chai';
|
||||
import { CounterComponent } from './counter.component';
|
||||
import { TestBed, async, ComponentFixture } from '@angular/core/testing';
|
||||
|
||||
let fixture: ComponentFixture<CounterComponent>;
|
||||
|
||||
describe('Counter component', () => {
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({ declarations: [CounterComponent] });
|
||||
fixture = TestBed.createComponent(CounterComponent);
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should display a title', async(() => {
|
||||
const titleText = fixture.nativeElement.querySelector('h1').textContent;
|
||||
expect(titleText).toEqual('Counter');
|
||||
}));
|
||||
|
||||
it('should start with count 0, then increments by 1 when clicked', async(() => {
|
||||
const countElement = fixture.nativeElement.querySelector('strong');
|
||||
expect(countElement.textContent).toEqual('0');
|
||||
|
||||
const incrementButton = fixture.nativeElement.querySelector('button');
|
||||
incrementButton.click();
|
||||
fixture.detectChanges();
|
||||
expect(countElement.textContent).toEqual('1');
|
||||
}));
|
||||
});
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'counter',
|
||||
templateUrl: './counter.component.html'
|
||||
})
|
||||
export class CounterComponent {
|
||||
public currentCount = 0;
|
||||
|
||||
public incrementCounter() {
|
||||
this.currentCount++;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
<h1>Weather forecast</h1>
|
||||
|
||||
<p>This component demonstrates fetching data from the server.</p>
|
||||
|
||||
<p *ngIf="!forecasts"><em>Loading...</em></p>
|
||||
|
||||
<table class='table' *ngIf="forecasts">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Date</th>
|
||||
<th>Temp. (C)</th>
|
||||
<th>Temp. (F)</th>
|
||||
<th>Summary</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr *ngFor="let forecast of forecasts">
|
||||
<td>{{ forecast.dateFormatted }}</td>
|
||||
<td>{{ forecast.temperatureC }}</td>
|
||||
<td>{{ forecast.temperatureF }}</td>
|
||||
<td>{{ forecast.summary }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
|
@ -1,23 +0,0 @@
|
|||
import { Component, Inject } from '@angular/core';
|
||||
import { Http } from '@angular/http';
|
||||
|
||||
@Component({
|
||||
selector: 'fetchdata',
|
||||
templateUrl: './fetchdata.component.html'
|
||||
})
|
||||
export class FetchDataComponent {
|
||||
public forecasts: WeatherForecast[];
|
||||
|
||||
constructor(http: Http, @Inject('BASE_URL') baseUrl: string) {
|
||||
http.get(baseUrl + 'api/SampleData/WeatherForecasts').subscribe(result => {
|
||||
this.forecasts = result.json() as WeatherForecast[];
|
||||
}, error => console.error(error));
|
||||
}
|
||||
}
|
||||
|
||||
interface WeatherForecast {
|
||||
dateFormatted: string;
|
||||
temperatureC: number;
|
||||
temperatureF: number;
|
||||
summary: string;
|
||||
}
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
<h1>Hello, world!</h1>
|
||||
<p>Welcome to your new single-page application, built with:</p>
|
||||
<ul>
|
||||
<li><a href='https://get.asp.net/'>ASP.NET Core</a> and <a href='https://msdn.microsoft.com/en-us/library/67ef8sbd.aspx'>C#</a> for cross-platform server-side code</li>
|
||||
<li><a href='https://angular.io/'>Angular</a> and <a href='http://www.typescriptlang.org/'>TypeScript</a> for client-side code</li>
|
||||
<li><a href='https://webpack.github.io/'>Webpack</a> for building and bundling client-side resources</li>
|
||||
<li><a href='http://getbootstrap.com/'>Bootstrap</a> for layout and styling</li>
|
||||
</ul>
|
||||
<p>To help you get started, we've also set up:</p>
|
||||
<ul>
|
||||
<li><strong>Client-side navigation</strong>. For example, click <em>Counter</em> then <em>Back</em> to return here.</li>
|
||||
<li><strong>Server-side prerendering</strong>. For faster initial loading and improved SEO, your Angular app is prerendered on the server. The resulting HTML is then transferred to the browser where a client-side copy of the app takes over.</li>
|
||||
<li><strong>Webpack dev middleware</strong>. In development mode, there's no need to run the <code>webpack</code> build tool. Your client-side resources are dynamically built on demand. Updates are available as soon as you modify any file.</li>
|
||||
<li><strong>Hot module replacement</strong>. In development mode, you don't even need to reload the page after making most changes. Within seconds of saving changes to files, your Angular app will be rebuilt and a new instance injected into the page.</li>
|
||||
<li><strong>Efficient production builds</strong>. In production mode, development-time features are disabled, and the <code>webpack</code> build tool produces minified static CSS and JavaScript files.</li>
|
||||
</ul>
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'nav-menu',
|
||||
templateUrl: './navmenu.component.html',
|
||||
styleUrls: ['./navmenu.component.css']
|
||||
})
|
||||
export class NavMenuComponent {
|
||||
}
|
||||
|
|
@ -1,23 +0,0 @@
|
|||
import 'reflect-metadata';
|
||||
import 'zone.js';
|
||||
import 'bootstrap';
|
||||
import { enableProdMode } from '@angular/core';
|
||||
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
|
||||
import { AppModule } from './app/app.browser.module';
|
||||
|
||||
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('app');
|
||||
const newRootElem = document.createElement('app');
|
||||
oldRootElem!.parentNode!.insertBefore(newRootElem, oldRootElem);
|
||||
modulePromise.then(appModule => appModule.destroy());
|
||||
});
|
||||
} else {
|
||||
enableProdMode();
|
||||
}
|
||||
|
||||
// Note: @ng-tools/webpack looks for the following expression when performing production
|
||||
// builds. Don't change how this line looks, otherwise you may break tree-shaking.
|
||||
const modulePromise = platformBrowserDynamic().bootstrapModule(AppModule);
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
import { AppPage } from './app.po';
|
||||
|
||||
describe('App', () => {
|
||||
let page: AppPage;
|
||||
|
||||
beforeEach(() => {
|
||||
page = new AppPage();
|
||||
});
|
||||
|
||||
it('should display welcome message', () => {
|
||||
page.navigateTo();
|
||||
expect(page.getMainHeading()).toEqual('Hello, world!');
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
import { browser, by, element } from 'protractor';
|
||||
|
||||
export class AppPage {
|
||||
navigateTo() {
|
||||
return browser.get('/');
|
||||
}
|
||||
|
||||
getMainHeading() {
|
||||
return element(by.css('app-root h1')).getText();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"extends": "../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../out-tsc/e2e",
|
||||
"baseUrl": "./",
|
||||
"module": "commonjs",
|
||||
"target": "es5",
|
||||
"types": [
|
||||
"jasmine",
|
||||
"jasminewd2",
|
||||
"node"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
// Karma configuration file, see link for more information
|
||||
// https://karma-runner.github.io/1.0/config/configuration-file.html
|
||||
|
||||
module.exports = function (config) {
|
||||
config.set({
|
||||
basePath: '',
|
||||
frameworks: ['jasmine', '@angular/cli'],
|
||||
plugins: [
|
||||
require('karma-jasmine'),
|
||||
require('karma-chrome-launcher'),
|
||||
require('karma-jasmine-html-reporter'),
|
||||
require('karma-coverage-istanbul-reporter'),
|
||||
require('@angular/cli/plugins/karma')
|
||||
],
|
||||
client:{
|
||||
clearContext: false // leave Jasmine Spec Runner output visible in browser
|
||||
},
|
||||
coverageIstanbulReporter: {
|
||||
reports: [ 'html', 'lcovonly' ],
|
||||
fixWebpackSourcePaths: true
|
||||
},
|
||||
angularCli: {
|
||||
environment: 'dev'
|
||||
},
|
||||
reporters: ['progress', 'kjhtml'],
|
||||
port: 9876,
|
||||
colors: true,
|
||||
logLevel: config.LOG_INFO,
|
||||
autoWatch: true,
|
||||
browsers: ['Chrome'],
|
||||
singleRun: false
|
||||
});
|
||||
};
|
||||
4211
src/Microsoft.DotNet.Web.Spa.ProjectTemplates/content/Angular-CSharp/ClientApp/npm-shrinkwrap.json
generated
Normal file
4211
src/Microsoft.DotNet.Web.Spa.ProjectTemplates/content/Angular-CSharp/ClientApp/npm-shrinkwrap.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,53 @@
|
|||
{
|
||||
"name": "client-app",
|
||||
"version": "0.0.0",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"ng": "ng",
|
||||
"start": "ng serve --deploy-url=/dist/ --output-hashing=media --extract-css",
|
||||
"build": "ng build --deploy-url=/dist/ --output-hashing=media --extract-css",
|
||||
"build:ssr": "ng build --deploy-url=/dist/ --output-hashing=media --extract-css --bundle-dependencies=all --app=ssr",
|
||||
"test": "ng test",
|
||||
"lint": "ng lint",
|
||||
"e2e": "ng e2e"
|
||||
},
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@angular/animations": "^5.0.0",
|
||||
"@angular/common": "^5.0.0",
|
||||
"@angular/compiler": "^5.0.0",
|
||||
"@angular/core": "^5.0.0",
|
||||
"@angular/forms": "^5.0.0",
|
||||
"@angular/http": "^5.0.0",
|
||||
"@angular/platform-browser": "^5.0.0",
|
||||
"@angular/platform-browser-dynamic": "^5.0.0",
|
||||
"@angular/platform-server": "^5.0.0",
|
||||
"@angular/router": "^5.0.0",
|
||||
"aspnet-prerendering": "^3.0.1",
|
||||
"bootstrap": "^3.3.7",
|
||||
"core-js": "^2.4.1",
|
||||
"rxjs": "^5.5.2",
|
||||
"zone.js": "^0.8.14"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular/cli": "1.5.0",
|
||||
"@angular/compiler-cli": "^5.0.0",
|
||||
"@angular/language-service": "^5.0.0",
|
||||
"@types/jasmine": "~2.5.53",
|
||||
"@types/jasminewd2": "~2.0.2",
|
||||
"@types/node": "~6.0.60",
|
||||
"codelyzer": "~4.0.1",
|
||||
"jasmine-core": "~2.6.2",
|
||||
"jasmine-spec-reporter": "~4.1.0",
|
||||
"karma": "~1.7.0",
|
||||
"karma-chrome-launcher": "~2.1.1",
|
||||
"karma-cli": "~1.0.1",
|
||||
"karma-coverage-istanbul-reporter": "^1.2.1",
|
||||
"karma-jasmine": "~1.1.0",
|
||||
"karma-jasmine-html-reporter": "^0.2.2",
|
||||
"protractor": "~5.1.2",
|
||||
"ts-node": "~3.2.0",
|
||||
"tslint": "~5.7.0",
|
||||
"typescript": "~2.4.2"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
// Protractor configuration file, see link for more information
|
||||
// https://github.com/angular/protractor/blob/master/lib/config.ts
|
||||
|
||||
const { SpecReporter } = require('jasmine-spec-reporter');
|
||||
|
||||
exports.config = {
|
||||
allScriptsTimeout: 11000,
|
||||
specs: [
|
||||
'./e2e/**/*.e2e-spec.ts'
|
||||
],
|
||||
capabilities: {
|
||||
'browserName': 'chrome'
|
||||
},
|
||||
directConnect: true,
|
||||
baseUrl: 'http://localhost:4200/',
|
||||
framework: 'jasmine',
|
||||
jasmineNodeOpts: {
|
||||
showColors: true,
|
||||
defaultTimeoutInterval: 30000,
|
||||
print: function() {}
|
||||
},
|
||||
onPrepare() {
|
||||
require('ts-node').register({
|
||||
project: 'e2e/tsconfig.e2e.json'
|
||||
});
|
||||
jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } }));
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
@media (max-width: 767px) {
|
||||
/* On small screens, the nav menu spans the full width of the screen. Leave a space for it. */
|
||||
.body-content {
|
||||
padding-top: 50px;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
<div class='container-fluid'>
|
||||
<div class='row'>
|
||||
<div class='col-sm-3'>
|
||||
<app-nav-menu></app-nav-menu>
|
||||
</div>
|
||||
<div class='col-sm-9 body-content'>
|
||||
<router-outlet></router-outlet>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
templateUrl: './app.component.html',
|
||||
styleUrls: ['./app.component.css']
|
||||
})
|
||||
export class AppComponent {
|
||||
title = 'app';
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
import { BrowserModule } from '@angular/platform-browser';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { HttpClientModule } from '@angular/common/http';
|
||||
import { RouterModule } from '@angular/router';
|
||||
|
||||
import { AppComponent } from './app.component';
|
||||
import { NavMenuComponent } from './nav-menu/nav-menu.component';
|
||||
import { HomeComponent } from './home/home.component';
|
||||
import { CounterComponent } from './counter/counter.component';
|
||||
import { FetchDataComponent } from './fetch-data/fetch-data.component';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
AppComponent,
|
||||
NavMenuComponent,
|
||||
HomeComponent,
|
||||
CounterComponent,
|
||||
FetchDataComponent
|
||||
],
|
||||
imports: [
|
||||
BrowserModule.withServerTransition({ appId: 'ng-cli-universal' }),
|
||||
HttpClientModule,
|
||||
FormsModule,
|
||||
RouterModule.forRoot([
|
||||
{ path: '', component: HomeComponent, pathMatch: 'full' },
|
||||
{ path: 'counter', component: CounterComponent },
|
||||
{ path: 'fetch-data', component: FetchDataComponent },
|
||||
])
|
||||
],
|
||||
providers: [],
|
||||
bootstrap: [AppComponent]
|
||||
})
|
||||
export class AppModule { }
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
import { NgModule } from '@angular/core';
|
||||
import { ServerModule } from '@angular/platform-server';
|
||||
import { AppComponent } from './app.component';
|
||||
import { AppModule } from './app.module';
|
||||
|
||||
@NgModule({
|
||||
imports: [AppModule, ServerModule],
|
||||
bootstrap: [AppComponent]
|
||||
})
|
||||
export class AppServerModule { }
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { CounterComponent } from './counter.component';
|
||||
|
||||
describe('CounterComponent', () => {
|
||||
let component: CounterComponent;
|
||||
let fixture: ComponentFixture<CounterComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ CounterComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(CounterComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should display a title', async(() => {
|
||||
const titleText = fixture.nativeElement.querySelector('h1').textContent;
|
||||
expect(titleText).toEqual('Counter');
|
||||
}));
|
||||
|
||||
it('should start with count 0, then increments by 1 when clicked', async(() => {
|
||||
const countElement = fixture.nativeElement.querySelector('strong');
|
||||
expect(countElement.textContent).toEqual('0');
|
||||
|
||||
const incrementButton = fixture.nativeElement.querySelector('button');
|
||||
incrementButton.click();
|
||||
fixture.detectChanges();
|
||||
expect(countElement.textContent).toEqual('1');
|
||||
}));
|
||||
});
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-counter-component',
|
||||
templateUrl: './counter.component.html'
|
||||
})
|
||||
export class CounterComponent {
|
||||
public currentCount = 0;
|
||||
|
||||
public incrementCounter() {
|
||||
this.currentCount++;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
<h1>Weather forecast</h1>
|
||||
|
||||
<p>This component demonstrates fetching data from the server.</p>
|
||||
|
||||
<p *ngIf="!forecasts"><em>Loading...</em></p>
|
||||
|
||||
<table class='table' *ngIf="forecasts">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Date</th>
|
||||
<th>Temp. (C)</th>
|
||||
<th>Temp. (F)</th>
|
||||
<th>Summary</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr *ngFor="let forecast of forecasts">
|
||||
<td>{{ forecast.dateFormatted }}</td>
|
||||
<td>{{ forecast.temperatureC }}</td>
|
||||
<td>{{ forecast.temperatureF }}</td>
|
||||
<td>{{ forecast.summary }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
import { Component, Inject } from '@angular/core';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
|
||||
@Component({
|
||||
selector: 'app-fetch-data',
|
||||
templateUrl: './fetch-data.component.html'
|
||||
})
|
||||
export class FetchDataComponent {
|
||||
public forecasts: WeatherForecast[];
|
||||
|
||||
constructor(http: HttpClient, @Inject('BASE_URL') baseUrl: string) {
|
||||
http.get<WeatherForecast[]>(baseUrl + 'api/SampleData/WeatherForecasts').subscribe(result => {
|
||||
this.forecasts = result;
|
||||
}, error => console.error(error));
|
||||
}
|
||||
}
|
||||
|
||||
interface WeatherForecast {
|
||||
dateFormatted: string;
|
||||
temperatureC: number;
|
||||
temperatureF: number;
|
||||
summary: string;
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
<h1>Hello, world!</h1>
|
||||
<p>Welcome to your new single-page application, built with:</p>
|
||||
<ul>
|
||||
<li><a href='https://get.asp.net/'>ASP.NET Core</a> and <a href='https://msdn.microsoft.com/en-us/library/67ef8sbd.aspx'>C#</a> for cross-platform server-side code</li>
|
||||
<li><a href='https://angular.io/'>Angular</a> and <a href='http://www.typescriptlang.org/'>TypeScript</a> for client-side code</li>
|
||||
<li><a href='https://webpack.github.io/'>Webpack</a> for building and bundling client-side resources</li>
|
||||
<li><a href='http://getbootstrap.com/'>Bootstrap</a> for layout and styling</li>
|
||||
</ul>
|
||||
<p>To help you get started, we've also set up:</p>
|
||||
<ul>
|
||||
<li><strong>Client-side navigation</strong>. For example, click <em>Counter</em> then <em>Back</em> to return here.</li>
|
||||
<li><strong>Server-side prerendering</strong>. For faster initial loading and improved SEO, your Angular app is prerendered on the server. The resulting HTML is then transferred to the browser where a client-side copy of the app takes over.</li>
|
||||
<li><strong>Webpack dev middleware</strong>. In development mode, there's no need to run the <code>webpack</code> build tool. Your client-side resources are dynamically built on demand. Updates are available as soon as you modify any file.</li>
|
||||
<li><strong>Hot module replacement</strong>. In development mode, you don't even need to reload the page after making most changes. Within seconds of saving changes to files, your Angular app will be rebuilt and a new instance injected is into the page.</li>
|
||||
<li><strong>Efficient production builds</strong>. In production mode, development-time features are disabled, and the <code>webpack</code> build tool produces minified static CSS and JavaScript files.</li>
|
||||
</ul>
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'home',
|
||||
templateUrl: './home.component.html'
|
||||
selector: 'app-home',
|
||||
templateUrl: './home.component.html',
|
||||
})
|
||||
export class HomeComponent {
|
||||
}
|
||||
|
|
@ -7,13 +7,13 @@
|
|||
<span class='icon-bar'></span>
|
||||
<span class='icon-bar'></span>
|
||||
</button>
|
||||
<a class='navbar-brand' [routerLink]="['/home']">AngularSpa</a>
|
||||
<a class='navbar-brand' [routerLink]="['/']">AngularSpa</a>
|
||||
</div>
|
||||
<div class='clearfix'></div>
|
||||
<div class='navbar-collapse collapse'>
|
||||
<ul class='nav navbar-nav'>
|
||||
<li [routerLinkActive]="['link-active']">
|
||||
<a [routerLink]="['/home']">
|
||||
<li [routerLinkActive]="['link-active']" [routerLinkActiveOptions]="{ exact: true }">
|
||||
<a [routerLink]="['/']">
|
||||
<span class='glyphicon glyphicon-home'></span> Home
|
||||
</a>
|
||||
</li>
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-nav-menu',
|
||||
templateUrl: './nav-menu.component.html',
|
||||
styleUrls: ['./nav-menu.component.css']
|
||||
})
|
||||
export class NavMenuComponent {
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
export const environment = {
|
||||
production: true
|
||||
};
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
// The file contents for the current environment will overwrite these during build.
|
||||
// The build system defaults to the dev environment which uses `environment.ts`, but if you do
|
||||
// `ng build --env=prod` then `environment.prod.ts` will be used instead.
|
||||
// The list of which env maps to which file can be found in `.angular-cli.json`.
|
||||
|
||||
export const environment = {
|
||||
production: false
|
||||
};
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>AngularSpa</title>
|
||||
<base href="/">
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="icon" type="image/x-icon" href="favicon.ico">
|
||||
</head>
|
||||
<body>
|
||||
<app-root>Loading...</app-root>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -2,24 +2,24 @@ import 'reflect-metadata';
|
|||
import 'zone.js';
|
||||
import 'rxjs/add/operator/first';
|
||||
import { APP_BASE_HREF } from '@angular/common';
|
||||
import { enableProdMode, ApplicationRef, NgZone, ValueProvider } from '@angular/core';
|
||||
import { enableProdMode, ApplicationRef, NgModule, NgZone, ValueProvider } from '@angular/core';
|
||||
import { platformDynamicServer, PlatformState, INITIAL_CONFIG } from '@angular/platform-server';
|
||||
import { AppServerModule } from './app/app.server.module';
|
||||
import { createServerRenderer, RenderResult } from 'aspnet-prerendering';
|
||||
import { AppModule } from './app/app.server.module';
|
||||
|
||||
enableProdMode();
|
||||
|
||||
export default createServerRenderer(params => {
|
||||
const providers = [
|
||||
{ provide: INITIAL_CONFIG, useValue: { document: '<app></app>', url: params.url } },
|
||||
{ provide: INITIAL_CONFIG, useValue: { document: params.data.originalHtml, url: params.url } },
|
||||
{ provide: APP_BASE_HREF, useValue: params.baseUrl },
|
||||
{ provide: 'BASE_URL', useValue: params.origin + params.baseUrl },
|
||||
];
|
||||
|
||||
return platformDynamicServer(providers).bootstrapModule(AppModule).then(moduleRef => {
|
||||
return platformDynamicServer(providers).bootstrapModule(AppServerModule).then(moduleRef => {
|
||||
const appRef: ApplicationRef = moduleRef.injector.get(ApplicationRef);
|
||||
const state = moduleRef.injector.get(PlatformState);
|
||||
const zone = moduleRef.injector.get(NgZone);
|
||||
const zone: NgZone = moduleRef.injector.get(NgZone);
|
||||
|
||||
return new Promise<RenderResult>((resolve, reject) => {
|
||||
zone.onError.subscribe((errorInfo: any) => reject(errorInfo));
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
import { enableProdMode } from '@angular/core';
|
||||
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
|
||||
|
||||
import { AppModule } from './app/app.module';
|
||||
import { environment } from './environments/environment';
|
||||
|
||||
export function getBaseUrl() {
|
||||
return document.getElementsByTagName('base')[0].href;
|
||||
}
|
||||
|
||||
const providers = [
|
||||
{ provide: 'BASE_URL', useFactory: getBaseUrl, deps: [] }
|
||||
];
|
||||
|
||||
if (environment.production) {
|
||||
enableProdMode();
|
||||
}
|
||||
|
||||
platformBrowserDynamic(providers).bootstrapModule(AppModule)
|
||||
.catch(err => console.log(err));
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
/**
|
||||
* This file includes polyfills needed by Angular and is loaded before the app.
|
||||
* You can add your own extra polyfills to this file.
|
||||
*
|
||||
* This file is divided into 2 sections:
|
||||
* 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers.
|
||||
* 2. Application imports. Files imported after ZoneJS that should be loaded before your main
|
||||
* file.
|
||||
*
|
||||
* The current setup is for so-called "evergreen" browsers; the last versions of browsers that
|
||||
* automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera),
|
||||
* Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile.
|
||||
*
|
||||
* Learn more in https://angular.io/docs/ts/latest/guide/browser-support.html
|
||||
*/
|
||||
|
||||
/***************************************************************************************************
|
||||
* BROWSER POLYFILLS
|
||||
*/
|
||||
|
||||
/** IE9, IE10 and IE11 requires all of the following polyfills. **/
|
||||
// import 'core-js/es6/symbol';
|
||||
// import 'core-js/es6/object';
|
||||
// import 'core-js/es6/function';
|
||||
// import 'core-js/es6/parse-int';
|
||||
// import 'core-js/es6/parse-float';
|
||||
// import 'core-js/es6/number';
|
||||
// import 'core-js/es6/math';
|
||||
// import 'core-js/es6/string';
|
||||
// import 'core-js/es6/date';
|
||||
// import 'core-js/es6/array';
|
||||
// import 'core-js/es6/regexp';
|
||||
// import 'core-js/es6/map';
|
||||
// import 'core-js/es6/weak-map';
|
||||
// import 'core-js/es6/set';
|
||||
|
||||
/** IE10 and IE11 requires the following for NgClass support on SVG elements */
|
||||
// import 'classlist.js'; // Run `npm install --save classlist.js`.
|
||||
|
||||
/** IE10 and IE11 requires the following for the Reflect API. */
|
||||
// import 'core-js/es6/reflect';
|
||||
|
||||
|
||||
/** Evergreen browsers require these. **/
|
||||
// Used for reflect-metadata in JIT. If you use AOT (and only Angular decorators), you can remove.
|
||||
import 'core-js/es7/reflect';
|
||||
|
||||
|
||||
/**
|
||||
* Required to support Web Animations `@angular/platform-browser/animations`.
|
||||
* Needed for: All but Chrome, Firefox and Opera. http://caniuse.com/#feat=web-animation
|
||||
**/
|
||||
// import 'web-animations-js'; // Run `npm install --save web-animations-js`.
|
||||
|
||||
|
||||
|
||||
/***************************************************************************************************
|
||||
* Zone JS is required by Angular itself.
|
||||
*/
|
||||
import 'zone.js/dist/zone'; // Included with Angular CLI.
|
||||
|
||||
|
||||
|
||||
/***************************************************************************************************
|
||||
* APPLICATION IMPORTS
|
||||
*/
|
||||
|
||||
/**
|
||||
* Date, currency, decimal and percent pipes.
|
||||
* Needed for: All but Chrome, Firefox, Edge, IE11 and Safari 10
|
||||
*/
|
||||
// import 'intl'; // Run `npm install --save intl`.
|
||||
/**
|
||||
* Need to import at least one locale-data with intl.
|
||||
*/
|
||||
// import 'intl/locale-data/jsonp/en';
|
||||
|
|
@ -0,0 +1 @@
|
|||
/* You can add global styles to this file, and also import other style files */
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
// This file is required by karma.conf.js and loads recursively all the .spec and framework files
|
||||
|
||||
import 'zone.js/dist/long-stack-trace-zone';
|
||||
import 'zone.js/dist/proxy.js';
|
||||
import 'zone.js/dist/sync-test';
|
||||
import 'zone.js/dist/jasmine-patch';
|
||||
import 'zone.js/dist/async-test';
|
||||
import 'zone.js/dist/fake-async-test';
|
||||
import { getTestBed } from '@angular/core/testing';
|
||||
import {
|
||||
BrowserDynamicTestingModule,
|
||||
platformBrowserDynamicTesting
|
||||
} from '@angular/platform-browser-dynamic/testing';
|
||||
|
||||
// Unfortunately there's no typing for the `__karma__` variable. Just declare it as any.
|
||||
declare const __karma__: any;
|
||||
declare const require: any;
|
||||
|
||||
// Prevent Karma from running prematurely.
|
||||
__karma__.loaded = function () {};
|
||||
|
||||
// First, initialize the Angular testing environment.
|
||||
getTestBed().initTestEnvironment(
|
||||
BrowserDynamicTestingModule,
|
||||
platformBrowserDynamicTesting()
|
||||
);
|
||||
// Then we find all the tests.
|
||||
const context = require.context('./', true, /\.spec\.ts$/);
|
||||
// And load the modules.
|
||||
context.keys().map(context);
|
||||
// Finally, start Karma to run the tests.
|
||||
__karma__.start();
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"extends": "../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"baseUrl": "./",
|
||||
"module": "commonjs"
|
||||
},
|
||||
"angularCompilerOptions": {
|
||||
"entryModule": "app/app.server.module#AppServerModule"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"extends": "../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../out-tsc/app",
|
||||
"baseUrl": "./",
|
||||
"module": "es2015",
|
||||
"types": []
|
||||
},
|
||||
"exclude": [
|
||||
"test.ts",
|
||||
"**/*.spec.ts"
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
"extends": "../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../out-tsc/spec",
|
||||
"baseUrl": "./",
|
||||
"module": "commonjs",
|
||||
"target": "es5",
|
||||
"types": [
|
||||
"jasmine",
|
||||
"node"
|
||||
]
|
||||
},
|
||||
"files": [
|
||||
"test.ts"
|
||||
],
|
||||
"include": [
|
||||
"**/*.spec.ts",
|
||||
"**/*.d.ts"
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
/* SystemJS module definition */
|
||||
declare var module: NodeModule;
|
||||
interface NodeModule {
|
||||
id: string;
|
||||
}
|
||||
|
|
@ -1,33 +0,0 @@
|
|||
// Load required polyfills and testing libraries
|
||||
import 'reflect-metadata';
|
||||
import 'zone.js';
|
||||
import 'zone.js/dist/long-stack-trace-zone';
|
||||
import 'zone.js/dist/proxy.js';
|
||||
import 'zone.js/dist/sync-test';
|
||||
import 'zone.js/dist/jasmine-patch';
|
||||
import 'zone.js/dist/async-test';
|
||||
import 'zone.js/dist/fake-async-test';
|
||||
import * as testing from '@angular/core/testing';
|
||||
import * as testingBrowser from '@angular/platform-browser-dynamic/testing';
|
||||
|
||||
// There's no typing for the `__karma__` variable. Just declare it as any
|
||||
declare var __karma__: any;
|
||||
declare var require: any;
|
||||
|
||||
// Prevent Karma from running prematurely
|
||||
__karma__.loaded = function () {};
|
||||
|
||||
// First, initialize the Angular testing environment
|
||||
testing.getTestBed().initTestEnvironment(
|
||||
testingBrowser.BrowserDynamicTestingModule,
|
||||
testingBrowser.platformBrowserDynamicTesting()
|
||||
);
|
||||
|
||||
// Then we find all the tests
|
||||
const context = require.context('../', true, /\.spec\.ts$/);
|
||||
|
||||
// And load the modules
|
||||
context.keys().map(context);
|
||||
|
||||
// Finally, start Karma to run the tests
|
||||
__karma__.start();
|
||||
|
|
@ -1,26 +0,0 @@
|
|||
// Karma configuration file, see link for more information
|
||||
// https://karma-runner.github.io/0.13/config/configuration-file.html
|
||||
|
||||
module.exports = function (config) {
|
||||
config.set({
|
||||
basePath: '.',
|
||||
frameworks: ['jasmine'],
|
||||
files: [
|
||||
'../../wwwroot/dist/vendor.js',
|
||||
'./boot-tests.ts'
|
||||
],
|
||||
preprocessors: {
|
||||
'./boot-tests.ts': ['webpack']
|
||||
},
|
||||
reporters: ['progress'],
|
||||
port: 9876,
|
||||
colors: true,
|
||||
logLevel: config.LOG_INFO,
|
||||
autoWatch: true,
|
||||
browsers: ['Chrome'],
|
||||
mime: { 'application/javascript': ['ts','tsx'] },
|
||||
singleRun: false,
|
||||
webpack: require('../../webpack.config.js')().filter(config => config.target !== 'node'), // Test against client bundle, because tests run in a browser
|
||||
webpackMiddleware: { stats: 'errors-only' }
|
||||
});
|
||||
};
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
{
|
||||
"compileOnSave": false,
|
||||
"compilerOptions": {
|
||||
"outDir": "./dist/out-tsc",
|
||||
"sourceMap": true,
|
||||
"declaration": false,
|
||||
"moduleResolution": "node",
|
||||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true,
|
||||
"target": "es5",
|
||||
"typeRoots": [
|
||||
"node_modules/@types"
|
||||
],
|
||||
"lib": [
|
||||
"es2017",
|
||||
"dom"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,140 @@
|
|||
{
|
||||
"rulesDirectory": [
|
||||
"node_modules/codelyzer"
|
||||
],
|
||||
"rules": {
|
||||
"arrow-return-shorthand": true,
|
||||
"callable-types": true,
|
||||
"class-name": true,
|
||||
"comment-format": [
|
||||
true,
|
||||
"check-space"
|
||||
],
|
||||
"curly": true,
|
||||
"eofline": true,
|
||||
"forin": true,
|
||||
"import-blacklist": [
|
||||
true,
|
||||
"rxjs",
|
||||
"rxjs/Rx"
|
||||
],
|
||||
"import-spacing": true,
|
||||
"indent": [
|
||||
true,
|
||||
"spaces"
|
||||
],
|
||||
"interface-over-type-literal": true,
|
||||
"label-position": true,
|
||||
"max-line-length": [
|
||||
true,
|
||||
140
|
||||
],
|
||||
"member-access": false,
|
||||
"member-ordering": [
|
||||
true,
|
||||
{
|
||||
"order": [
|
||||
"static-field",
|
||||
"instance-field",
|
||||
"static-method",
|
||||
"instance-method"
|
||||
]
|
||||
}
|
||||
],
|
||||
"no-arg": true,
|
||||
"no-bitwise": true,
|
||||
"no-console": [
|
||||
true,
|
||||
"debug",
|
||||
"info",
|
||||
"time",
|
||||
"timeEnd",
|
||||
"trace"
|
||||
],
|
||||
"no-construct": true,
|
||||
"no-debugger": true,
|
||||
"no-duplicate-super": true,
|
||||
"no-empty": false,
|
||||
"no-empty-interface": true,
|
||||
"no-eval": true,
|
||||
"no-inferrable-types": [
|
||||
true,
|
||||
"ignore-params"
|
||||
],
|
||||
"no-misused-new": true,
|
||||
"no-non-null-assertion": true,
|
||||
"no-shadowed-variable": true,
|
||||
"no-string-literal": false,
|
||||
"no-string-throw": true,
|
||||
"no-switch-case-fall-through": true,
|
||||
"no-trailing-whitespace": true,
|
||||
"no-unnecessary-initializer": true,
|
||||
"no-unused-expression": true,
|
||||
"no-use-before-declare": true,
|
||||
"no-var-keyword": true,
|
||||
"object-literal-sort-keys": false,
|
||||
"one-line": [
|
||||
true,
|
||||
"check-open-brace",
|
||||
"check-catch",
|
||||
"check-else",
|
||||
"check-whitespace"
|
||||
],
|
||||
"prefer-const": true,
|
||||
"quotemark": [
|
||||
true,
|
||||
"single"
|
||||
],
|
||||
"radix": true,
|
||||
"semicolon": [
|
||||
true,
|
||||
"always"
|
||||
],
|
||||
"triple-equals": [
|
||||
true,
|
||||
"allow-null-check"
|
||||
],
|
||||
"typedef-whitespace": [
|
||||
true,
|
||||
{
|
||||
"call-signature": "nospace",
|
||||
"index-signature": "nospace",
|
||||
"parameter": "nospace",
|
||||
"property-declaration": "nospace",
|
||||
"variable-declaration": "nospace"
|
||||
}
|
||||
],
|
||||
"typeof-compare": true,
|
||||
"unified-signatures": true,
|
||||
"variable-name": false,
|
||||
"whitespace": [
|
||||
true,
|
||||
"check-branch",
|
||||
"check-decl",
|
||||
"check-operator",
|
||||
"check-separator",
|
||||
"check-type"
|
||||
],
|
||||
"directive-selector": [
|
||||
true,
|
||||
"attribute",
|
||||
"app",
|
||||
"camelCase"
|
||||
],
|
||||
"component-selector": [
|
||||
true,
|
||||
"element",
|
||||
"app",
|
||||
"kebab-case"
|
||||
],
|
||||
"use-input-property-decorator": true,
|
||||
"use-output-property-decorator": true,
|
||||
"use-host-property-decorator": true,
|
||||
"no-input-rename": true,
|
||||
"no-output-rename": true,
|
||||
"use-life-cycle-interface": true,
|
||||
"use-pipe-transform-interface": true,
|
||||
"component-class-suffix": true,
|
||||
"directive-class-suffix": true
|
||||
}
|
||||
}
|
||||
|
|
@ -1,23 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace AngularSpa.Controllers
|
||||
{
|
||||
public class HomeController : Controller
|
||||
{
|
||||
public IActionResult Index()
|
||||
{
|
||||
return View();
|
||||
}
|
||||
|
||||
public IActionResult Error()
|
||||
{
|
||||
ViewData["RequestId"] = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
|
||||
return View();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +1,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.HttpsPolicy;
|
||||
using Microsoft.AspNetCore.SpaServices.Webpack;
|
||||
using Microsoft.AspNetCore.SpaServices.AngularCli;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
|
|
@ -32,10 +28,6 @@ namespace AngularSpa
|
|||
if (env.IsDevelopment())
|
||||
{
|
||||
app.UseDeveloperExceptionPage();
|
||||
app.UseWebpackDevMiddleware(new WebpackDevMiddlewareOptions
|
||||
{
|
||||
HotModuleReplacement = true
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -50,11 +42,31 @@ namespace AngularSpa
|
|||
{
|
||||
routes.MapRoute(
|
||||
name: "default",
|
||||
template: "{controller=Home}/{action=Index}/{id?}");
|
||||
template: "{controller}/{action=Index}/{id?}");
|
||||
});
|
||||
|
||||
routes.MapSpaFallbackRoute(
|
||||
name: "spa-fallback",
|
||||
defaults: new { controller = "Home", action = "Index" });
|
||||
app.UseSpa(spa =>
|
||||
{
|
||||
spa.Options.DefaultPage = "/dist/index.html";
|
||||
spa.Options.SourcePath = "ClientApp";
|
||||
|
||||
/*
|
||||
// If you want to enable server-side rendering (SSR),
|
||||
// [1] In AngularSpa.csproj, change the <BuildServerSideRenderer> property
|
||||
// value to 'true', so that the SSR bundle is built during publish
|
||||
// [2] Uncomment this code block
|
||||
spa.UseSpaPrerendering(options =>
|
||||
{
|
||||
options.BootModulePath = $"{spa.Options.SourcePath}/dist-server/main.bundle.js";
|
||||
options.BootModuleBuilder = env.IsDevelopment() ? new AngularCliBuilder(npmScript: "build:ssr") : null;
|
||||
options.ExcludeUrls = new[] { "/sockjs-node" };
|
||||
});
|
||||
*/
|
||||
|
||||
if (env.IsDevelopment())
|
||||
{
|
||||
spa.UseAngularCliServer(npmScript: "start");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +0,0 @@
|
|||
@{
|
||||
ViewData["Title"] = "Home Page";
|
||||
}
|
||||
|
||||
<app asp-prerender-module="ClientApp/dist/main-server">Loading...</app>
|
||||
|
||||
<script src="~/dist/vendor.js" asp-append-version="true"></script>
|
||||
@section scripts {
|
||||
<script src="~/dist/main-client.js" asp-append-version="true"></script>
|
||||
}
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
@{
|
||||
ViewData["Title"] = "Error";
|
||||
}
|
||||
|
||||
<h1 class="text-danger">Error.</h1>
|
||||
<h2 class="text-danger">An error occurred while processing your request.</h2>
|
||||
|
||||
@if (!string.IsNullOrEmpty((string)ViewData["RequestId"]))
|
||||
{
|
||||
<p>
|
||||
<strong>Request ID:</strong> <code>@ViewData["RequestId"]</code>
|
||||
</p>
|
||||
}
|
||||
|
||||
<h3>Development Mode</h3>
|
||||
<p>
|
||||
Swapping to <strong>Development</strong> environment will display more detailed information about the error that occurred.
|
||||
</p>
|
||||
<p>
|
||||
<strong>Development environment should not be enabled in deployed applications</strong>, as it can result in sensitive information from exceptions being displayed to end users. For local debugging, development environment can be enabled by setting the <strong>ASPNETCORE_ENVIRONMENT</strong> environment variable to <strong>Development</strong>, and restarting the application.
|
||||
</p>
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>@ViewData["Title"] - AngularSpa</title>
|
||||
<base href="~/" />
|
||||
|
||||
<link rel="stylesheet" href="~/dist/vendor.css" asp-append-version="true" />
|
||||
</head>
|
||||
<body>
|
||||
@RenderBody()
|
||||
|
||||
@RenderSection("scripts", required: false)
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
@using AngularSpa
|
||||
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
|
||||
@addTagHelper *, Microsoft.AspNetCore.SpaServices
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
@{
|
||||
Layout = "_Layout";
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,62 +0,0 @@
|
|||
{
|
||||
"name": "AngularSpa",
|
||||
"private": true,
|
||||
"version": "0.0.0",
|
||||
"scripts": {
|
||||
"test": "karma start ClientApp/test/karma.conf.js"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular/animations": "4.2.5",
|
||||
"@angular/common": "4.2.5",
|
||||
"@angular/compiler": "4.2.5",
|
||||
"@angular/compiler-cli": "4.2.5",
|
||||
"@angular/core": "4.2.5",
|
||||
"@angular/forms": "4.2.5",
|
||||
"@angular/http": "4.2.5",
|
||||
"@angular/platform-browser": "4.2.5",
|
||||
"@angular/platform-browser-dynamic": "4.2.5",
|
||||
"@angular/platform-server": "4.2.5",
|
||||
"@angular/router": "4.2.5",
|
||||
"@ngtools/webpack": "1.5.0",
|
||||
"@types/chai": "4.0.1",
|
||||
"@types/jasmine": "2.5.53",
|
||||
"@types/webpack-env": "1.13.0",
|
||||
"angular2-router-loader": "0.3.5",
|
||||
"angular2-template-loader": "0.6.2",
|
||||
"aspnet-prerendering": "^3.0.1",
|
||||
"aspnet-webpack": "^2.0.1",
|
||||
"awesome-typescript-loader": "3.2.1",
|
||||
"bootstrap": "3.3.7",
|
||||
"chai": "4.0.2",
|
||||
"css": "2.2.1",
|
||||
"css-loader": "0.28.4",
|
||||
"es6-shim": "0.35.3",
|
||||
"event-source-polyfill": "0.0.9",
|
||||
"expose-loader": "0.7.3",
|
||||
"extract-text-webpack-plugin": "2.1.2",
|
||||
"file-loader": "0.11.2",
|
||||
"html-loader": "0.4.5",
|
||||
"isomorphic-fetch": "2.2.1",
|
||||
"jasmine-core": "2.6.4",
|
||||
"jquery": "3.2.1",
|
||||
"json-loader": "0.5.4",
|
||||
"karma": "1.7.0",
|
||||
"karma-chai": "0.1.0",
|
||||
"karma-chrome-launcher": "2.2.0",
|
||||
"karma-cli": "1.0.1",
|
||||
"karma-jasmine": "1.1.0",
|
||||
"karma-webpack": "2.0.3",
|
||||
"preboot": "4.5.2",
|
||||
"raw-loader": "0.5.1",
|
||||
"reflect-metadata": "0.1.10",
|
||||
"rxjs": "5.4.2",
|
||||
"style-loader": "0.18.2",
|
||||
"to-string-loader": "1.1.5",
|
||||
"typescript": "2.4.1",
|
||||
"url-loader": "0.5.9",
|
||||
"webpack": "2.5.1",
|
||||
"webpack-hot-middleware": "2.18.2",
|
||||
"webpack-merge": "4.1.0",
|
||||
"zone.js": "0.8.12"
|
||||
}
|
||||
}
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"module": "es2015",
|
||||
"moduleResolution": "node",
|
||||
"target": "es5",
|
||||
"sourceMap": true,
|
||||
"experimentalDecorators": true,
|
||||
"emitDecoratorMetadata": true,
|
||||
"skipDefaultLibCheck": true,
|
||||
"skipLibCheck": true, // Workaround for https://github.com/angular/angular/issues/17863. Remove this if you upgrade to a fixed version of Angular.
|
||||
"strict": true,
|
||||
"lib": [ "es6", "dom" ],
|
||||
"types": [ "webpack-env" ]
|
||||
},
|
||||
"exclude": [ "bin", "node_modules" ],
|
||||
"atom": { "rewriteTsconfig": false }
|
||||
}
|
||||
|
|
@ -1,84 +0,0 @@
|
|||
const path = require('path');
|
||||
const webpack = require('webpack');
|
||||
const merge = require('webpack-merge');
|
||||
const AotPlugin = require('@ngtools/webpack').AotPlugin;
|
||||
const CheckerPlugin = require('awesome-typescript-loader').CheckerPlugin;
|
||||
|
||||
module.exports = (env) => {
|
||||
// Configuration in common to both client-side and server-side bundles
|
||||
const isDevBuild = !(env && env.prod);
|
||||
const sharedConfig = {
|
||||
stats: { modules: false },
|
||||
context: __dirname,
|
||||
resolve: { extensions: [ '.js', '.ts' ] },
|
||||
output: {
|
||||
filename: '[name].js',
|
||||
publicPath: 'dist/' // Webpack dev middleware, if enabled, handles requests for this URL prefix
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{ test: /\.ts$/, use: isDevBuild ? ['awesome-typescript-loader?silent=true', 'angular2-template-loader', 'angular2-router-loader'] : '@ngtools/webpack' },
|
||||
{ test: /\.html$/, use: 'html-loader?minimize=false' },
|
||||
{ test: /\.css$/, use: [ 'to-string-loader', isDevBuild ? 'css-loader' : 'css-loader?minimize' ] },
|
||||
{ test: /\.(png|jpg|jpeg|gif|svg)$/, use: 'url-loader?limit=25000' }
|
||||
]
|
||||
},
|
||||
plugins: [new CheckerPlugin()]
|
||||
};
|
||||
|
||||
// Configuration for client-side bundle suitable for running in browsers
|
||||
const clientBundleOutputDir = './wwwroot/dist';
|
||||
const clientBundleConfig = merge(sharedConfig, {
|
||||
entry: { 'main-client': './ClientApp/boot.browser.ts' },
|
||||
output: { path: path.join(__dirname, clientBundleOutputDir) },
|
||||
plugins: [
|
||||
new webpack.DllReferencePlugin({
|
||||
context: __dirname,
|
||||
manifest: require('./wwwroot/dist/vendor-manifest.json')
|
||||
})
|
||||
].concat(isDevBuild ? [
|
||||
// Plugins that apply in development builds only
|
||||
new webpack.SourceMapDevToolPlugin({
|
||||
filename: '[file].map', // Remove this line if you prefer inline source maps
|
||||
moduleFilenameTemplate: path.relative(clientBundleOutputDir, '[resourcePath]') // Point sourcemap entries to the original file locations on disk
|
||||
})
|
||||
] : [
|
||||
// Plugins that apply in production builds only
|
||||
new webpack.optimize.UglifyJsPlugin(),
|
||||
new AotPlugin({
|
||||
tsConfigPath: './tsconfig.json',
|
||||
entryModule: path.join(__dirname, 'ClientApp/app/app.browser.module#AppModule'),
|
||||
exclude: ['./**/*.server.ts']
|
||||
})
|
||||
])
|
||||
});
|
||||
|
||||
// Configuration for server-side (prerendering) bundle suitable for running in Node
|
||||
const serverBundleConfig = merge(sharedConfig, {
|
||||
resolve: { mainFields: ['main'] },
|
||||
entry: { 'main-server': './ClientApp/boot.server.ts' },
|
||||
plugins: [
|
||||
new webpack.DllReferencePlugin({
|
||||
context: __dirname,
|
||||
manifest: require('./ClientApp/dist/vendor-manifest.json'),
|
||||
sourceType: 'commonjs2',
|
||||
name: './vendor'
|
||||
})
|
||||
].concat(isDevBuild ? [] : [
|
||||
// Plugins that apply in production builds only
|
||||
new AotPlugin({
|
||||
tsConfigPath: './tsconfig.json',
|
||||
entryModule: path.join(__dirname, 'ClientApp/app/app.server.module#AppModule'),
|
||||
exclude: ['./**/*.browser.ts']
|
||||
})
|
||||
]),
|
||||
output: {
|
||||
libraryTarget: 'commonjs',
|
||||
path: path.join(__dirname, './ClientApp/dist')
|
||||
},
|
||||
target: 'node',
|
||||
devtool: 'inline-source-map'
|
||||
});
|
||||
|
||||
return [clientBundleConfig, serverBundleConfig];
|
||||
};
|
||||
|
|
@ -1,94 +0,0 @@
|
|||
const path = require('path');
|
||||
const webpack = require('webpack');
|
||||
const ExtractTextPlugin = require('extract-text-webpack-plugin');
|
||||
const merge = require('webpack-merge');
|
||||
const treeShakableModules = [
|
||||
'@angular/animations',
|
||||
'@angular/common',
|
||||
'@angular/compiler',
|
||||
'@angular/core',
|
||||
'@angular/forms',
|
||||
'@angular/http',
|
||||
'@angular/platform-browser',
|
||||
'@angular/platform-browser-dynamic',
|
||||
'@angular/router',
|
||||
'zone.js',
|
||||
];
|
||||
const nonTreeShakableModules = [
|
||||
'bootstrap',
|
||||
'bootstrap/dist/css/bootstrap.css',
|
||||
'es6-promise',
|
||||
'es6-shim',
|
||||
'event-source-polyfill',
|
||||
'jquery',
|
||||
];
|
||||
const allModules = treeShakableModules.concat(nonTreeShakableModules);
|
||||
|
||||
module.exports = (env) => {
|
||||
const extractCSS = new ExtractTextPlugin('vendor.css');
|
||||
const isDevBuild = !(env && env.prod);
|
||||
const sharedConfig = {
|
||||
stats: { modules: false },
|
||||
resolve: { extensions: [ '.js' ] },
|
||||
module: {
|
||||
rules: [
|
||||
{ test: /\.(png|woff|woff2|eot|ttf|svg)(\?|$)/, use: 'url-loader?limit=100000' }
|
||||
]
|
||||
},
|
||||
output: {
|
||||
publicPath: 'dist/',
|
||||
filename: '[name].js',
|
||||
library: '[name]_[hash]'
|
||||
},
|
||||
plugins: [
|
||||
new webpack.ProvidePlugin({ $: 'jquery', jQuery: 'jquery' }), // Maps these identifiers to the jQuery package (because Bootstrap expects it to be a global variable)
|
||||
new webpack.ContextReplacementPlugin(/\@angular\b.*\b(bundles|linker)/, path.join(__dirname, './ClientApp')), // Workaround for https://github.com/angular/angular/issues/11580
|
||||
new webpack.ContextReplacementPlugin(/angular(\\|\/)core(\\|\/)@angular/, path.join(__dirname, './ClientApp')), // Workaround for https://github.com/angular/angular/issues/14898
|
||||
new webpack.IgnorePlugin(/^vertx$/) // Workaround for https://github.com/stefanpenner/es6-promise/issues/100
|
||||
]
|
||||
};
|
||||
|
||||
const clientBundleConfig = merge(sharedConfig, {
|
||||
entry: {
|
||||
// To keep development builds fast, include all vendor dependencies in the vendor bundle.
|
||||
// But for production builds, leave the tree-shakable ones out so the AOT compiler can produce a smaller bundle.
|
||||
vendor: isDevBuild ? allModules : nonTreeShakableModules
|
||||
},
|
||||
output: { path: path.join(__dirname, 'wwwroot', 'dist') },
|
||||
module: {
|
||||
rules: [
|
||||
{ test: /\.css(\?|$)/, use: extractCSS.extract({ use: isDevBuild ? 'css-loader' : 'css-loader?minimize' }) }
|
||||
]
|
||||
},
|
||||
plugins: [
|
||||
extractCSS,
|
||||
new webpack.DllPlugin({
|
||||
path: path.join(__dirname, 'wwwroot', 'dist', '[name]-manifest.json'),
|
||||
name: '[name]_[hash]'
|
||||
})
|
||||
].concat(isDevBuild ? [] : [
|
||||
new webpack.optimize.UglifyJsPlugin()
|
||||
])
|
||||
});
|
||||
|
||||
const serverBundleConfig = merge(sharedConfig, {
|
||||
target: 'node',
|
||||
resolve: { mainFields: ['main'] },
|
||||
entry: { vendor: allModules.concat(['aspnet-prerendering']) },
|
||||
output: {
|
||||
path: path.join(__dirname, 'ClientApp', 'dist'),
|
||||
libraryTarget: 'commonjs2',
|
||||
},
|
||||
module: {
|
||||
rules: [ { test: /\.css(\?|$)/, use: ['to-string-loader', isDevBuild ? 'css-loader' : 'css-loader?minimize' ] } ]
|
||||
},
|
||||
plugins: [
|
||||
new webpack.DllPlugin({
|
||||
path: path.join(__dirname, 'ClientApp', 'dist', '[name]-manifest.json'),
|
||||
name: '[name]_[hash]'
|
||||
})
|
||||
]
|
||||
});
|
||||
|
||||
return [clientBundleConfig, serverBundleConfig];
|
||||
}
|
||||
21
src/Microsoft.DotNet.Web.Spa.ProjectTemplates/content/React-CSharp/ClientApp/.gitignore
vendored
Normal file
21
src/Microsoft.DotNet.Web.Spa.ProjectTemplates/content/React-CSharp/ClientApp/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
# See https://help.github.com/ignore-files/ for more about ignoring files.
|
||||
|
||||
# dependencies
|
||||
/node_modules
|
||||
|
||||
# testing
|
||||
/coverage
|
||||
|
||||
# production
|
||||
/build
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
.env.local
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
.env.production.local
|
||||
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,30 +0,0 @@
|
|||
import './css/site.css';
|
||||
import 'bootstrap';
|
||||
import * as React from 'react';
|
||||
import * as ReactDOM from 'react-dom';
|
||||
import { AppContainer } from 'react-hot-loader';
|
||||
import { BrowserRouter } from 'react-router-dom';
|
||||
import * as RoutesModule from './routes';
|
||||
let routes = RoutesModule.routes;
|
||||
|
||||
function renderApp() {
|
||||
// This code starts up the React app when it runs in a browser. It sets up the routing
|
||||
// configuration and injects the app into a DOM element.
|
||||
const baseUrl = document.getElementsByTagName('base')[0].getAttribute('href')!;
|
||||
ReactDOM.render(
|
||||
<AppContainer>
|
||||
<BrowserRouter children={ routes } basename={ baseUrl } />
|
||||
</AppContainer>,
|
||||
document.getElementById('react-app')
|
||||
);
|
||||
}
|
||||
|
||||
renderApp();
|
||||
|
||||
// Allow Hot Module Replacement
|
||||
if (module.hot) {
|
||||
module.hot.accept('./routes', () => {
|
||||
routes = require<typeof RoutesModule>('./routes').routes;
|
||||
renderApp();
|
||||
});
|
||||
}
|
||||
|
|
@ -1,31 +0,0 @@
|
|||
import * as React from 'react';
|
||||
import { RouteComponentProps } from 'react-router';
|
||||
|
||||
interface CounterState {
|
||||
currentCount: number;
|
||||
}
|
||||
|
||||
export class Counter extends React.Component<RouteComponentProps<{}>, CounterState> {
|
||||
constructor() {
|
||||
super();
|
||||
this.state = { currentCount: 0 };
|
||||
}
|
||||
|
||||
public render() {
|
||||
return <div>
|
||||
<h1>Counter</h1>
|
||||
|
||||
<p>This is a simple example of a React component.</p>
|
||||
|
||||
<p>Current count: <strong>{ this.state.currentCount }</strong></p>
|
||||
|
||||
<button onClick={ () => { this.incrementCounter() } }>Increment</button>
|
||||
</div>;
|
||||
}
|
||||
|
||||
incrementCounter() {
|
||||
this.setState({
|
||||
currentCount: this.state.currentCount + 1
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -1,63 +0,0 @@
|
|||
import * as React from 'react';
|
||||
import { RouteComponentProps } from 'react-router';
|
||||
import 'isomorphic-fetch';
|
||||
|
||||
interface FetchDataExampleState {
|
||||
forecasts: WeatherForecast[];
|
||||
loading: boolean;
|
||||
}
|
||||
|
||||
export class FetchData extends React.Component<RouteComponentProps<{}>, FetchDataExampleState> {
|
||||
constructor() {
|
||||
super();
|
||||
this.state = { forecasts: [], loading: true };
|
||||
|
||||
fetch('api/SampleData/WeatherForecasts')
|
||||
.then(response => response.json() as Promise<WeatherForecast[]>)
|
||||
.then(data => {
|
||||
this.setState({ forecasts: data, loading: false });
|
||||
});
|
||||
}
|
||||
|
||||
public render() {
|
||||
let contents = this.state.loading
|
||||
? <p><em>Loading...</em></p>
|
||||
: FetchData.renderForecastsTable(this.state.forecasts);
|
||||
|
||||
return <div>
|
||||
<h1>Weather forecast</h1>
|
||||
<p>This component demonstrates fetching data from the server.</p>
|
||||
{ contents }
|
||||
</div>;
|
||||
}
|
||||
|
||||
private static renderForecastsTable(forecasts: WeatherForecast[]) {
|
||||
return <table className='table'>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Date</th>
|
||||
<th>Temp. (C)</th>
|
||||
<th>Temp. (F)</th>
|
||||
<th>Summary</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{forecasts.map(forecast =>
|
||||
<tr key={ forecast.dateFormatted }>
|
||||
<td>{ forecast.dateFormatted }</td>
|
||||
<td>{ forecast.temperatureC }</td>
|
||||
<td>{ forecast.temperatureF }</td>
|
||||
<td>{ forecast.summary }</td>
|
||||
</tr>
|
||||
)}
|
||||
</tbody>
|
||||
</table>;
|
||||
}
|
||||
}
|
||||
|
||||
interface WeatherForecast {
|
||||
dateFormatted: string;
|
||||
temperatureC: number;
|
||||
temperatureF: number;
|
||||
summary: string;
|
||||
}
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
import * as React from 'react';
|
||||
import { RouteComponentProps } from 'react-router';
|
||||
|
||||
export class Home extends React.Component<RouteComponentProps<{}>, {}> {
|
||||
public render() {
|
||||
return <div>
|
||||
<h1>Hello, world!</h1>
|
||||
<p>Welcome to your new single-page application, built with:</p>
|
||||
<ul>
|
||||
<li><a href='https://get.asp.net/'>ASP.NET Core</a> and <a href='https://msdn.microsoft.com/en-us/library/67ef8sbd.aspx'>C#</a> for cross-platform server-side code</li>
|
||||
<li><a href='https://facebook.github.io/react/'>React</a> and <a href='http://www.typescriptlang.org/'>TypeScript</a> for client-side code</li>
|
||||
<li><a href='https://webpack.github.io/'>Webpack</a> for building and bundling client-side resources</li>
|
||||
<li><a href='http://getbootstrap.com/'>Bootstrap</a> for layout and styling</li>
|
||||
</ul>
|
||||
<p>To help you get started, we've also set up:</p>
|
||||
<ul>
|
||||
<li><strong>Client-side navigation</strong>. For example, click <em>Counter</em> then <em>Back</em> to return here.</li>
|
||||
<li><strong>Webpack dev middleware</strong>. In development mode, there's no need to run the <code>webpack</code> build tool. Your client-side resources are dynamically built on demand. Updates are available as soon as you modify any file.</li>
|
||||
<li><strong>Hot module replacement</strong>. In development mode, you don't even need to reload the page after making most changes. Within seconds of saving changes to files, rebuilt React components will be injected directly into your running application, preserving its live state.</li>
|
||||
<li><strong>Efficient production builds</strong>. In production mode, development-time features are disabled, and the <code>webpack</code> build tool produces minified static CSS and JavaScript files.</li>
|
||||
</ul>
|
||||
<h4>Going further</h4>
|
||||
<p>
|
||||
For larger applications, or for server-side prerendering (i.e., for <em>isomorphic</em> or <em>universal</em> applications), you should consider using a Flux/Redux-like architecture.
|
||||
You can generate an ASP.NET Core application with React and Redux using <code>dotnet new reactredux</code> instead of using this template.
|
||||
</p>
|
||||
</div>;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
import * as React from 'react';
|
||||
import { NavMenu } from './NavMenu';
|
||||
|
||||
export interface LayoutProps {
|
||||
children?: React.ReactNode;
|
||||
}
|
||||
|
||||
export class Layout extends React.Component<LayoutProps, {}> {
|
||||
public render() {
|
||||
return <div className='container-fluid'>
|
||||
<div className='row'>
|
||||
<div className='col-sm-3'>
|
||||
<NavMenu />
|
||||
</div>
|
||||
<div className='col-sm-9'>
|
||||
{ this.props.children }
|
||||
</div>
|
||||
</div>
|
||||
</div>;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,40 +0,0 @@
|
|||
import * as React from 'react';
|
||||
import { Link, NavLink } from 'react-router-dom';
|
||||
|
||||
export class NavMenu extends React.Component<{}, {}> {
|
||||
public render() {
|
||||
return <div className='main-nav'>
|
||||
<div className='navbar navbar-inverse'>
|
||||
<div className='navbar-header'>
|
||||
<button type='button' className='navbar-toggle' data-toggle='collapse' data-target='.navbar-collapse'>
|
||||
<span className='sr-only'>Toggle navigation</span>
|
||||
<span className='icon-bar'></span>
|
||||
<span className='icon-bar'></span>
|
||||
<span className='icon-bar'></span>
|
||||
</button>
|
||||
<Link className='navbar-brand' to={ '/' }>ReactSpa</Link>
|
||||
</div>
|
||||
<div className='clearfix'></div>
|
||||
<div className='navbar-collapse collapse'>
|
||||
<ul className='nav navbar-nav'>
|
||||
<li>
|
||||
<NavLink to={ '/' } exact activeClassName='active'>
|
||||
<span className='glyphicon glyphicon-home'></span> Home
|
||||
</NavLink>
|
||||
</li>
|
||||
<li>
|
||||
<NavLink to={ '/counter' } activeClassName='active'>
|
||||
<span className='glyphicon glyphicon-education'></span> Counter
|
||||
</NavLink>
|
||||
</li>
|
||||
<li>
|
||||
<NavLink to={ '/fetchdata' } activeClassName='active'>
|
||||
<span className='glyphicon glyphicon-th-list'></span> Fetch data
|
||||
</NavLink>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,66 +0,0 @@
|
|||
.main-nav li .glyphicon {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
/* Highlighting rules for nav menu items */
|
||||
.main-nav li a.active,
|
||||
.main-nav li a.active:hover,
|
||||
.main-nav li a.active:focus {
|
||||
background-color: #4189C7;
|
||||
color: white;
|
||||
}
|
||||
|
||||
/* Keep the nav menu independent of scrolling and on top of other items */
|
||||
.main-nav {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
@media (max-width: 767px) {
|
||||
/* On small screens, the nav menu spans the full width of the screen. Leave a space for it. */
|
||||
body {
|
||||
padding-top: 50px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
/* On small screens, convert the nav menu to a vertical sidebar */
|
||||
.main-nav {
|
||||
height: 100%;
|
||||
width: calc(25% - 20px);
|
||||
}
|
||||
.main-nav .navbar {
|
||||
border-radius: 0px;
|
||||
border-width: 0px;
|
||||
height: 100%;
|
||||
}
|
||||
.main-nav .navbar-header {
|
||||
float: none;
|
||||
}
|
||||
.main-nav .navbar-collapse {
|
||||
border-top: 1px solid #444;
|
||||
padding: 0px;
|
||||
}
|
||||
.main-nav .navbar ul {
|
||||
float: none;
|
||||
}
|
||||
.main-nav .navbar li {
|
||||
float: none;
|
||||
font-size: 15px;
|
||||
margin: 6px;
|
||||
}
|
||||
.main-nav .navbar li a {
|
||||
padding: 10px 16px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.main-nav .navbar a {
|
||||
/* If a menu item's text is too long, truncate it */
|
||||
width: 100%;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
}
|
||||
3406
src/Microsoft.DotNet.Web.Spa.ProjectTemplates/content/React-CSharp/ClientApp/npm-shrinkwrap.json
generated
Normal file
3406
src/Microsoft.DotNet.Web.Spa.ProjectTemplates/content/React-CSharp/ClientApp/npm-shrinkwrap.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,21 @@
|
|||
{
|
||||
"name": "ReactSpa",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"bootstrap": "^3.3.7",
|
||||
"react": "^16.0.0",
|
||||
"react-bootstrap": "^0.31.5",
|
||||
"react-dom": "^16.0.0",
|
||||
"react-router-bootstrap": "^0.24.4",
|
||||
"react-router-dom": "^4.2.2",
|
||||
"react-scripts": "1.0.17",
|
||||
"rimraf": "^2.6.2"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "rimraf ./build && react-scripts start",
|
||||
"build": "react-scripts build",
|
||||
"test": "react-scripts test --env=jsdom",
|
||||
"eject": "react-scripts eject"
|
||||
}
|
||||
}
|
||||
|
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 31 KiB |
|
|
@ -0,0 +1,41 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="theme-color" content="#000000">
|
||||
<base href="%PUBLIC_URL%/" />
|
||||
<!--
|
||||
manifest.json provides metadata used when your web app is added to the
|
||||
homescreen on Android. See https://developers.google.com/web/fundamentals/engage-and-retain/web-app-manifest/
|
||||
-->
|
||||
<link rel="manifest" href="%PUBLIC_URL%/manifest.json">
|
||||
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
|
||||
<!--
|
||||
Notice the use of %PUBLIC_URL% in the tags above.
|
||||
It will be replaced with the URL of the `public` folder during the build.
|
||||
Only files inside the `public` folder can be referenced from the HTML.
|
||||
|
||||
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
|
||||
work correctly both with client-side routing and a non-root public URL.
|
||||
Learn how to configure a non-root public URL by running `npm run build`.
|
||||
-->
|
||||
<title>ReactSpa</title>
|
||||
</head>
|
||||
<body>
|
||||
<noscript>
|
||||
You need to enable JavaScript to run this app.
|
||||
</noscript>
|
||||
<div id="root"></div>
|
||||
<!--
|
||||
This HTML file is a template.
|
||||
If you open it directly in the browser, you will see an empty page.
|
||||
|
||||
You can add webfonts, meta tags, or analytics to this file.
|
||||
The build step will place the bundled scripts into the <body> tag.
|
||||
|
||||
To begin the development, run `npm start` or `yarn start`.
|
||||
To create a production bundle, use `npm run build` or `yarn build`.
|
||||
-->
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"short_name": "ReactSpa",
|
||||
"name": "ReactSpa",
|
||||
"icons": [
|
||||
{
|
||||
"src": "favicon.ico",
|
||||
"sizes": "64x64 32x32 24x24 16x16",
|
||||
"type": "image/x-icon"
|
||||
}
|
||||
],
|
||||
"start_url": "./index.html",
|
||||
"display": "standalone",
|
||||
"theme_color": "#000000",
|
||||
"background_color": "#ffffff"
|
||||
}
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
import * as React from 'react';
|
||||
import { Route } from 'react-router-dom';
|
||||
import { Layout } from './components/Layout';
|
||||
import { Home } from './components/Home';
|
||||
import { FetchData } from './components/FetchData';
|
||||
import { Counter } from './components/Counter';
|
||||
|
||||
export const routes = <Layout>
|
||||
<Route exact path='/' component={ Home } />
|
||||
<Route path='/counter' component={ Counter } />
|
||||
<Route path='/fetchdata' component={ FetchData } />
|
||||
</Layout>;
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
import React, { Component } from 'react';
|
||||
import { Route } from 'react-router';
|
||||
import { Layout } from './components/Layout';
|
||||
import { Home } from './components/Home';
|
||||
import { FetchData } from './components/FetchData';
|
||||
import { Counter } from './components/Counter';
|
||||
|
||||
export default class App extends Component {
|
||||
displayName = App.name
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Layout>
|
||||
<Route exact path='/' component={Home} />
|
||||
<Route path='/counter' component={Counter} />
|
||||
<Route path='/fetchdata' component={FetchData} />
|
||||
</Layout>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import App from './App';
|
||||
|
||||
it('renders without crashing', () => {
|
||||
const div = document.createElement('div');
|
||||
ReactDOM.render(<App />, div);
|
||||
});
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
import React, { Component } from 'react';
|
||||
|
||||
export class Counter extends Component {
|
||||
displayName = Counter.name
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.state = { currentCount: 0 };
|
||||
}
|
||||
|
||||
incrementCounter() {
|
||||
this.setState({
|
||||
currentCount: this.state.currentCount + 1
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<h1>Counter</h1>
|
||||
|
||||
<p>This is a simple example of a React component.</p>
|
||||
|
||||
<p>Current count: <strong>{this.state.currentCount}</strong></p>
|
||||
|
||||
<button onClick={() => this.incrementCounter()}>Increment</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
import React, { Component } from 'react';
|
||||
|
||||
export class FetchData extends Component {
|
||||
displayName = FetchData.name
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.state = { forecasts: [], loading: true };
|
||||
|
||||
fetch('api/SampleData/WeatherForecasts')
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
this.setState({ forecasts: data, loading: false });
|
||||
});
|
||||
}
|
||||
|
||||
static renderForecastsTable(forecasts) {
|
||||
return (
|
||||
<table className='table'>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Date</th>
|
||||
<th>Temp. (C)</th>
|
||||
<th>Temp. (F)</th>
|
||||
<th>Summary</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{forecasts.map(forecast =>
|
||||
<tr key={forecast.dateFormatted}>
|
||||
<td>{forecast.dateFormatted}</td>
|
||||
<td>{forecast.temperatureC}</td>
|
||||
<td>{forecast.temperatureF}</td>
|
||||
<td>{forecast.summary}</td>
|
||||
</tr>
|
||||
)}
|
||||
</tbody>
|
||||
</table>
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
let contents = this.state.loading
|
||||
? <p><em>Loading...</em></p>
|
||||
: FetchData.renderForecastsTable(this.state.forecasts);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h1>Weather forecast</h1>
|
||||
<p>This component demonstrates fetching data from the server.</p>
|
||||
{contents}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
import React, { Component } from 'react';
|
||||
|
||||
export class Home extends Component {
|
||||
displayName = Home.name
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<h1>Hello, world!</h1>
|
||||
<p>Welcome to your new single-page application, built with:</p>
|
||||
<ul>
|
||||
<li><a href='https://get.asp.net/'>ASP.NET Core</a> and <a href='https://msdn.microsoft.com/en-us/library/67ef8sbd.aspx'>C#</a> for cross-platform server-side code</li>
|
||||
<li><a href='https://facebook.github.io/react/'>React</a> for client-side code</li>
|
||||
<li><a href='http://getbootstrap.com/'>Bootstrap</a> for layout and styling</li>
|
||||
</ul>
|
||||
<p>To help you get started, we've also set up:</p>
|
||||
<ul>
|
||||
<li><strong>Client-side navigation</strong>. For example, click <em>Counter</em> then <em>Back</em> to return here.</li>
|
||||
<li><strong>Development server integration</strong>. In development mode, there's no need to run the <code>create-react-app</code> tool manually. Your client-side resources are dynamically built on demand. Updates are available as soon as you modify any file.</li>
|
||||
<li><strong>Efficient production builds</strong>. In production mode, development-time features are disabled, and <code>create-react-app</code> builds minified static CSS and JavaScript files.</li>
|
||||
</ul>
|
||||
<h4>Going further</h4>
|
||||
<p>
|
||||
For larger applications, or for server-side prerendering (i.e., for <em>isomorphic</em> or <em>universal</em> applications), you should consider using a Flux/Redux-like architecture. You can generate an ASP.NET Core application with React and Redux using <code>dotnet new reactredux</code> instead of using this template.
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
import React, { Component } from 'react';
|
||||
import { Col, Grid, Row } from 'react-bootstrap';
|
||||
import { NavMenu } from './NavMenu';
|
||||
|
||||
export class Layout extends Component {
|
||||
displayName = Layout.name
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Grid fluid>
|
||||
<Row>
|
||||
<Col sm={3}>
|
||||
<NavMenu />
|
||||
</Col>
|
||||
<Col sm={9}>
|
||||
{this.props.children}
|
||||
</Col>
|
||||
</Row>
|
||||
</Grid>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
.navbar li .glyphicon {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
/* Highlighting rules for nav menu items */
|
||||
.navbar .navbar-nav .active a,
|
||||
.navbar .navbar-nav .active a:hover,
|
||||
.navbar .navbar-nav .active a:focus {
|
||||
background-image: none;
|
||||
background-color: #4189C7;
|
||||
color: white;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
/* On large screens, convert the nav menu to a vertical sidebar */
|
||||
.navbar {
|
||||
height: 100%;
|
||||
width: calc(25% - 20px);
|
||||
}
|
||||
.navbar {
|
||||
border-radius: 0;
|
||||
border-width: 0;
|
||||
height: 100%;
|
||||
}
|
||||
.navbar-header {
|
||||
float: none;
|
||||
}
|
||||
.navbar .navbar-collapse {
|
||||
border-top: 1px solid #444;
|
||||
padding: 0;
|
||||
}
|
||||
.navbar .container-fluid {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
.navbar .container-fluid .navbar-brand {
|
||||
margin: 0;
|
||||
}
|
||||
.navbar ul {
|
||||
float: none;
|
||||
}
|
||||
.navbar li {
|
||||
float: none;
|
||||
font-size: 15px;
|
||||
margin: 6px;
|
||||
}
|
||||
.navbar li a {
|
||||
padding: 10px 16px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.navbar a {
|
||||
/* If a menu item's text is too long, truncate it */
|
||||
width: 100%;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
import React, { Component } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { Glyphicon, Nav, Navbar, NavItem } from 'react-bootstrap';
|
||||
import { LinkContainer } from 'react-router-bootstrap';
|
||||
import './NavMenu.css';
|
||||
|
||||
export class NavMenu extends Component {
|
||||
displayName = NavMenu.name
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Navbar inverse fixedTop fluid collapseOnSelect>
|
||||
<Navbar.Header>
|
||||
<Navbar.Brand>
|
||||
<Link to={'/'}>ReactSpa</Link>
|
||||
</Navbar.Brand>
|
||||
<Navbar.Toggle />
|
||||
</Navbar.Header>
|
||||
<Navbar.Collapse>
|
||||
<Nav>
|
||||
<LinkContainer to={'/'} exact>
|
||||
<NavItem>
|
||||
<Glyphicon glyph='home' /> Home
|
||||
</NavItem>
|
||||
</LinkContainer>
|
||||
<LinkContainer to={'/counter'}>
|
||||
<NavItem>
|
||||
<Glyphicon glyph='education' /> Counter
|
||||
</NavItem>
|
||||
</LinkContainer>
|
||||
<LinkContainer to={'/fetchdata'}>
|
||||
<NavItem>
|
||||
<Glyphicon glyph='th-list' /> Fetch data
|
||||
</NavItem>
|
||||
</LinkContainer>
|
||||
</Nav>
|
||||
</Navbar.Collapse>
|
||||
</Navbar>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
@media (max-width: 767px) {
|
||||
/* On small screens, the nav menu spans the full width of the screen. Leave a space for it. */
|
||||
.body-content {
|
||||
body {
|
||||
padding-top: 50px;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
import 'bootstrap/dist/css/bootstrap.css';
|
||||
import 'bootstrap/dist/css/bootstrap-theme.css';
|
||||
import './index.css';
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import { BrowserRouter } from 'react-router-dom';
|
||||
import App from './App';
|
||||
import registerServiceWorker from './registerServiceWorker';
|
||||
|
||||
const baseUrl = document.getElementsByTagName('base')[0].getAttribute('href');
|
||||
const rootElement = document.getElementById('root');
|
||||
|
||||
ReactDOM.render(
|
||||
<BrowserRouter basename={baseUrl}>
|
||||
<App />
|
||||
</BrowserRouter>,
|
||||
rootElement);
|
||||
|
||||
registerServiceWorker();
|
||||
|
|
@ -0,0 +1,108 @@
|
|||
// In production, we register a service worker to serve assets from local cache.
|
||||
|
||||
// This lets the app load faster on subsequent visits in production, and gives
|
||||
// it offline capabilities. However, it also means that developers (and users)
|
||||
// will only see deployed updates on the "N+1" visit to a page, since previously
|
||||
// cached resources are updated in the background.
|
||||
|
||||
// To learn more about the benefits of this model, read https://goo.gl/KwvDNy.
|
||||
// This link also includes instructions on opting out of this behavior.
|
||||
|
||||
const isLocalhost = Boolean(
|
||||
window.location.hostname === 'localhost' ||
|
||||
// [::1] is the IPv6 localhost address.
|
||||
window.location.hostname === '[::1]' ||
|
||||
// 127.0.0.1/8 is considered localhost for IPv4.
|
||||
window.location.hostname.match(
|
||||
/^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/
|
||||
)
|
||||
);
|
||||
|
||||
export default function register() {
|
||||
if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
|
||||
// The URL constructor is available in all browsers that support SW.
|
||||
const publicUrl = new URL(process.env.PUBLIC_URL, window.location);
|
||||
if (publicUrl.origin !== window.location.origin) {
|
||||
// Our service worker won't work if PUBLIC_URL is on a different origin
|
||||
// from what our page is served on. This might happen if a CDN is used to
|
||||
// serve assets; see https://github.com/facebookincubator/create-react-app/issues/2374
|
||||
return;
|
||||
}
|
||||
|
||||
window.addEventListener('load', () => {
|
||||
const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;
|
||||
|
||||
if (isLocalhost) {
|
||||
// This is running on localhost. Lets check if a service worker still exists or not.
|
||||
checkValidServiceWorker(swUrl);
|
||||
} else {
|
||||
// Is not local host. Just register service worker
|
||||
registerValidSW(swUrl);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function registerValidSW(swUrl) {
|
||||
navigator.serviceWorker
|
||||
.register(swUrl)
|
||||
.then(registration => {
|
||||
registration.onupdatefound = () => {
|
||||
const installingWorker = registration.installing;
|
||||
installingWorker.onstatechange = () => {
|
||||
if (installingWorker.state === 'installed') {
|
||||
if (navigator.serviceWorker.controller) {
|
||||
// At this point, the old content will have been purged and
|
||||
// the fresh content will have been added to the cache.
|
||||
// It's the perfect time to display a "New content is
|
||||
// available; please refresh." message in your web app.
|
||||
console.log('New content is available; please refresh.');
|
||||
} else {
|
||||
// At this point, everything has been precached.
|
||||
// It's the perfect time to display a
|
||||
// "Content is cached for offline use." message.
|
||||
console.log('Content is cached for offline use.');
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error during service worker registration:', error);
|
||||
});
|
||||
}
|
||||
|
||||
function checkValidServiceWorker(swUrl) {
|
||||
// Check if the service worker can be found. If it can't reload the page.
|
||||
fetch(swUrl)
|
||||
.then(response => {
|
||||
// Ensure service worker exists, and that we really are getting a JS file.
|
||||
if (
|
||||
response.status === 404 ||
|
||||
response.headers.get('content-type').indexOf('javascript') === -1
|
||||
) {
|
||||
// No service worker found. Probably a different app. Reload the page.
|
||||
navigator.serviceWorker.ready.then(registration => {
|
||||
registration.unregister().then(() => {
|
||||
window.location.reload();
|
||||
});
|
||||
});
|
||||
} else {
|
||||
// Service worker found. Proceed as normal.
|
||||
registerValidSW(swUrl);
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
console.log(
|
||||
'No internet connection found. App is running in offline mode.'
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
export function unregister() {
|
||||
if ('serviceWorker' in navigator) {
|
||||
navigator.serviceWorker.ready.then(registration => {
|
||||
registration.unregister();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -1,23 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace ReactSpa.Controllers
|
||||
{
|
||||
public class HomeController : Controller
|
||||
{
|
||||
public IActionResult Index()
|
||||
{
|
||||
return View();
|
||||
}
|
||||
|
||||
public IActionResult Error()
|
||||
{
|
||||
ViewData["RequestId"] = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
|
||||
return View();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +1,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.HttpsPolicy;
|
||||
using Microsoft.AspNetCore.SpaServices.Webpack;
|
||||
using Microsoft.AspNetCore.SpaServices.ReactDevelopmentServer;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
|
|
@ -24,6 +20,12 @@ namespace ReactSpa
|
|||
public void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
services.AddMvc();
|
||||
|
||||
// In production, the React files will be served from this directory
|
||||
services.AddSpaStaticFiles(configuration =>
|
||||
{
|
||||
configuration.RootPath = "ClientApp/build";
|
||||
});
|
||||
}
|
||||
|
||||
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
||||
|
|
@ -32,11 +34,6 @@ namespace ReactSpa
|
|||
if (env.IsDevelopment())
|
||||
{
|
||||
app.UseDeveloperExceptionPage();
|
||||
app.UseWebpackDevMiddleware(new WebpackDevMiddlewareOptions
|
||||
{
|
||||
HotModuleReplacement = true,
|
||||
ReactHotModuleReplacement = true
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -46,16 +43,23 @@ namespace ReactSpa
|
|||
|
||||
app.UseHttpsRedirection();
|
||||
app.UseStaticFiles();
|
||||
app.UseSpaStaticFiles();
|
||||
|
||||
app.UseMvc(routes =>
|
||||
{
|
||||
routes.MapRoute(
|
||||
name: "default",
|
||||
template: "{controller=Home}/{action=Index}/{id?}");
|
||||
template: "{controller}/{action=Index}/{id?}");
|
||||
});
|
||||
|
||||
routes.MapSpaFallbackRoute(
|
||||
name: "spa-fallback",
|
||||
defaults: new { controller = "Home", action = "Index" });
|
||||
app.UseSpa(spa =>
|
||||
{
|
||||
spa.Options.SourcePath = "ClientApp";
|
||||
|
||||
if (env.IsDevelopment())
|
||||
{
|
||||
spa.UseReactDevelopmentServer(npmScript: "start");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +0,0 @@
|
|||
@{
|
||||
ViewData["Title"] = "Home Page";
|
||||
}
|
||||
|
||||
<div id="react-app">Loading...</div>
|
||||
|
||||
@section scripts {
|
||||
<script src="~/dist/main.js" asp-append-version="true"></script>
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue