Compare commits

..

1 Commits

Author SHA1 Message Date
Pranav K
128683be0e Pinning versions for 2.0.0 2017-08-17 15:00:10 -07:00
269 changed files with 1238 additions and 3753 deletions

11
.gitignore vendored
View File

@@ -29,7 +29,14 @@ nuget.exe
npm-debug.log npm-debug.log
/.build/ /.build/
# The templates can't contain their own .gitignore files, because Yeoman has strange default handling for
# files with that name (https://github.com/npm/npm/issues/1862). So, each template instead has a template_gitignore
# file which gets renamed after the files are copied. And so any files that need to be excluded in the source
# repo have to be excluded here.
/templates/*/node_modules/
/templates/*/wwwroot/dist/
/templates/*/ClientApp/dist/
/templates/*/yarn.lock
.vscode/ .vscode/
global.json /templates/*/Properties/launchSettings.json
korebuild-lock.txt

View File

@@ -2,7 +2,7 @@
<configuration> <configuration>
<packageSources> <packageSources>
<clear /> <clear />
<add key="AspNetCore" value="https://dotnet.myget.org/F/aspnetcore-ci-dev/api/v3/index.json" /> <add key="AspNetCore" value="https://dotnet.myget.org/F/aspnetcore-master/api/v3/index.json" />
<add key="AspNetCoreTools" value="https://dotnet.myget.org/F/aspnetcore-tools/api/v3/index.json" /> <add key="AspNetCoreTools" value="https://dotnet.myget.org/F/aspnetcore-tools/api/v3/index.json" />
<add key="NuGet" value="https://api.nuget.org/v3/index.json" /> <add key="NuGet" value="https://api.nuget.org/v3/index.json" />
</packageSources> </packageSources>

View File

@@ -1,10 +1,10 @@
init: init:
- git config --global core.autocrlf true - git config --global core.autocrlf true
install: install:
- ps: Install-Product node 6.9.2 x64 - ps: Install-Product node 6.9.2 x64
# .NET Core SDK binaries # .NET Core SDK binaries
# Download .NET Core 2.0 Preview 3 SDK and add to PATH # Download .NET Core 2.0 Preview 3 SDK and add to PATH
- ps: $urlCurrent = "https://dotnetcli.azureedge.net/dotnet/Sdk/2.0.0-preview3-006857/dotnet-sdk-2.0.0-preview3-006857-win-x64.zip" - ps: $urlCurrent = "https://dotnetcli.azureedge.net/dotnet/Sdk/2.0.0-preview3-006729/dotnet-sdk-2.0.0-preview3-006729-win-x64.zip"
- ps: $env:DOTNET_INSTALL_DIR = "$pwd\.dotnetsdk" - ps: $env:DOTNET_INSTALL_DIR = "$pwd\.dotnetsdk"
- ps: mkdir $env:DOTNET_INSTALL_DIR -Force | Out-Null - ps: mkdir $env:DOTNET_INSTALL_DIR -Force | Out-Null
- ps: $tempFileCurrent = [System.IO.Path]::Combine([System.IO.Path]::GetTempPath(), [System.IO.Path]::GetRandomFileName()) - ps: $tempFileCurrent = [System.IO.Path]::Combine([System.IO.Path]::GetTempPath(), [System.IO.Path]::GetRandomFileName())
@@ -18,15 +18,13 @@ build_script:
- npm run build - npm run build
- ps: Pop-Location - ps: Pop-Location
artifacts: artifacts:
- path: templates\package-builder\artifacts\*.nupkg - path: templates\package-builder\dist\artifacts\generator-aspnetcore-spa.tar.gz
name: generator-aspnetcore-spa
- path: templates\package-builder\dist\artifacts\*.nupkg
name: Microsoft.AspNetCore.SpaTemplates name: Microsoft.AspNetCore.SpaTemplates
type: NuGetPackage type: NuGetPackage
# - ps: .\build.ps1 # - ps: .\build.ps1
clone_depth: 1 clone_depth: 1
environment:
global:
DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true
DOTNET_CLI_TELEMETRY_OPTOUT: 1
test_script: test_script:
- dotnet restore - dotnet restore
- ps: Push-Location - ps: Push-Location

222
build.ps1
View File

@@ -1,177 +1,67 @@
#!/usr/bin/env powershell $ErrorActionPreference = "Stop"
#requires -version 4
<# function DownloadWithRetry([string] $url, [string] $downloadLocation, [int] $retries)
.SYNOPSIS {
Build this repository while($true)
{
try
{
Invoke-WebRequest $url -OutFile $downloadLocation
break
}
catch
{
$exceptionMessage = $_.Exception.Message
Write-Host "Failed to download '$url': $exceptionMessage"
if ($retries -gt 0) {
$retries--
Write-Host "Waiting 10 seconds before retrying. Retries left: $retries"
Start-Sleep -Seconds 10
.DESCRIPTION }
Downloads korebuild if required. Then builds the repository. else
{
.PARAMETER Path $exception = $_.Exception
The folder to build. Defaults to the folder containing this script. throw $exception
}
.PARAMETER Channel }
The channel of KoreBuild to download. Overrides the value from the config file. }
.PARAMETER DotNetHome
The directory where .NET Core tools will be stored.
.PARAMETER ToolsSource
The base url where build tools can be downloaded. Overrides the value from the config file.
.PARAMETER Update
Updates KoreBuild to the latest version even if a lock file is present.
.PARAMETER ConfigFile
The path to the configuration file that stores values. Defaults to version.xml.
.PARAMETER MSBuildArgs
Arguments to be passed to MSBuild
.NOTES
This function will create a file $PSScriptRoot/korebuild-lock.txt. This lock file can be committed to source, but does not have to be.
When the lockfile is not present, KoreBuild will create one using latest available version from $Channel.
The $ConfigFile is expected to be an XML file. It is optional, and the configuration values in it are optional as well.
.EXAMPLE
Example config file:
```xml
<!-- version.xml -->
<Project>
<PropertyGroup>
<KoreBuildChannel>dev</KoreBuildChannel>
<KoreBuildToolsSource>https://aspnetcore.blob.core.windows.net/buildtools</KoreBuildToolsSource>
</PropertyGroup>
</Project>
```
#>
[CmdletBinding(PositionalBinding = $false)]
param(
[string]$Path = $PSScriptRoot,
[Alias('c')]
[string]$Channel,
[Alias('d')]
[string]$DotNetHome,
[Alias('s')]
[string]$ToolsSource,
[Alias('u')]
[switch]$Update,
[string]$ConfigFile = (Join-Path $PSScriptRoot 'version.xml'),
[Parameter(ValueFromRemainingArguments = $true)]
[string[]]$MSBuildArgs
)
Set-StrictMode -Version 2
$ErrorActionPreference = 'Stop'
#
# Functions
#
function Get-KoreBuild {
$lockFile = Join-Path $Path 'korebuild-lock.txt'
if (!(Test-Path $lockFile) -or $Update) {
Get-RemoteFile "$ToolsSource/korebuild/channels/$Channel/latest.txt" $lockFile
} }
$version = Get-Content $lockFile | Where-Object { $_ -like 'version:*' } | Select-Object -first 1 cd $PSScriptRoot
if (!$version) {
Write-Error "Failed to parse version from $lockFile. Expected a line that begins with 'version:'"
}
$version = $version.TrimStart('version:').Trim()
$korebuildPath = Join-Paths $DotNetHome ('buildtools', 'korebuild', $version)
if (!(Test-Path $korebuildPath)) { $repoFolder = $PSScriptRoot
Write-Host -ForegroundColor Magenta "Downloading KoreBuild $version" $env:REPO_FOLDER = $repoFolder
New-Item -ItemType Directory -Path $korebuildPath | Out-Null
$remotePath = "$ToolsSource/korebuild/artifacts/$version/korebuild.$version.zip"
try { $koreBuildZip="https://github.com/aspnet/KoreBuild/archive/rel/2.0.0.zip"
$tmpfile = Join-Path ([IO.Path]::GetTempPath()) "KoreBuild-$([guid]::NewGuid()).zip" if ($env:KOREBUILD_ZIP)
Get-RemoteFile $remotePath $tmpfile {
if (Get-Command -Name 'Expand-Archive' -ErrorAction Ignore) { $koreBuildZip=$env:KOREBUILD_ZIP
# Use built-in commands where possible as they are cross-plat compatible
Expand-Archive -Path $tmpfile -DestinationPath $korebuildPath
} }
else {
# Fallback to old approach for old installations of PowerShell $buildFolder = ".build"
$buildFile="$buildFolder\KoreBuild.ps1"
if (!(Test-Path $buildFolder)) {
Write-Host "Downloading KoreBuild from $koreBuildZip"
$tempFolder=$env:TEMP + "\KoreBuild-" + [guid]::NewGuid()
New-Item -Path "$tempFolder" -Type directory | Out-Null
$localZipFile="$tempFolder\korebuild.zip"
DownloadWithRetry -url $koreBuildZip -downloadLocation $localZipFile -retries 6
Add-Type -AssemblyName System.IO.Compression.FileSystem Add-Type -AssemblyName System.IO.Compression.FileSystem
[System.IO.Compression.ZipFile]::ExtractToDirectory($tmpfile, $korebuildPath) [System.IO.Compression.ZipFile]::ExtractToDirectory($localZipFile, $tempFolder)
}
} New-Item -Path "$buildFolder" -Type directory | Out-Null
catch { copy-item "$tempFolder\**\build\*" $buildFolder -Recurse
Remove-Item -Recurse -Force $korebuildPath -ErrorAction Ignore
throw # Cleanup
} if (Test-Path $tempFolder) {
finally { Remove-Item -Recurse -Force $tempFolder
Remove-Item $tmpfile -ErrorAction Ignore
} }
} }
return $korebuildPath &"$buildFile" @args
}
function Join-Paths([string]$path, [string[]]$childPaths) {
$childPaths | ForEach-Object { $path = Join-Path $path $_ }
return $path
}
function Get-RemoteFile([string]$RemotePath, [string]$LocalPath) {
if ($RemotePath -notlike 'http*') {
Copy-Item $RemotePath $LocalPath
return
}
$retries = 10
while ($retries -gt 0) {
$retries -= 1
try {
Invoke-WebRequest -UseBasicParsing -Uri $RemotePath -OutFile $LocalPath
return
}
catch {
Write-Verbose "Request failed. $retries retries remaining"
}
}
Write-Error "Download failed: '$RemotePath'."
}
#
# Main
#
# Load configuration or set defaults
if (Test-Path $ConfigFile) {
[xml] $config = Get-Content $ConfigFile
if (!($Channel)) { [string] $Channel = Select-Xml -Xml $config -XPath '/Project/PropertyGroup/KoreBuildChannel' }
if (!($ToolsSource)) { [string] $ToolsSource = Select-Xml -Xml $config -XPath '/Project/PropertyGroup/KoreBuildToolsSource' }
}
if (!$DotNetHome) {
$DotNetHome = if ($env:DOTNET_HOME) { $env:DOTNET_HOME } `
elseif ($env:USERPROFILE) { Join-Path $env:USERPROFILE '.dotnet'} `
elseif ($env:HOME) {Join-Path $env:HOME '.dotnet'}`
else { Join-Path $PSScriptRoot '.dotnet'}
}
if (!$Channel) { $Channel = 'dev' }
if (!$ToolsSource) { $ToolsSource = 'https://aspnetcore.blob.core.windows.net/buildtools' }
# Execute
$korebuildPath = Get-KoreBuild
Import-Module -Force -Scope Local (Join-Path $korebuildPath 'KoreBuild.psd1')
try {
Install-Tools $ToolsSource $DotNetHome
Invoke-RepositoryBuild $Path @MSBuildArgs
}
finally {
Remove-Module 'KoreBuild' -ErrorAction Ignore
}

227
build.sh
View File

@@ -1,199 +1,46 @@
#!/usr/bin/env bash #!/usr/bin/env bash
repoFolder="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
cd $repoFolder
set -euo pipefail koreBuildZip="https://github.com/aspnet/KoreBuild/archive/rel/2.0.0.zip"
if [ ! -z $KOREBUILD_ZIP ]; then
# koreBuildZip=$KOREBUILD_ZIP
# variables
#
RESET="\033[0m"
RED="\033[0;31m"
MAGENTA="\033[0;95m"
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
[ -z "${DOTNET_HOME:-}" ] && DOTNET_HOME="$HOME/.dotnet"
config_file="$DIR/version.xml"
verbose=false
update=false
repo_path="$DIR"
channel=''
tools_source=''
#
# Functions
#
__usage() {
echo "Usage: $(basename "${BASH_SOURCE[0]}") [options] [[--] <MSBUILD_ARG>...]"
echo ""
echo "Arguments:"
echo " <MSBUILD_ARG>... Arguments passed to MSBuild. Variable number of arguments allowed."
echo ""
echo "Options:"
echo " --verbose Show verbose output."
echo " -c|--channel <CHANNEL> The channel of KoreBuild to download. Overrides the value from the config file.."
echo " --config-file <FILE> TThe path to the configuration file that stores values. Defaults to version.xml."
echo " -d|--dotnet-home <DIR> The directory where .NET Core tools will be stored. Defaults to '\$DOTNET_HOME' or '\$HOME/.dotnet."
echo " --path <PATH> The directory to build. Defaults to the directory containing the script."
echo " -s|--tools-source <URL> The base url where build tools can be downloaded. Overrides the value from the config file."
echo " -u|--update Update to the latest KoreBuild even if the lock file is present."
echo ""
echo "Description:"
echo " This function will create a file \$DIR/korebuild-lock.txt. This lock file can be committed to source, but does not have to be."
echo " When the lockfile is not present, KoreBuild will create one using latest available version from \$channel."
if [[ "${1:-}" != '--no-exit' ]]; then
exit 2
fi
}
get_korebuild() {
local version
local lock_file="$repo_path/korebuild-lock.txt"
if [ ! -f "$lock_file" ] || [ "$update" = true ]; then
__get_remote_file "$tools_source/korebuild/channels/$channel/latest.txt" "$lock_file"
fi
version="$(grep 'version:*' -m 1 "$lock_file")"
if [[ "$version" == '' ]]; then
__error "Failed to parse version from $lock_file. Expected a line that begins with 'version:'"
return 1
fi
version="$(echo "${version#version:}" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')"
local korebuild_path="$DOTNET_HOME/buildtools/korebuild/$version"
{
if [ ! -d "$korebuild_path" ]; then
mkdir -p "$korebuild_path"
local remote_path="$tools_source/korebuild/artifacts/$version/korebuild.$version.zip"
tmpfile="$(mktemp)"
echo -e "${MAGENTA}Downloading KoreBuild ${version}${RESET}"
if __get_remote_file "$remote_path" "$tmpfile"; then
unzip -q -d "$korebuild_path" "$tmpfile"
fi
rm "$tmpfile" || true
fi fi
source "$korebuild_path/KoreBuild.sh" buildFolder=".build"
} || { buildFile="$buildFolder/KoreBuild.sh"
if [ -d "$korebuild_path" ]; then
echo "Cleaning up after failed installation" if test ! -d $buildFolder; then
rm -rf "$korebuild_path" || true echo "Downloading KoreBuild from $koreBuildZip"
tempFolder="/tmp/KoreBuild-$(uuidgen)"
mkdir $tempFolder
localZipFile="$tempFolder/korebuild.zip"
retries=6
until (wget -O $localZipFile $koreBuildZip 2>/dev/null || curl -o $localZipFile --location $koreBuildZip 2>/dev/null)
do
echo "Failed to download '$koreBuildZip'"
if [ "$retries" -le 0 ]; then
exit 1
fi fi
return 1 retries=$((retries - 1))
} echo "Waiting 10 seconds before retrying. Retries left: $retries"
} sleep 10s
__error() {
echo -e "${RED}$*${RESET}" 1>&2
}
__machine_has() {
hash "$1" > /dev/null 2>&1
return $?
}
__get_remote_file() {
local remote_path=$1
local local_path=$2
if [[ "$remote_path" != 'http'* ]]; then
cp "$remote_path" "$local_path"
return 0
fi
local failed=false
if __machine_has wget; then
wget --tries 10 --quiet -O "$local_path" "$remote_path" || failed=true
else
failed=true
fi
if [ "$failed" = true ] && __machine_has curl; then
failed=false
curl --retry 10 -sSL -f --create-dirs -o "$local_path" "$remote_path" || failed=true
fi
if [ "$failed" = true ]; then
__error "Download failed: $remote_path" 1>&2
return 1
fi
}
__read_dom () { local IFS=\> ; read -r -d \< ENTITY CONTENT ;}
#
# main
#
while [[ $# -gt 0 ]]; do
case $1 in
-\?|-h|--help)
__usage --no-exit
exit 0
;;
-c|--channel|-Channel)
shift
channel="${1:-}"
[ -z "$channel" ] && __usage
;;
--config-file|-ConfigFile)
shift
config_file="${1:-}"
[ -z "$config_file" ] && __usage
;;
-d|--dotnet-home|-DotNetHome)
shift
DOTNET_HOME="${1:-}"
[ -z "$DOTNET_HOME" ] && __usage
;;
--path|-Path)
shift
repo_path="${1:-}"
[ -z "$repo_path" ] && __usage
;;
-s|--tools-source|-ToolsSource)
shift
tools_source="${1:-}"
[ -z "$tools_source" ] && __usage
;;
-u|--update|-Update)
update=true
;;
--verbose|-Verbose)
verbose=true
;;
--)
shift
break
;;
*)
break
;;
esac
shift
done done
if ! __machine_has unzip; then unzip -q -d $tempFolder $localZipFile
__error 'Missing required command: unzip'
exit 1 mkdir $buildFolder
cp -r $tempFolder/**/build/** $buildFolder
chmod +x $buildFile
# Cleanup
if test -d $tempFolder; then
rm -rf $tempFolder
fi
fi fi
if ! __machine_has curl && ! __machine_has wget; then $buildFile -r $repoFolder "$@"
__error 'Missing required command. Either wget or curl is required.'
exit 1
fi
if [ -f "$config_file" ]; then
comment=false
while __read_dom; do
if [ "$comment" = true ]; then [[ $CONTENT == *'-->'* ]] && comment=false ; continue; fi
if [[ $ENTITY == '!--'* ]]; then comment=true; continue; fi
if [ -z "$channel" ] && [[ $ENTITY == "KoreBuildChannel" ]]; then channel=$CONTENT; fi
if [ -z "$tools_source" ] && [[ $ENTITY == "KoreBuildToolsSource" ]]; then tools_source=$CONTENT; fi
done < "$config_file"
fi
[ -z "$channel" ] && channel='dev'
[ -z "$tools_source" ] && tools_source='https://aspnetcore.blob.core.windows.net/buildtools'
get_korebuild
install_tools "$tools_source" "$DOTNET_HOME"
invoke_repository_build "$repo_path" "$@"

View File

@@ -1,6 +1,6 @@
<Project> <Project>
<Import Project="dependencies.props" /> <Import Project="dependencies.props" />
<Import Project="..\version.xml" /> <Import Project="..\version.props" />
<PropertyGroup> <PropertyGroup>
<Product>Microsoft ASP.NET Core</Product> <Product>Microsoft ASP.NET Core</Product>

View File

@@ -1,11 +1,12 @@
<Project> <Project>
<PropertyGroup> <PropertyGroup>
<AspNetCoreVersion>2.1.0-*</AspNetCoreVersion> <AspNetCoreVersion>2.0.0</AspNetCoreVersion>
<InternalAspNetCoreSdkVersion>2.1.1-*</InternalAspNetCoreSdkVersion> <AutoMapperVersion>5.0.2</AutoMapperVersion>
<InternalAspNetCoreSdkVersion>2.0.1-rtm-15400</InternalAspNetCoreSdkVersion>
<JsonNetVersion>10.0.1</JsonNetVersion> <JsonNetVersion>10.0.1</JsonNetVersion>
<NETStandardImplicitPackageVersion>2.0.0-*</NETStandardImplicitPackageVersion> <NETStandardImplicitPackageVersion>2.0.0</NETStandardImplicitPackageVersion>
<NETStandardLibraryNETFrameworkVersion>2.0.0-*</NETStandardLibraryNETFrameworkVersion> <NETStandardLibraryNETFrameworkVersion>2.0.0</NETStandardLibraryNETFrameworkVersion>
<RuntimeFrameworkVersion Condition="'$(TargetFramework)'=='netcoreapp2.0'">2.0.0-*</RuntimeFrameworkVersion> <RuntimeFrameworkVersion Condition="'$(TargetFramework)'=='netcoreapp2.0'">2.0.0</RuntimeFrameworkVersion>
<ThreadingDataflowVersion>4.8.0-*</ThreadingDataflowVersion> <ThreadingDataflowVersion>4.8.0</ThreadingDataflowVersion>
</PropertyGroup> </PropertyGroup>
</Project> </Project>

View File

@@ -21,6 +21,7 @@ namespace ConsoleApplication
// Since .NET Core 1.1, the HTTP hosting model has become basically as fast as the Socket hosting model // Since .NET Core 1.1, the HTTP hosting model has become basically as fast as the Socket hosting model
//options.UseSocketHosting(); //options.UseSocketHosting();
options.ProjectPath = Directory.GetCurrentDirectory();
options.WatchFileExtensions = new string[] {}; // Don't watch anything options.WatchFileExtensions = new string[] {}; // Don't watch anything
}); });
var serviceProvider = services.BuildServiceProvider(); var serviceProvider = services.BuildServiceProvider();

View File

@@ -1,6 +1,5 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO;
using System.Threading; using System.Threading;
using Microsoft.AspNetCore.NodeServices.HostingModels; using Microsoft.AspNetCore.NodeServices.HostingModels;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
@@ -35,18 +34,14 @@ namespace Microsoft.AspNetCore.NodeServices
InvocationTimeoutMilliseconds = DefaultInvocationTimeoutMilliseconds; InvocationTimeoutMilliseconds = DefaultInvocationTimeoutMilliseconds;
WatchFileExtensions = (string[])DefaultWatchFileExtensions.Clone(); WatchFileExtensions = (string[])DefaultWatchFileExtensions.Clone();
// In an ASP.NET environment, we can use the IHostingEnvironment data to auto-populate a few
// things that you'd otherwise have to specify manually
var hostEnv = serviceProvider.GetService<IHostingEnvironment>(); var hostEnv = serviceProvider.GetService<IHostingEnvironment>();
if (hostEnv != null) if (hostEnv != null)
{ {
// In an ASP.NET environment, we can use the IHostingEnvironment data to auto-populate a few
// things that you'd otherwise have to specify manually
ProjectPath = hostEnv.ContentRootPath; ProjectPath = hostEnv.ContentRootPath;
EnvironmentVariables["NODE_ENV"] = hostEnv.IsDevelopment() ? "development" : "production"; // De-facto standard values for Node EnvironmentVariables["NODE_ENV"] = hostEnv.IsDevelopment() ? "development" : "production"; // De-facto standard values for Node
} }
else
{
ProjectPath = Directory.GetCurrentDirectory();
}
var applicationLifetime = serviceProvider.GetService<IApplicationLifetime>(); var applicationLifetime = serviceProvider.GetService<IApplicationLifetime>();
if (applicationLifetime != null) if (applicationLifetime != null)

View File

@@ -50,7 +50,6 @@ namespace Microsoft.AspNetCore.NodeServices.HostingModels
options.DebuggingPort) options.DebuggingPort)
{ {
_client = new HttpClient(); _client = new HttpClient();
_client.Timeout = TimeSpan.FromMilliseconds(options.InvocationTimeoutMilliseconds + 1000);
} }
private static string MakeCommandLineOptions(int port) private static string MakeCommandLineOptions(int port)

View File

@@ -317,7 +317,7 @@ module.exports = {
## Hosting models ## Hosting models
NodeServices has a pluggable hosting/transport mechanism, because it is an abstraction over various possible ways to invoke Node.js from .NET. This allows more high-level facilities (e.g., for Angular prerendering) to be agnostic to the details of launching Node and communicating with it - those high-level facilities can just trust that *somehow* we can invoke code in Node for them. NodeServices has a pluggable hosting/transport mechanism, because it is an abstraction over various possible ways to invoke Node.js from .NET. This allows more high-level facilities (e.g., for Angular prerendering) to be agnostic to the details of launching Node and communicating it - those high-level facilities can just trust that *somehow* we can invoke code in Node for them.
Using this abstraction, we could run Node inside the .NET process, in a separate process on the same machine, or even on a different machine altogether. At the time of writing, all the built-in hosting mechanisms work by launching Node as a separate process on the same machine as your .NET code. Using this abstraction, we could run Node inside the .NET process, in a separate process on the same machine, or even on a different machine altogether. At the time of writing, all the built-in hosting mechanisms work by launching Node as a separate process on the same machine as your .NET code.

View File

@@ -4,7 +4,6 @@ using System.Threading;
using Microsoft.AspNetCore.NodeServices; using Microsoft.AspNetCore.NodeServices;
using Microsoft.AspNetCore.SpaServices.Webpack; using Microsoft.AspNetCore.SpaServices.Webpack;
using Newtonsoft.Json; using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
namespace Microsoft.AspNetCore.Builder namespace Microsoft.AspNetCore.Builder
{ {
@@ -15,12 +14,6 @@ namespace Microsoft.AspNetCore.Builder
{ {
private const string DefaultConfigFile = "webpack.config.js"; private const string DefaultConfigFile = "webpack.config.js";
private static readonly JsonSerializerSettings jsonSerializerSettings = new JsonSerializerSettings
{
ContractResolver = new CamelCasePropertyNamesContractResolver(),
TypeNameHandling = TypeNameHandling.None
};
/// <summary> /// <summary>
/// Enables Webpack dev middleware support. This hosts an instance of the Webpack compiler in memory /// Enables Webpack dev middleware support. This hosts an instance of the Webpack compiler in memory
/// in your application so that you can always serve up-to-date Webpack-built resources without having /// in your application so that you can always serve up-to-date Webpack-built resources without having
@@ -94,7 +87,7 @@ namespace Microsoft.AspNetCore.Builder
}; };
var devServerInfo = var devServerInfo =
nodeServices.InvokeExportAsync<WebpackDevServerInfo>(nodeScript.FileName, "createWebpackDevServer", nodeServices.InvokeExportAsync<WebpackDevServerInfo>(nodeScript.FileName, "createWebpackDevServer",
JsonConvert.SerializeObject(devServerOptions, jsonSerializerSettings)).Result; JsonConvert.SerializeObject(devServerOptions)).Result;
// If we're talking to an older version of aspnet-webpack, it will return only a single PublicPath, // If we're talking to an older version of aspnet-webpack, it will return only a single PublicPath,
// not an array of PublicPaths. Handle that scenario. // not an array of PublicPaths. Handle that scenario.

View File

@@ -1,5 +0,0 @@
/node_modules/
**/*.js
**/*.d.ts
**/*.metadata.json
/compiled

View File

@@ -1,3 +0,0 @@
!/*.js
!/*.d.ts
/compiled

View File

@@ -1,12 +0,0 @@
Copyright (c) .NET Foundation. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License"); you may not use
these files except in compliance with the License. You may obtain a copy of the
License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied. See the License for the
specific language governing permissions and limitations under the License.

View File

@@ -1,33 +0,0 @@
{
"name": "aspnet-angular",
"version": "0.1.1",
"description": "Helpers for using Angular in ASP.NET Core projects",
"main": "index.js",
"scripts": {
"prepublish": "rimraf *.d.ts && ngc && echo 'Finished building NPM package \"aspnet-angular\"'",
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "https://github.com/aspnet/JavaScriptServices.git"
},
"author": "Microsoft",
"license": "Apache-2.0",
"bugs": {
"url": "https://github.com/aspnet/JavaScriptServices/issues"
},
"devDependencies": {
"@angular/common": "^4.3.2",
"@angular/compiler": "^4.3.2",
"@angular/compiler-cli": "^4.3.2",
"@angular/core": "^4.3.2",
"@angular/http": "^4.3.2",
"@angular/platform-browser": "^4.3.2",
"rimraf": "^2.6.1",
"rxjs": "^5.4.2",
"zone.js": "^0.8.16"
},
"peerDependencies": {
"@angular/core": "^4.2.5 || ^5.0.0-beta"
}
}

View File

@@ -1,94 +0,0 @@
import { Provider, NgModule, Inject } from '@angular/core';
import { Headers, Http, ResponseOptions, RequestOptionsArgs, Response } from '@angular/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/of';
import 'rxjs/add/operator/map';
const globalSerializedStateKey = 'HTTP_STATE_TRANSFER';
const backingStoreDIToken = 'HTTP_STATE_BACKING_STORE';
export interface CacheOptions {
permanent: boolean;
}
export interface CachedHttpResponse {
headers: { [name: string]: any } | null;
status: number;
statusText: string | null;
text: string;
url: string;
}
export type BackingStore = { [key: string]: CachedHttpResponse };
export class HttpWithStateTransfer {
private backingStore: BackingStore;
private http: Http;
constructor(@Inject(Http) http: Http, @Inject(backingStoreDIToken) backingStore: BackingStore) {
this.http = http;
this.backingStore = backingStore;
}
public stateForTransfer(): any {
return { [globalSerializedStateKey]: this.backingStore };
}
public get(url: string, options?: CacheOptions, requestOptions?: RequestOptionsArgs): Observable<Response> {
return this.getCachedResponse(/* cacheKey */ url, () => this.http.get(url, requestOptions), options);
}
private getCachedResponse(cacheKey: string, provider: () => Observable<Response>, options?: CacheOptions): Observable<Response> {
// By default, the cache is only used for the *first* client-side read. So, we're only performing
// a one-time transfer of server-side response to the client. If you want to keep and reuse cached
// responses continually during server-side and client-side execution, set 'permanent' to 'true.
const isClient = typeof window !== 'undefined';
const isPermanent = options && options.permanent;
const allowReadFromCache = isClient || isPermanent;
if (allowReadFromCache && this.backingStore.hasOwnProperty(cacheKey)) {
const cachedValue = this.backingStore[cacheKey];
if (!isPermanent) {
delete this.backingStore[cacheKey];
}
return Observable.of(new Response(new ResponseOptions({
body: cachedValue.text,
headers: new Headers(cachedValue.headers),
status: cachedValue.status,
url: cachedValue.url
})));
}
return provider()
.map(response => {
const allowWriteToCache = !isClient || isPermanent;
if (allowWriteToCache) {
this.backingStore[cacheKey] = {
headers: response.headers ? response.headers.toJSON() : null,
status: response.status,
statusText: response.statusText,
text: response.text(),
url: response.url
};
}
return response;
});
}
}
export function defaultBackingStoreFactory() {
const transferredData = typeof window !== 'undefined' ? (window as any)[globalSerializedStateKey] : null;
return transferredData || {};
}
@NgModule({
providers: [
// The backing store is a separate DI service so you could override exactly how it gets
// transferred from server to client
{ provide: backingStoreDIToken, useFactory: defaultBackingStoreFactory },
{ provide: HttpWithStateTransfer, useClass: HttpWithStateTransfer },
]
})
export class HttpWithStateTransferModule {
}

View File

@@ -1 +0,0 @@
export * from './HttpWithStateTransfer';

View File

@@ -1,20 +0,0 @@
{
"compilerOptions": {
"experimentalDecorators": true,
"moduleResolution": "node",
"module": "commonjs",
"target": "es5",
"declaration": true,
"outDir": ".",
"lib": ["es2015", "dom"]
},
"files": [
"src/index.ts"
],
"exclude": [
"node_modules"
],
"angularCompilerOptions": {
"genDir": "compiled"
}
}

View File

@@ -1,6 +1,6 @@
{ {
"name": "aspnet-prerendering", "name": "aspnet-prerendering",
"version": "3.0.1", "version": "2.0.6",
"description": "Helpers for server-side rendering of JavaScript applications in ASP.NET Core projects. Works in conjunction with the Microsoft.AspNetCore.SpaServices NuGet package.", "description": "Helpers for server-side rendering of JavaScript applications in ASP.NET Core projects. Works in conjunction with the Microsoft.AspNetCore.SpaServices NuGet package.",
"main": "index.js", "main": "index.js",
"scripts": { "scripts": {
@@ -17,7 +17,7 @@
"url": "https://github.com/aspnet/JavaScriptServices.git" "url": "https://github.com/aspnet/JavaScriptServices.git"
}, },
"dependencies": { "dependencies": {
"domain-task": "^3.0.0" "domain-task": "^2.0.2"
}, },
"devDependencies": { "devDependencies": {
"@types/node": "^6.0.42", "@types/node": "^6.0.42",

View File

@@ -26,7 +26,6 @@ export function createServerRenderer(bootFunc: BootFunc): RenderToStringFunc {
domainTasks: domainTaskCompletionPromise, domainTasks: domainTaskCompletionPromise,
data: customDataParameter data: customDataParameter
}; };
const absoluteBaseUrl = params.origin + params.baseUrl; // Should be same value as page's <base href>
// Open a new domain that can track all the async tasks involved in the app's execution // Open a new domain that can track all the async tasks involved in the app's execution
domainTaskRun(/* code to run */ () => { domainTaskRun(/* code to run */ () => {
@@ -36,7 +35,7 @@ export function createServerRenderer(bootFunc: BootFunc): RenderToStringFunc {
bindPromiseContinuationsToDomain(domainTaskCompletionPromise, domain['active']); bindPromiseContinuationsToDomain(domainTaskCompletionPromise, domain['active']);
// Make the base URL available to the 'domain-tasks/fetch' helper within this execution context // Make the base URL available to the 'domain-tasks/fetch' helper within this execution context
domainTaskBaseUrl(absoluteBaseUrl); domainTaskBaseUrl(absoluteRequestUrl);
// Begin rendering, and apply a timeout // Begin rendering, and apply a timeout
const bootFuncPromise = bootFunc(params); const bootFuncPromise = bootFunc(params);

View File

@@ -1,6 +1,6 @@
{ {
"name": "aspnet-webpack-react", "name": "aspnet-webpack-react",
"version": "3.0.0", "version": "3.0.0-beta.1",
"description": "Helpers for using Webpack with React in ASP.NET Core projects. Works in conjunction with the Microsoft.AspNetCore.SpaServices NuGet package.", "description": "Helpers for using Webpack with React in ASP.NET Core projects. Works in conjunction with the Microsoft.AspNetCore.SpaServices NuGet package.",
"main": "index.js", "main": "index.js",
"scripts": { "scripts": {

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
{ {
"name": "aspnet-webpack", "name": "aspnet-webpack",
"version": "2.0.1", "version": "1.0.29",
"description": "Helpers for using Webpack in ASP.NET Core projects. Works in conjunction with the Microsoft.AspNetCore.SpaServices NuGet package.", "description": "Helpers for using Webpack in ASP.NET Core projects. Works in conjunction with the Microsoft.AspNetCore.SpaServices NuGet package.",
"main": "index.js", "main": "index.js",
"scripts": { "scripts": {

View File

@@ -5,11 +5,11 @@ import * as fs from 'fs';
import * as path from 'path'; import * as path from 'path';
import * as querystring from 'querystring'; import * as querystring from 'querystring';
import { requireNewCopy } from './RequireNewCopy'; import { requireNewCopy } from './RequireNewCopy';
import { hasSufficientPermissions } from './WebpackTestPermissions';
export type CreateDevServerResult = { export type CreateDevServerResult = {
Port: number, Port: number,
PublicPaths: string[] PublicPaths: string[],
PublicPath: string // For backward compatibility with older verions of Microsoft.AspNetCore.SpaServices. Will be removed soon.
}; };
export interface CreateDevServerCallback { export interface CreateDevServerCallback {
@@ -108,7 +108,7 @@ function attachWebpackDevMiddleware(app: any, webpackConfig: webpack.Configurati
const compiler = webpack(webpackConfig); const compiler = webpack(webpackConfig);
app.use(require('webpack-dev-middleware')(compiler, { app.use(require('webpack-dev-middleware')(compiler, {
noInfo: true, noInfo: true,
publicPath: ensureLeadingSlash(webpackConfig.output.publicPath), publicPath: webpackConfig.output.publicPath,
watchOptions: webpackConfig.watchOptions watchOptions: webpackConfig.watchOptions
})); }));
@@ -195,14 +195,6 @@ function copyRecursiveToRealFsSync(from: typeof fs, rootDir: string, exclude: Re
}); });
} }
function ensureLeadingSlash(value: string) {
if (value !== null && value.substring(0, 1) !== '/') {
value = '/' + value;
}
return value;
}
function pathJoinSafe(rootPath: string, filePath: string) { function pathJoinSafe(rootPath: string, filePath: string) {
// On Windows, MemoryFileSystem's readdirSync output produces directory entries like 'C:' // On Windows, MemoryFileSystem's readdirSync output produces directory entries like 'C:'
// which then trigger errors if you call statSync for them. Avoid this by detecting drive // which then trigger errors if you call statSync for them. Avoid this by detecting drive
@@ -224,16 +216,6 @@ function beginWebpackWatcher(webpackConfig: webpack.Configuration) {
export function createWebpackDevServer(callback: CreateDevServerCallback, optionsJson: string) { export function createWebpackDevServer(callback: CreateDevServerCallback, optionsJson: string) {
const options: CreateDevServerOptions = JSON.parse(optionsJson); const options: CreateDevServerOptions = JSON.parse(optionsJson);
// See the large comment in WebpackTestPermissions.ts for details about this
if (!hasSufficientPermissions()) {
console.log('WARNING: Webpack dev middleware is not enabled because the server process does not have sufficient permissions. You should either remove the UseWebpackDevMiddleware call from your code, or to make it work, give your server process user account permission to write to your application directory and to read all ancestor-level directories.');
callback(null, {
Port: 0,
PublicPaths: []
});
return;
}
// Read the webpack config's export, and normalize it into the more general 'array of configs' format // Read the webpack config's export, and normalize it into the more general 'array of configs' format
let webpackConfigExport: WebpackConfigFileExport = requireNewCopy(options.webpackConfigPath); let webpackConfigExport: WebpackConfigFileExport = requireNewCopy(options.webpackConfigPath);
if (webpackConfigExport instanceof Function) { if (webpackConfigExport instanceof Function) {
@@ -275,32 +257,22 @@ export function createWebpackDevServer(callback: CreateDevServerCallback, option
if (!publicPath) { if (!publicPath) {
throw new Error('To use the Webpack dev server, you must specify a value for \'publicPath\' on the \'output\' section of your webpack config (for any configuration that targets browsers)'); throw new Error('To use the Webpack dev server, you must specify a value for \'publicPath\' on the \'output\' section of your webpack config (for any configuration that targets browsers)');
} }
const publicPathNoTrailingSlash = removeTrailingSlash(publicPath); normalizedPublicPaths.push(removeTrailingSlash(publicPath));
normalizedPublicPaths.push(publicPathNoTrailingSlash);
// This is the URL the client will connect to, except that since it's a relative URL // Newer versions of Microsoft.AspNetCore.SpaServices will explicitly pass an HMR endpoint URL
// (no leading slash), Webpack will resolve it against the runtime <base href> URL // (because it's relative to the app's URL space root, which the client doesn't otherwise know).
// plus it also adds the publicPath // For back-compatibility, fall back on connecting directly to the underlying HMR server (though
const hmrClientEndpoint = removeLeadingSlash(options.hotModuleReplacementEndpointUrl); // that won't work if the app is hosted on HTTPS because of the mixed-content rule, and we can't
// run the HMR server itself on HTTPS because in general it has no valid cert).
// This is the URL inside the Webpack middleware Node server that we'll proxy to. const hmrClientEndpoint = options.hotModuleReplacementEndpointUrl // The URL that we'll proxy (e.g., /__asp_webpack_hmr)
// We have to prefix with the public path because Webpack will add the publicPath || `http://localhost:${listener.address().port}/__webpack_hmr`; // Fall back on absolute URL to bypass proxying
// when it resolves hmrClientEndpoint as a relative URL. const hmrServerEndpoint = options.hotModuleReplacementEndpointUrl
const hmrServerEndpoint = ensureLeadingSlash(publicPathNoTrailingSlash + options.hotModuleReplacementEndpointUrl); || '/__webpack_hmr'; // URL is relative to webpack dev server root
// We always overwrite the 'path' option as it needs to match what the .NET side is expecting // We always overwrite the 'path' option as it needs to match what the .NET side is expecting
const hmrClientOptions = options.suppliedOptions.HotModuleReplacementClientOptions || <StringMap<string>>{}; const hmrClientOptions = options.suppliedOptions.HotModuleReplacementClientOptions || <StringMap<string>>{};
hmrClientOptions['path'] = hmrClientEndpoint; hmrClientOptions['path'] = hmrClientEndpoint;
const dynamicPublicPathKey = 'dynamicPublicPath';
if (!(dynamicPublicPathKey in hmrClientOptions)) {
// dynamicPublicPath default to true, so we can work with nonempty pathbases (virtual directories)
hmrClientOptions[dynamicPublicPathKey] = true;
} else {
// ... but you can set it to any other value explicitly if you want (e.g., false)
hmrClientOptions[dynamicPublicPathKey] = JSON.parse(hmrClientOptions[dynamicPublicPathKey]);
}
attachWebpackDevMiddleware(app, webpackConfig, enableHotModuleReplacement, enableReactHotModuleReplacement, hmrClientOptions, hmrServerEndpoint); attachWebpackDevMiddleware(app, webpackConfig, enableHotModuleReplacement, enableReactHotModuleReplacement, hmrClientOptions, hmrServerEndpoint);
} }
}); });
@@ -308,7 +280,11 @@ export function createWebpackDevServer(callback: CreateDevServerCallback, option
// Tell the ASP.NET app what addresses we're listening on, so that it can proxy requests here // Tell the ASP.NET app what addresses we're listening on, so that it can proxy requests here
callback(null, { callback(null, {
Port: listener.address().port, Port: listener.address().port,
PublicPaths: normalizedPublicPaths PublicPaths: normalizedPublicPaths,
// For back-compatibility with older versions of Microsoft.AspNetCore.SpaServices, in the case where
// you have exactly one webpackConfigArray entry. This will be removed soon.
PublicPath: normalizedPublicPaths[0]
}); });
} catch (ex) { } catch (ex) {
callback(ex.stack, null); callback(ex.stack, null);
@@ -316,14 +292,6 @@ export function createWebpackDevServer(callback: CreateDevServerCallback, option
}); });
} }
function removeLeadingSlash(str: string) {
if (str.indexOf('/') === 0) {
str = str.substring(1);
}
return str;
}
function removeTrailingSlash(str: string) { function removeTrailingSlash(str: string) {
if (str.lastIndexOf('/') === str.length - 1) { if (str.lastIndexOf('/') === str.length - 1) {
str = str.substring(0, str.length - 1); str = str.substring(0, str.length - 1);

View File

@@ -1,58 +0,0 @@
import * as fs from 'fs';
import * as path from 'path';
const isWindows = /^win/.test(process.platform);
// On Windows, Node (still as of v8.1.3) has an issue whereby, when locating JavaScript modules
// on disk, it walks up the directory hierarchy to the disk root, testing whether each directory
// is a symlink or not. This fails with an exception if the process doesn't have permission to
// read those directories. This is a problem when hosting in full IIS, because in typical cases
// the process does not have read permission for higher-level directories.
//
// NodeServices itself works around this by injecting a patched version of Node's 'lstat' API that
// suppresses these irrelevant errors during module loads. This covers most scenarios, but isn't
// enough to make Webpack dev middleware work, because typical Webpack configs use loaders such as
// 'awesome-typescript-loader', which works by forking a child process to do some of its work. The
// child process does not get the patched 'lstat', and hence fails. It's an especially bad failure,
// because the Webpack compiler doesn't even surface the exception - it just never completes the
// compilation process, causing the application to hang indefinitely.
//
// Additionally, Webpack dev middleware will want to write its output to disk, which is also going
// to fail in a typical IIS process, because you won't have 'write' permission to the app dir by
// default. We have to actually write the build output to disk (and not purely keep it in the in-
// memory file system) because the server-side prerendering Node instance is a separate process
// that only knows about code changes when it sees the compiled files on disk change.
//
// In the future, we'll hopefully get Node to fix its underlying issue, and figure out whether VS
// could give 'write' access to the app dir when launching sites in IIS. But until then, disable
// Webpack dev middleware if we detect the server process doesn't have the necessary permissions.
export function hasSufficientPermissions() {
if (isWindows) {
return canReadDirectoryAndAllAncestors(process.cwd());
} else {
return true;
}
}
function canReadDirectoryAndAllAncestors(dir: string): boolean {
if (!canReadDirectory(dir)) {
return false;
}
const parentDir = path.resolve(dir, '..');
if (parentDir === dir) {
// There are no more parent directories - we've reached the disk root
return true;
} else {
return canReadDirectoryAndAllAncestors(parentDir);
}
}
function canReadDirectory(dir: string): boolean {
try {
fs.statSync(dir);
return true;
} catch(ex) {
return false;
}
}

View File

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@@ -9,17 +9,17 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup Condition="'$(TargetFrameworkOverride)' == ''"> <ItemGroup Condition="'$(TargetFrameworkOverride)' == ''">
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.0" /> <PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.0-rtm-26190" />
</ItemGroup> </ItemGroup>
<ItemGroup Condition="'$(TargetFrameworkOverride)' != ''"> <ItemGroup Condition="'$(TargetFrameworkOverride)' != ''">
<PackageReference Include="Microsoft.AspNetCore" Version="2.0.0" /> <PackageReference Include="Microsoft.AspNetCore" Version="2.0.0-rtm-26190" />
<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.0.0" /> <PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.0.0-rtm-26190" />
<PackageReference Include="Microsoft.AspNetCore.SpaServices" Version="2.0.0" /> <PackageReference Include="Microsoft.AspNetCore.SpaServices" Version="2.0.0-rtm-26190" />
<PackageReference Include="Microsoft.AspNetCore.StaticFiles" Version="2.0.0" /> <PackageReference Include="Microsoft.AspNetCore.StaticFiles" Version="2.0.0-rtm-26190" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<DotNetCliToolReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Tools" Version="2.0.0" /> <DotNetCliToolReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Tools" Version="2.0.0-rtm-26190" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@@ -2,22 +2,20 @@ import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser'; import { BrowserModule } from '@angular/platform-browser';
import { AppModuleShared } from './app.module.shared'; import { AppModuleShared } from './app.module.shared';
import { AppComponent } from './components/app/app.component'; import { AppComponent } from './components/app/app.component';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
@NgModule({ @NgModule({
bootstrap: [ AppComponent ], bootstrap: [ AppComponent ],
imports: [ imports: [
BrowserModule, BrowserModule,
AppModuleShared, AppModuleShared
BrowserAnimationsModule
], ],
providers: [ providers: [
{ provide: 'BASE_URL', useFactory: getBaseUrl } { provide: 'ORIGIN_URL', useFactory: getOriginUrl }
] ]
}) })
export class AppModule { export class AppModule {
} }
export function getBaseUrl() { export function getOriginUrl() {
return document.getElementsByTagName('base')[0].href; return location.origin;
} }

View File

@@ -2,14 +2,12 @@ import { NgModule } from '@angular/core';
import { ServerModule } from '@angular/platform-server'; import { ServerModule } from '@angular/platform-server';
import { AppModuleShared } from './app.module.shared'; import { AppModuleShared } from './app.module.shared';
import { AppComponent } from './components/app/app.component'; import { AppComponent } from './components/app/app.component';
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
@NgModule({ @NgModule({
bootstrap: [ AppComponent ], bootstrap: [ AppComponent ],
imports: [ imports: [
ServerModule, ServerModule,
AppModuleShared, AppModuleShared
NoopAnimationsModule
] ]
}) })
export class AppModule { export class AppModule {

View File

@@ -14,7 +14,7 @@
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<tr *ngFor="let forecast of forecasts" [@itemAnim]> <tr *ngFor="let forecast of forecasts">
<td>{{ forecast.dateFormatted }}</td> <td>{{ forecast.dateFormatted }}</td>
<td>{{ forecast.temperatureC }}</td> <td>{{ forecast.temperatureC }}</td>
<td>{{ forecast.temperatureF }}</td> <td>{{ forecast.temperatureF }}</td>

View File

@@ -0,0 +1,23 @@
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('ORIGIN_URL') originUrl: string) {
http.get(originUrl + '/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;
}

View File

@@ -11,6 +11,6 @@
<li><strong>Client-side navigation</strong>. For example, click <em>Counter</em> then <em>Back</em> to return here.</li> <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>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>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>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> <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> </ul>

View File

@@ -7,7 +7,7 @@
<span class='icon-bar'></span> <span class='icon-bar'></span>
<span class='icon-bar'></span> <span class='icon-bar'></span>
</button> </button>
<a class='navbar-brand' [routerLink]="['/home']">AngularSpa</a> <a class='navbar-brand' [routerLink]="['/home']">WebApplicationBasic</a>
</div> </div>
<div class='clearfix'></div> <div class='clearfix'></div>
<div class='navbar-collapse collapse'> <div class='navbar-collapse collapse'>

View File

@@ -5,13 +5,13 @@ import { enableProdMode } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app/app.module.browser'; import { AppModule } from './app/app.module.browser';
if (module.hot) { if (module['hot']) {
module.hot.accept(); module['hot'].accept();
module.hot.dispose(() => { module['hot'].dispose(() => {
// Before restarting the app, we create a new root element and dispose the old one // Before restarting the app, we create a new root element and dispose the old one
const oldRootElem = document.querySelector('app'); const oldRootElem = document.querySelector('app');
const newRootElem = document.createElement('app'); const newRootElem = document.createElement('app');
oldRootElem!.parentNode!.insertBefore(newRootElem, oldRootElem); oldRootElem.parentNode.insertBefore(newRootElem, oldRootElem);
modulePromise.then(appModule => appModule.destroy()); modulePromise.then(appModule => appModule.destroy());
}); });
} else { } else {

View File

@@ -1,7 +1,6 @@
import 'reflect-metadata'; import 'reflect-metadata';
import 'zone.js'; import 'zone.js';
import 'rxjs/add/operator/first'; import 'rxjs/add/operator/first';
import { APP_BASE_HREF } from '@angular/common';
import { enableProdMode, ApplicationRef, NgZone, ValueProvider } from '@angular/core'; import { enableProdMode, ApplicationRef, NgZone, ValueProvider } from '@angular/core';
import { platformDynamicServer, PlatformState, INITIAL_CONFIG } from '@angular/platform-server'; import { platformDynamicServer, PlatformState, INITIAL_CONFIG } from '@angular/platform-server';
import { createServerRenderer, RenderResult } from 'aspnet-prerendering'; import { createServerRenderer, RenderResult } from 'aspnet-prerendering';
@@ -12,17 +11,16 @@ enableProdMode();
export default createServerRenderer(params => { export default createServerRenderer(params => {
const providers = [ const providers = [
{ provide: INITIAL_CONFIG, useValue: { document: '<app></app>', url: params.url } }, { provide: INITIAL_CONFIG, useValue: { document: '<app></app>', url: params.url } },
{ provide: APP_BASE_HREF, useValue: params.baseUrl }, { provide: 'ORIGIN_URL', useValue: params.origin }
{ provide: 'BASE_URL', useValue: params.origin + params.baseUrl },
]; ];
return platformDynamicServer(providers).bootstrapModule(AppModule).then(moduleRef => { return platformDynamicServer(providers).bootstrapModule(AppModule).then(moduleRef => {
const appRef: ApplicationRef = moduleRef.injector.get(ApplicationRef); const appRef = moduleRef.injector.get(ApplicationRef);
const state = moduleRef.injector.get(PlatformState); const state = moduleRef.injector.get(PlatformState);
const zone = moduleRef.injector.get(NgZone); const zone = moduleRef.injector.get(NgZone);
return new Promise<RenderResult>((resolve, reject) => { return new Promise<RenderResult>((resolve, reject) => {
zone.onError.subscribe((errorInfo: any) => reject(errorInfo)); zone.onError.subscribe(errorInfo => reject(errorInfo));
appRef.isStable.first(isStable => isStable).subscribe(() => { appRef.isStable.first(isStable => isStable).subscribe(() => {
// Because 'onStable' fires before 'onError', we have to delay slightly before // Because 'onStable' fires before 'onError', we have to delay slightly before
// completing the request in case there's an error to report // completing the request in case there's an error to report

View File

@@ -5,7 +5,7 @@ using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
namespace AureliaSpa.Controllers namespace WebApplicationBasic.Controllers
{ {
public class HomeController : Controller public class HomeController : Controller
{ {

View File

@@ -4,7 +4,7 @@ using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
namespace KnockoutSpa.Controllers namespace WebApplicationBasic.Controllers
{ {
[Route("api/[controller]")] [Route("api/[controller]")]
public class SampleDataController : Controller public class SampleDataController : Controller

View File

@@ -8,7 +8,7 @@ using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
namespace VueSpa namespace WebApplicationBasic
{ {
public class Program public class Program
{ {

View File

@@ -8,7 +8,7 @@ using Microsoft.AspNetCore.SpaServices.Webpack;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
namespace KnockoutSpa namespace WebApplicationBasic
{ {
public class Startup public class Startup
{ {

View File

@@ -3,7 +3,7 @@
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>@ViewData["Title"] - AngularSpa</title> <title>@ViewData["Title"] - WebApplicationBasic</title>
<base href="~/" /> <base href="~/" />
<link rel="stylesheet" href="~/dist/vendor.css" asp-append-version="true" /> <link rel="stylesheet" href="~/dist/vendor.css" asp-append-version="true" />

View File

@@ -1,3 +1,3 @@
@using AureliaSpa @using WebApplicationBasic
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@addTagHelper *, Microsoft.AspNetCore.SpaServices @addTagHelper *, Microsoft.AspNetCore.SpaServices

View File

@@ -1,5 +1,5 @@
{ {
"name": "AngularSpa", "name": "WebApplicationBasic",
"version": "0.0.0", "version": "0.0.0",
"dependencies": { "dependencies": {
"@angular/animations": { "@angular/animations": {
@@ -93,10 +93,10 @@
"resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-2.5.53.tgz", "resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-2.5.53.tgz",
"dev": true "dev": true
}, },
"@types/webpack-env": { "@types/node": {
"version": "1.13.0", "version": "8.0.8",
"from": "@types/webpack-env@1.13.0", "from": "@types/node@8.0.8",
"resolved": "https://registry.npmjs.org/@types/webpack-env/-/webpack-env-1.13.0.tgz" "resolved": "https://registry.npmjs.org/@types/node/-/node-8.0.8.tgz"
}, },
"accepts": { "accepts": {
"version": "1.3.3", "version": "1.3.3",
@@ -274,14 +274,14 @@
"resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.9.1.tgz" "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.9.1.tgz"
}, },
"aspnet-prerendering": { "aspnet-prerendering": {
"version": "3.0.1", "version": "2.0.6",
"from": "aspnet-prerendering@3.0.1", "from": "aspnet-prerendering@>=2.0.5 <3.0.0",
"resolved": "https://registry.npmjs.org/aspnet-prerendering/-/aspnet-prerendering-3.0.1.tgz" "resolved": "https://registry.npmjs.org/aspnet-prerendering/-/aspnet-prerendering-2.0.6.tgz"
}, },
"aspnet-webpack": { "aspnet-webpack": {
"version": "2.0.1", "version": "1.0.29",
"from": "aspnet-webpack@2.0.1", "from": "aspnet-webpack@>=1.0.29 <2.0.0",
"resolved": "https://registry.npmjs.org/aspnet-webpack/-/aspnet-webpack-2.0.1.tgz" "resolved": "https://registry.npmjs.org/aspnet-webpack/-/aspnet-webpack-1.0.29.tgz"
}, },
"assert": { "assert": {
"version": "1.4.1", "version": "1.4.1",
@@ -932,9 +932,9 @@
"resolved": "https://registry.npmjs.org/domain-context/-/domain-context-0.5.1.tgz" "resolved": "https://registry.npmjs.org/domain-context/-/domain-context-0.5.1.tgz"
}, },
"domain-task": { "domain-task": {
"version": "3.0.3", "version": "2.0.3",
"from": "domain-task@>=3.0.0 <4.0.0", "from": "domain-task@>=2.0.2 <3.0.0",
"resolved": "https://registry.npmjs.org/domain-task/-/domain-task-3.0.3.tgz" "resolved": "https://registry.npmjs.org/domain-task/-/domain-task-2.0.3.tgz"
}, },
"ee-first": { "ee-first": {
"version": "1.1.1", "version": "1.1.1",

View File

@@ -1,11 +1,11 @@
{ {
"name": "AngularSpa", "name": "WebApplicationBasic",
"private": true, "private": true,
"version": "0.0.0", "version": "0.0.0",
"scripts": { "scripts": {
"test": "karma start ClientApp/test/karma.conf.js" "test": "karma start ClientApp/test/karma.conf.js"
}, },
"devDependencies": { "dependencies": {
"@angular/animations": "4.2.5", "@angular/animations": "4.2.5",
"@angular/common": "4.2.5", "@angular/common": "4.2.5",
"@angular/compiler": "4.2.5", "@angular/compiler": "4.2.5",
@@ -18,16 +18,12 @@
"@angular/platform-server": "4.2.5", "@angular/platform-server": "4.2.5",
"@angular/router": "4.2.5", "@angular/router": "4.2.5",
"@ngtools/webpack": "1.5.0", "@ngtools/webpack": "1.5.0",
"@types/chai": "4.0.1", "@types/node": "8.0.8",
"@types/jasmine": "2.5.53",
"@types/webpack-env": "1.13.0",
"angular2-router-loader": "0.3.5",
"angular2-template-loader": "0.6.2", "angular2-template-loader": "0.6.2",
"aspnet-prerendering": "^3.0.1", "aspnet-prerendering": "^2.0.5",
"aspnet-webpack": "^2.0.1", "aspnet-webpack": "^1.0.29",
"awesome-typescript-loader": "3.2.1", "awesome-typescript-loader": "3.2.1",
"bootstrap": "3.3.7", "bootstrap": "3.3.7",
"chai": "4.0.2",
"css": "2.2.1", "css": "2.2.1",
"css-loader": "0.28.4", "css-loader": "0.28.4",
"es6-shim": "0.35.3", "es6-shim": "0.35.3",
@@ -37,15 +33,8 @@
"file-loader": "0.11.2", "file-loader": "0.11.2",
"html-loader": "0.4.5", "html-loader": "0.4.5",
"isomorphic-fetch": "2.2.1", "isomorphic-fetch": "2.2.1",
"jasmine-core": "2.6.4",
"jquery": "3.2.1", "jquery": "3.2.1",
"json-loader": "0.5.4", "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", "preboot": "4.5.2",
"raw-loader": "0.5.1", "raw-loader": "0.5.1",
"reflect-metadata": "0.1.10", "reflect-metadata": "0.1.10",
@@ -58,5 +47,17 @@
"webpack-hot-middleware": "2.18.2", "webpack-hot-middleware": "2.18.2",
"webpack-merge": "4.1.0", "webpack-merge": "4.1.0",
"zone.js": "0.8.12" "zone.js": "0.8.12"
},
"devDependencies": {
"@types/chai": "4.0.1",
"@types/jasmine": "2.5.53",
"chai": "4.0.2",
"jasmine-core": "2.6.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"
} }
} }

View File

@@ -1,16 +1,13 @@
{ {
"compilerOptions": { "compilerOptions": {
"module": "es2015",
"moduleResolution": "node", "moduleResolution": "node",
"target": "es5", "target": "es5",
"sourceMap": true, "sourceMap": true,
"experimentalDecorators": true, "experimentalDecorators": true,
"emitDecoratorMetadata": true, "emitDecoratorMetadata": true,
"skipDefaultLibCheck": 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" ], "lib": [ "es6", "dom" ],
"types": [ "webpack-env" ] "types": [ "node" ]
}, },
"exclude": [ "bin", "node_modules" ], "exclude": [ "bin", "node_modules" ],
"atom": { "rewriteTsconfig": false } "atom": { "rewriteTsconfig": false }

View File

@@ -13,11 +13,11 @@ module.exports = (env) => {
resolve: { extensions: [ '.js', '.ts' ] }, resolve: { extensions: [ '.js', '.ts' ] },
output: { output: {
filename: '[name].js', filename: '[name].js',
publicPath: 'dist/' // Webpack dev middleware, if enabled, handles requests for this URL prefix publicPath: '/dist/' // Webpack dev middleware, if enabled, handles requests for this URL prefix
}, },
module: { module: {
rules: [ rules: [
{ test: /\.ts$/, use: isDevBuild ? ['awesome-typescript-loader?silent=true', 'angular2-template-loader', 'angular2-router-loader'] : '@ngtools/webpack' }, { test: /\.ts$/, include: /ClientApp/, use: isDevBuild ? ['awesome-typescript-loader?silent=true', 'angular2-template-loader'] : '@ngtools/webpack' },
{ test: /\.html$/, use: 'html-loader?minimize=false' }, { test: /\.html$/, use: 'html-loader?minimize=false' },
{ test: /\.css$/, use: [ 'to-string-loader', isDevBuild ? 'css-loader' : 'css-loader?minimize' ] }, { test: /\.css$/, use: [ 'to-string-loader', isDevBuild ? 'css-loader' : 'css-loader?minimize' ] },
{ test: /\.(png|jpg|jpeg|gif|svg)$/, use: 'url-loader?limit=25000' } { test: /\.(png|jpg|jpeg|gif|svg)$/, use: 'url-loader?limit=25000' }

View File

@@ -36,7 +36,7 @@ module.exports = (env) => {
] ]
}, },
output: { output: {
publicPath: 'dist/', publicPath: '/dist/',
filename: '[name].js', filename: '[name].js',
library: '[name]_[hash]' library: '[name]_[hash]'
}, },

View File

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 31 KiB

View File

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

@@ -9,17 +9,17 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup Condition="'$(TargetFrameworkOverride)' == ''"> <ItemGroup Condition="'$(TargetFrameworkOverride)' == ''">
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.0" /> <PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.0-rtm-26190" />
</ItemGroup> </ItemGroup>
<ItemGroup Condition="'$(TargetFrameworkOverride)' != ''"> <ItemGroup Condition="'$(TargetFrameworkOverride)' != ''">
<PackageReference Include="Microsoft.AspNetCore" Version="2.0.0" /> <PackageReference Include="Microsoft.AspNetCore" Version="2.0.0-rtm-26190" />
<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.0.0" /> <PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.0.0-rtm-26190" />
<PackageReference Include="Microsoft.AspNetCore.SpaServices" Version="2.0.0" /> <PackageReference Include="Microsoft.AspNetCore.SpaServices" Version="2.0.0-rtm-26190" />
<PackageReference Include="Microsoft.AspNetCore.StaticFiles" Version="2.0.0" /> <PackageReference Include="Microsoft.AspNetCore.StaticFiles" Version="2.0.0-rtm-26190" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<DotNetCliToolReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Tools" Version="2.0.0" /> <DotNetCliToolReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Tools" Version="2.0.0-*" />
</ItemGroup> </ItemGroup>
<!--/-:cnd:noEmit --> <!--/-:cnd:noEmit -->

View File

@@ -6,7 +6,7 @@ export class Fetchdata {
public forecasts: WeatherForecast[]; public forecasts: WeatherForecast[];
constructor(http: HttpClient) { constructor(http: HttpClient) {
http.fetch('api/SampleData/WeatherForecasts') http.fetch('/api/SampleData/WeatherForecasts')
.then(result => result.json() as Promise<WeatherForecast[]>) .then(result => result.json() as Promise<WeatherForecast[]>)
.then(data => { .then(data => {
this.forecasts = data; this.forecasts = data;

View File

@@ -9,7 +9,7 @@
<span class="icon-bar"></span> <span class="icon-bar"></span>
<span class="icon-bar"></span> <span class="icon-bar"></span>
</button> </button>
<a class="navbar-brand" href="#/home">AureliaSpa</a> <a class="navbar-brand" href="#/home">WebApplicationBasic</a>
</div> </div>
<div class="clearfix"></div> <div class="clearfix"></div>
<div class="navbar-collapse collapse"> <div class="navbar-collapse collapse">

View File

@@ -1,6 +1,5 @@
import 'isomorphic-fetch'; import 'isomorphic-fetch';
import { Aurelia, PLATFORM } from 'aurelia-framework'; import { Aurelia, PLATFORM } from 'aurelia-framework';
import { HttpClient } from 'aurelia-fetch-client';
import 'bootstrap/dist/css/bootstrap.css'; import 'bootstrap/dist/css/bootstrap.css';
import 'bootstrap'; import 'bootstrap';
declare const IS_DEV_BUILD: boolean; // The value is supplied by Webpack during the build declare const IS_DEV_BUILD: boolean; // The value is supplied by Webpack during the build
@@ -12,10 +11,5 @@ export function configure(aurelia: Aurelia) {
aurelia.use.developmentLogging(); aurelia.use.developmentLogging();
} }
new HttpClient().configure(config => {
const baseUrl = document.getElementsByTagName('base')[0].href;
config.withBaseUrl(baseUrl);
});
aurelia.start().then(() => aurelia.setRoot(PLATFORM.moduleName('app/components/app/app'))); aurelia.start().then(() => aurelia.setRoot(PLATFORM.moduleName('app/components/app/app')));
} }

View File

@@ -5,7 +5,7 @@ using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
namespace KnockoutSpa.Controllers namespace WebApplicationBasic.Controllers
{ {
public class HomeController : Controller public class HomeController : Controller
{ {

View File

@@ -4,7 +4,7 @@ using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
namespace AureliaSpa.Controllers namespace WebApplicationBasic.Controllers
{ {
[Route("api/[controller]")] [Route("api/[controller]")]
public class SampleDataController : Controller public class SampleDataController : Controller

View File

@@ -8,7 +8,7 @@ using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
namespace AureliaSpa namespace WebApplicationBasic
{ {
public class Program public class Program
{ {

View File

@@ -8,7 +8,7 @@ using Microsoft.AspNetCore.SpaServices.Webpack;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
namespace VueSpa namespace WebApplicationBasic
{ {
public class Startup public class Startup
{ {

View File

@@ -3,7 +3,7 @@
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>@ViewData["Title"] - AureliaSpa</title> <title>@ViewData["Title"] - WebApplicationBasic</title>
<base href="~/" /> <base href="~/" />
<link rel="stylesheet" href="~/dist/vendor.css" asp-append-version="true" /> <link rel="stylesheet" href="~/dist/vendor.css" asp-append-version="true" />

View File

@@ -1,3 +1,3 @@
@using KnockoutSpa @using WebApplicationBasic
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@addTagHelper *, Microsoft.AspNetCore.SpaServices @addTagHelper *, Microsoft.AspNetCore.SpaServices

View File

@@ -1,11 +1,11 @@
{ {
"name": "AureliaSpa", "name": "WebApplicationBasic",
"version": "0.0.0", "version": "0.0.0",
"dependencies": { "dependencies": {
"@types/webpack-env": { "@types/node": {
"version": "1.13.0", "version": "7.0.32",
"from": "@types/webpack-env@>=1.13.0 <2.0.0", "from": "@types/node@>=7.0.12 <8.0.0",
"resolved": "https://registry.npmjs.org/@types/webpack-env/-/webpack-env-1.13.0.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-7.0.32.tgz",
"dev": true "dev": true
}, },
"acorn": { "acorn": {
@@ -113,9 +113,9 @@
"dev": true "dev": true
}, },
"aspnet-webpack": { "aspnet-webpack": {
"version": "2.0.1", "version": "1.0.29",
"from": "aspnet-webpack@2.0.1", "from": "aspnet-webpack@>=1.0.28 <2.0.0",
"resolved": "https://registry.npmjs.org/aspnet-webpack/-/aspnet-webpack-2.0.1.tgz", "resolved": "https://registry.npmjs.org/aspnet-webpack/-/aspnet-webpack-1.0.29.tgz",
"dev": true "dev": true
}, },
"assert": { "assert": {

View File

@@ -1,24 +1,26 @@
{ {
"name": "AureliaSpa", "name": "WebApplicationBasic",
"private": true, "private": true,
"version": "0.0.0", "version": "0.0.0",
"devDependencies": { "dependencies": {
"@types/webpack-env": "^1.13.0",
"aspnet-webpack": "^2.0.1",
"aurelia-bootstrapper": "^2.0.1", "aurelia-bootstrapper": "^2.0.1",
"aurelia-fetch-client": "^1.0.1", "aurelia-fetch-client": "^1.0.1",
"aurelia-framework": "^1.1.0", "aurelia-framework": "^1.1.0",
"aurelia-loader-webpack": "^2.0.0", "aurelia-loader-webpack": "^2.0.0",
"aurelia-pal": "^1.3.0", "aurelia-pal": "^1.3.0",
"aurelia-router": "^1.2.1", "aurelia-router": "^1.2.1",
"aurelia-webpack-plugin": "^2.0.0-rc.2",
"bootstrap": "^3.3.7", "bootstrap": "^3.3.7",
"isomorphic-fetch": "^2.2.1",
"jquery": "^3.2.1"
},
"devDependencies": {
"@types/node": "^7.0.12",
"aspnet-webpack": "^1.0.28",
"aurelia-webpack-plugin": "^2.0.0-rc.2",
"css-loader": "^0.28.0", "css-loader": "^0.28.0",
"extract-text-webpack-plugin": "^2.1.0", "extract-text-webpack-plugin": "^2.1.0",
"file-loader": "^0.11.1", "file-loader": "^0.11.1",
"html-loader": "^0.4.5", "html-loader": "^0.4.5",
"isomorphic-fetch": "^2.2.1",
"jquery": "^3.2.1",
"json-loader": "^0.5.4", "json-loader": "^0.5.4",
"style-loader": "^0.16.1", "style-loader": "^0.16.1",
"ts-loader": "^2.0.3", "ts-loader": "^2.0.3",

View File

@@ -1,15 +1,13 @@
{ {
"compilerOptions": { "compilerOptions": {
"module": "es2015",
"moduleResolution": "node", "moduleResolution": "node",
"target": "es5", "target": "es5",
"sourceMap": true, "sourceMap": true,
"experimentalDecorators": true, "experimentalDecorators": true,
"emitDecoratorMetadata": true, "emitDecoratorMetadata": true,
"skipDefaultLibCheck": true, "skipDefaultLibCheck": true,
"strict": true,
"lib": [ "es2015", "dom" ], "lib": [ "es2015", "dom" ],
"types": [ "webpack-env" ] "types": [ "node" ]
}, },
"exclude": [ "bin", "node_modules" ], "exclude": [ "bin", "node_modules" ],
"atom": { "rewriteTsconfig": false } "atom": { "rewriteTsconfig": false }

View File

@@ -14,7 +14,7 @@ module.exports = (env) => {
}, },
output: { output: {
path: path.resolve(bundleOutputDir), path: path.resolve(bundleOutputDir),
publicPath: 'dist/', publicPath: '/dist/',
filename: '[name].js' filename: '[name].js'
}, },
module: { module: {

View File

@@ -38,7 +38,7 @@ module.exports = ({ prod } = {}) => {
}, },
output: { output: {
path: path.join(__dirname, 'wwwroot', 'dist'), path: path.join(__dirname, 'wwwroot', 'dist'),
publicPath: 'dist/', publicPath: '/dist/',
filename: '[name].js', filename: '[name].js',
library: '[name]_[hash]', library: '[name]_[hash]',
}, },

View File

Before

Width:  |  Height:  |  Size: 83 KiB

After

Width:  |  Height:  |  Size: 83 KiB

View File

Before

Width:  |  Height:  |  Size: 6.0 KiB

After

Width:  |  Height:  |  Size: 6.0 KiB

View File

@@ -1,20 +1,19 @@
import './css/site.css'; import './css/site.css';
import 'bootstrap'; import 'bootstrap';
import * as ko from 'knockout'; import * as ko from 'knockout';
import { createBrowserHistory } from 'history';
import './webpack-component-loader'; import './webpack-component-loader';
import AppRootComponent from './components/app-root/app-root'; import AppRootComponent from './components/app-root/app-root';
const baseUrl = document.getElementsByTagName('base')[0].getAttribute('href')!; const createHistory = require('history').createBrowserHistory;
const basename = baseUrl.substring(0, baseUrl.length - 1); // History component needs no trailing slash
// Load and register the <app-root> component // Load and register the <app-root> component
ko.components.register('app-root', AppRootComponent); ko.components.register('app-root', AppRootComponent);
// Tell Knockout to start up an instance of your application // Tell Knockout to start up an instance of your application
ko.applyBindings({ history: createBrowserHistory({ basename }), basename }); ko.applyBindings({ history: createHistory() });
// Basic hot reloading support. Automatically reloads and restarts the Knockout app each time // Basic hot reloading support. Automatically reloads and restarts the Knockout app each time
// you modify source files. This will not preserve any application state other than the URL. // you modify source files. This will not preserve any application state other than the URL.
declare var module: any;
if (module.hot) { if (module.hot) {
module.hot.accept(); module.hot.accept();
module.hot.dispose(() => ko.cleanNode(document.body)); module.hot.dispose(() => ko.cleanNode(document.body));

Some files were not shown because too many files have changed in this diff Show More