Compare commits

..

63 Commits

Author SHA1 Message Date
SteveSandersonMS
135e264ae2 Example of adding font-awesome 2016-09-28 11:02:04 +01:00
SteveSandersonMS
e87aa1f088 Change Angular2Spa template to build server (prerendering) bundle explicitly. This simplifies deployment, fixes various compatibility issues (like #306) and makes debugging much easier for developers using the template. 2016-09-28 10:55:45 +01:00
SteveSandersonMS
30dfe5e8b5 In Angular2Spa webpack config, use "--env.prod" arg to trigger prod builds instead of ASPNETCORE_ENVIRONMENT env var. This is to guarantee production mode when publishing. 2016-09-28 10:04:16 +01:00
SteveSandersonMS
46966322b7 In LoadViaWebpack, account for CSS/font/etc files referenced with URLs that have a querystring. Fixes #335. 2016-09-28 10:04:16 +01:00
SteveSandersonMS
adf4732191 Make aspnet-webpack and SpaServices both back-compatible with older versions of the other, in case people don't upgrade both at the same time 2016-09-28 10:04:02 +01:00
SteveSandersonMS
7b227229b3 In Webpack dev middleware, for configs that target Node, just run a 'watch' compiler (since Node isn't going to fetch the modules via HTTP anyway) 2016-09-28 10:00:59 +01:00
SteveSandersonMS
2241c55a90 Support for array-style webpack configs in aspnet-webpack. Fixes #291. 2016-09-28 10:00:59 +01:00
SteveSandersonMS
85eba9ca27 Add README.md for generator-aspnetcore-spa. Fixes #308. 2016-09-27 11:05:01 +01:00
SteveSandersonMS
46906e4ea8 Add repo info to package.json in all NPM packages hosted in this repo 2016-09-27 11:00:41 +01:00
SteveSandersonMS
57265509f7 Rebuild entrypoint-socket.js 2016-09-27 10:47:14 +01:00
SteveSandersonMS
7e88903bcc Fix Node event chaining in VirtualConnectionServer to work with latest NPM libraries. Fixes #331. 2016-09-27 10:28:50 +01:00
SteveSandersonMS
67fc64309f Update Angular 2 Music Store sample to declare dependency on .NET Core 1.0.1 2016-09-27 10:28:01 +01:00
SteveSandersonMS
5a9d3cb189 Update readme to mention dependency on .NET Core 1.0.1 2016-09-27 10:13:03 +01:00
SteveSandersonMS
f79936c104 In Angular2Spa webpack config, allow html/css files from node_modules to be loaded via Webpack. 2016-09-27 10:03:54 +01:00
SteveSandersonMS
e8594287db In aspnet-webpack, make sure that webpack-externals-plugin doesn't treat non-JS files as external. Fixes #332. 2016-09-27 09:59:51 +01:00
SteveSandersonMS
b55e444a55 Also print CWD in node 'require' error reports 2016-09-21 11:43:12 +01:00
SteveSandersonMS
9aaa519044 Bump Yeoman package version to 0.3.0 2016-09-21 11:22:01 +01:00
SteveSandersonMS
f9807c546d In SpaServices NuGet package, pass through error stack when NPM modules fail to load 2016-09-21 11:11:24 +01:00
SteveSandersonMS
232e908ce8 Pass through error stack when NPM module loading failed in aspnet-webpack and aspnet-prerendering to make debugging easier 2016-09-21 11:08:04 +01:00
SteveSandersonMS
5214a553a7 In Angular2Spa, server-side rendering now reports all errors 2016-09-21 09:29:13 +01:00
SteveSandersonMS
2ba5a0ac93 As per #325, reference module.hot directly instead of via a local var, because Webpack does static analysis that looks for this 2016-09-20 16:51:50 +01:00
SteveSandersonMS
925f47fece In Angular2Spa, use css-loader so you can reference external images from CSS files, etc. 2016-09-20 16:13:25 +01:00
SteveSandersonMS
80343e9f17 In aspnet-webpack, replace ExternalsPlugin with webpack-node-externals because of #132 2016-09-20 15:41:06 +01:00
SteveSandersonMS
f7ef36bc74 Remove redundant section of docs 2016-09-20 11:00:48 +01:00
SteveSandersonMS
50be444440 Update docs to describe using LESS with Angular 2 component styling 2016-09-20 10:57:17 +01:00
SteveSandersonMS
19684f2b7d In Angular2Spa template, use per-component scoped styles. Fixes common config issues like #234. 2016-09-20 10:06:23 +01:00
SteveSandersonMS
cd18489f00 Fix HMR again following previous change 2016-09-19 17:40:17 +01:00
SteveSandersonMS
41f1f6fe82 Delay Angular 2 bootstrapping until DOMContentLoaded 2016-09-19 16:56:50 +01:00
SteveSandersonMS
ca99a2304c Remove style-loader from Angular2Spa vendor bundle as it's not used at all. Is used by other templates though. 2016-09-19 16:53:20 +01:00
SteveSandersonMS
83cfb59c2d Add comment about UniversalModule 2016-09-19 16:10:57 +01:00
SteveSandersonMS
494c7b585c Fix trailing whitespace 2016-09-19 16:05:22 +01:00
SteveSandersonMS
49a8536679 Update angular2-universal dependencies (cherry-pick 62dd13b3b) 2016-09-19 15:51:18 +01:00
SteveSandersonMS
358ee2261e Make indentation consistent 2016-09-19 15:43:58 +01:00
SteveSandersonMS
07a9c1685f Remove unnecessary NPM dependencies 2016-09-19 14:15:13 +01:00
SteveSandersonMS
4ea7eb195e Simplify webpack config. Eliminate dev/prod override files. 2016-09-19 14:13:20 +01:00
SteveSandersonMS
85dfdd9b50 Move tsconfig into ClientApp dir, since it's not needed at root 2016-09-19 14:04:00 +01:00
SteveSandersonMS
a91b6a6b5c Make HMR work again 2016-09-19 13:50:26 +01:00
SteveSandersonMS
a1c1bdb1e6 Simplify imports in boot-client.ts 2016-09-19 13:18:44 +01:00
SteveSandersonMS
297b4dbd92 Move more modules to vendor bundle. Remove explicit reflect-metadata reference (no longer needed). 2016-09-19 13:09:12 +01:00
SteveSandersonMS
8f550c5706 Simplify Angular 2 template where possible 2016-09-19 12:44:25 +01:00
SteveSandersonMS
243a9b4ef6 Add @types/node to avoid intellisense errors for "require" statements 2016-09-19 11:05:44 +01:00
SteveSandersonMS
1e08548aa0 Remove now-redundant 'typings' dir and custom-typings.d.ts 2016-09-19 10:33:02 +01:00
Mark Pieszak
ce0d2089d2 ng2 2.0, Universal 2.0, TS 2.0, Preboot 4.* 2016-09-19 09:12:03 +01:00
SteveSandersonMS
b71d139eb5 Update xproj files to reference dotnet build tooling 2016-09-15 14:36:42 +01:00
SteveSandersonMS
2ee0078cfd Fix HttpNodeInstanceEntryPoint to match latest NPM modules 2016-09-15 14:15:03 +01:00
SteveSandersonMS
591d548de7 Publish new Yeoman templates (0.2.9) 2016-09-15 12:34:24 +01:00
SteveSandersonMS
06ad36f830 In Angular 2 template, include prebuilt wwwroot/dist/* files to support VS and "dotnet new" templates (which can't run post-project-creation actions) 2016-09-15 12:32:01 +01:00
SteveSandersonMS
7a80d905b8 In Angular 2 template, include reflect-metadata and zone.js in vendor bundle 2016-09-15 12:07:49 +01:00
SteveSandersonMS
d76b013a56 WebpackDevMiddleware now uses ProjectPath option consistently. Fixes #307 2016-09-14 12:04:15 +01:00
SteveSandersonMS
7c316d5c74 Update to ASP.NET Core 1.0.1. Fixes #309 2016-09-14 11:36:53 +01:00
SteveSandersonMS
b72435c5cc Yeoman generator support for optional --projectguid=... CLI argument 2016-09-13 13:57:23 +01:00
SteveSandersonMS
7f841ff840 In Yeoman generator, support passing args from command line (e.g., --framework=angular-2) 2016-09-13 13:44:51 +01:00
SteveSandersonMS
80f740a9ed Revert "Webpack HMR EventSource requests are now proxied (rather than redirected) to the local HMR server" because of 'ECANCELED'/'EPIPE broken pipe' issues. Awaiting feedback from Kestrel team. 2016-09-13 12:51:23 +01:00
SteveSandersonMS
f071590fce Webpack HMR EventSource requests are now proxied (rather than redirected) to the local HMR server. Fixes #271. 2016-09-09 16:31:15 +01:00
SteveSandersonMS
bc2de2ad59 In aspnet-webpack HMR, don't rely on assumption that entry point is called 'main'. Fixes #289. 2016-09-09 13:21:31 +01:00
SteveSandersonMS
605090e909 Publish updated version of aspnet-webpack as 1.0.10 2016-09-09 11:37:57 +01:00
Erik Medina
67f7e7450f Adding tsd to dev dependencies in aspnet-webpack.
Adding tsd to aspnet-webpack's dev dependencies to allow the package's npm prepublish script to succeed without a global tsd install.
2016-09-09 11:34:43 +01:00
Erik Medina
da662c55fa Make webpack dev dependency a peer dependency in aspnet-webpack.
Moving webpack from a dev dependency to a peer dependency makes the dependency soft and allows the webpack-dev-middleware to pickup the version of webpack being used by the consumer of the package.
2016-09-09 11:34:43 +01:00
SteveSandersonMS
b4bec30b0f Clean up dependencies vs devDependencies in templates 2016-09-09 11:31:36 +01:00
SteveSandersonMS
28550784ed ReactReduxSpa's boot-server now supports redirections issued by react-router 2016-09-09 11:12:59 +01:00
SteveSandersonMS
1be9102aea Prerendering server-side code can now issue redirections. Fixes #280 2016-09-09 11:09:44 +01:00
SteveSandersonMS
c2c45b04df In preparation for supporting redirections, aspnet-prerendering now passes through all boot func resolution props to .NET code 2016-09-09 11:06:36 +01:00
Steve Sanderson
874575ba92 Fix instructions for running samples. Fixes #301 2016-09-09 09:44:16 +01:00
85 changed files with 728 additions and 2558 deletions

1
.gitignore vendored
View File

@@ -36,4 +36,5 @@ npm-debug.log
# repo have to be excluded here. # repo have to be excluded here.
/templates/*/node_modules/ /templates/*/node_modules/
/templates/*/wwwroot/dist/ /templates/*/wwwroot/dist/
/templates/*/ClientApp/dist/
.vscode/ .vscode/

View File

@@ -20,7 +20,7 @@ This repo contains:
* A Yeoman generator that creates preconfigured app starting points ([guide](http://blog.stevensanderson.com/2016/05/02/angular2-react-knockout-apps-on-aspnet-core/)) * A Yeoman generator that creates preconfigured app starting points ([guide](http://blog.stevensanderson.com/2016/05/02/angular2-react-knockout-apps-on-aspnet-core/))
* Samples and docs * Samples and docs
Everything here is cross-platform, and works with .NET Core 1.0 (RTM) or later on Windows, Linux, or OS X. Everything here is cross-platform, and works with .NET Core 1.0.1 or later on Windows, Linux, or OS X.
## Creating new applications ## Creating new applications
@@ -69,8 +69,9 @@ Also in this repo, [the `samples` directory](https://github.com/aspnet/JavaScrip
**To run the samples:** **To run the samples:**
* Clone this repo * Clone this repo
* Change directory to the same you want to run (e.g., `cd samples/angular/MusicStore`) * At the repo's root directory (the one containing `src`, `samples`, etc.), run `dotnet restore`
* Restore dependencies (run `dotnet restore` and `npm install`). * Change directory to the sample you want to run (e.g., `cd samples/angular/MusicStore`)
* Restore Node dependencies by running `npm install`
* If you're trying to run the Angular 2 "Music Store" sample, then also run `gulp` (which you need to have installed globally). None of the other samples require this. * If you're trying to run the Angular 2 "Music Store" sample, then also run `gulp` (which you need to have installed globally). None of the other samples require this.
* Run the application (`dotnet run`) * Run the application (`dotnet run`)
* Browse to [http://localhost:5000](http://localhost:5000) * Browse to [http://localhost:5000](http://localhost:5000)

View File

@@ -5,52 +5,75 @@
"preserveCompilationContext": true "preserveCompilationContext": true
}, },
"runtimeOptions": { "runtimeOptions": {
"gcServer": true "configProperties": {
"System.GC.Server": true
}
}, },
"tooling": { "tooling": {
"defaultNamespace": "MusicStore" "defaultNamespace": "MusicStore"
}, },
"dependencies": { "dependencies": {
"Microsoft.NETCore.App": { "Microsoft.NETCore.App": {
"version": "1.0.0", "version": "1.0.1",
"type": "platform" "type": "platform"
}, },
"Microsoft.AspNetCore.AngularServices": "1.0.0-*",
"Microsoft.AspNetCore.Diagnostics": "1.0.0", "Microsoft.AspNetCore.Diagnostics": "1.0.0",
"Microsoft.AspNetCore.Identity.EntityFrameworkCore": "1.0.0", "Microsoft.AspNetCore.Identity.EntityFrameworkCore": "1.0.0",
"Microsoft.AspNetCore.Mvc": "1.0.1",
"Microsoft.AspNetCore.Razor.Tools": {
"version": "1.0.0-preview2-final",
"type": "build"
},
"Microsoft.AspNetCore.Server.IISIntegration": "1.0.0", "Microsoft.AspNetCore.Server.IISIntegration": "1.0.0",
"Microsoft.AspNetCore.Mvc": "1.0.0", "Microsoft.AspNetCore.Server.Kestrel": "1.0.1",
"Microsoft.AspNetCore.Mvc.TagHelpers": "1.0.0",
"Microsoft.AspNetCore.Server.Kestrel": "1.0.0",
"Microsoft.AspNetCore.StaticFiles": "1.0.0", "Microsoft.AspNetCore.StaticFiles": "1.0.0",
"Microsoft.Extensions.Configuration.Json": "1.0.0",
"Microsoft.Extensions.Logging.Console": "1.0.0",
"Microsoft.NETCore.Platforms": "1.0.1",
"Microsoft.Extensions.Logging.Debug": "1.0.0",
"Microsoft.EntityFrameworkCore.SQLite": "1.0.0", "Microsoft.EntityFrameworkCore.SQLite": "1.0.0",
"Microsoft.AspNetCore.AngularServices": "1.0.0-*", "Microsoft.Extensions.Configuration.EnvironmentVariables": "1.0.0",
"AutoMapper": "5.0.2" "Microsoft.Extensions.Configuration.Json": "1.0.0",
"Microsoft.Extensions.Configuration.CommandLine": "1.0.0",
"Microsoft.Extensions.Logging": "1.0.0",
"Microsoft.Extensions.Logging.Console": "1.0.0",
"Microsoft.Extensions.Logging.Debug": "1.0.0",
"Microsoft.Extensions.Options.ConfigurationExtensions": "1.0.0",
"AutoMapper": "5.0.2"
}, },
"tools": {
"Microsoft.AspNetCore.Razor.Tools": "1.0.0-preview2-final",
"Microsoft.AspNetCore.Server.IISIntegration.Tools": "1.0.0-preview2-final",
"Microsoft.DotNet.Watcher.Tools": "1.0.0-preview2-final"
},
"frameworks": { "frameworks": {
"netcoreapp1.0": { "netcoreapp1.0": {
"imports": [ "imports": [
"dotnet5.6", "dotnet5.6",
"dnxcore50",
"portable-net45+win8" "portable-net45+win8"
] ]
} }
}, },
"publishOptions": { "publishOptions": {
"exclude": [ "include": [
"appsettings.json",
"ClientApp",
"node_modules", "node_modules",
"bower_components", "typings",
"**.xproj", "Views",
"**.user", "tsconfig.json",
"**.vspscc" "tsd.json",
"web.config",
"webpack.*.js",
"wwwroot"
] ]
}, },
"scripts": { "scripts": {
"prepublish": [ "npm install" ], "prepublish": [
"npm install",
"gulp"
],
"postpublish": [ "dotnet publish-iis --publish-folder %publish:OutputPath% --framework %publish:FullTargetFramework%" ] "postpublish": [ "dotnet publish-iis --publish-folder %publish:OutputPath% --framework %publish:FullTargetFramework%" ]
} }
} }

View File

@@ -10,6 +10,13 @@
"typings": "dist/Exports", "typings": "dist/Exports",
"author": "Microsoft", "author": "Microsoft",
"license": "Apache-2.0", "license": "Apache-2.0",
"bugs": {
"url": "https://github.com/aspnet/JavaScriptServices/issues"
},
"repository": {
"type": "git",
"url": "https://github.com/aspnet/JavaScriptServices.git"
},
"dependencies": { "dependencies": {
"angular2": "^2.0.0-beta.13", "angular2": "^2.0.0-beta.13",
"rxjs": "5.0.0-beta.2" "rxjs": "5.0.0-beta.2"

View File

@@ -9,7 +9,7 @@
"defaultNamespace": "Microsoft.AspNetCore.AngularServices" "defaultNamespace": "Microsoft.AspNetCore.AngularServices"
}, },
"dependencies": { "dependencies": {
"Microsoft.AspNetCore.Mvc.TagHelpers": "1.0.0", "Microsoft.AspNetCore.Mvc.TagHelpers": "1.0.1",
"Microsoft.AspNetCore.SpaServices": "1.0.0-*" "Microsoft.AspNetCore.SpaServices": "1.0.0-*"
}, },
"frameworks": { "frameworks": {

View File

@@ -128,9 +128,8 @@
ExitWhenParentExits_1.exitWhenParentExits(parseInt(parsedArgs.parentPid)); ExitWhenParentExits_1.exitWhenParentExits(parseInt(parsedArgs.parentPid));
function readRequestBodyAsJson(request, callback) { function readRequestBodyAsJson(request, callback) {
var requestBodyAsString = ''; var requestBodyAsString = '';
request request.on('data', function (chunk) { requestBodyAsString += chunk; });
.on('data', function (chunk) { requestBodyAsString += chunk; }) request.on('end', function () { callback(JSON.parse(requestBodyAsString)); });
.on('end', function () { callback(JSON.parse(requestBodyAsString)); });
} }
function respondWithError(res, errorValue) { function respondWithError(res, errorValue) {
res.statusCode = 500; res.statusCode = 500;

View File

@@ -376,11 +376,12 @@
_this._sendFrame(header.connectionIdBinary, data, writeCompletedCallback); _this._sendFrame(header.connectionIdBinary, data, writeCompletedCallback);
} }
}; };
var newVirtualConnection = new VirtualConnection_1.VirtualConnection(beginWriteCallback) var newVirtualConnection = new VirtualConnection_1.VirtualConnection(beginWriteCallback);
.on('end', function () { newVirtualConnection.on('end', function () {
// The virtual connection was closed remotely. Clean up locally. // The virtual connection was closed remotely. Clean up locally.
_this._onVirtualConnectionWasClosed(header.connectionIdString); _this._onVirtualConnectionWasClosed(header.connectionIdString);
}).on('finish', function () { });
newVirtualConnection.on('finish', function () {
// The virtual connection was closed locally. Clean up locally, and notify the remote that we're done. // The virtual connection was closed locally. Clean up locally, and notify the remote that we're done.
_this._onVirtualConnectionWasClosed(header.connectionIdString); _this._onVirtualConnectionWasClosed(header.connectionIdString);
_this._sendFrame(header.connectionIdBinary, new Buffer(0)); _this._sendFrame(header.connectionIdBinary, new Buffer(0));

View File

@@ -80,9 +80,8 @@ exitWhenParentExits(parseInt(parsedArgs.parentPid));
function readRequestBodyAsJson(request, callback) { function readRequestBodyAsJson(request, callback) {
let requestBodyAsString = ''; let requestBodyAsString = '';
request request.on('data', chunk => { requestBodyAsString += chunk; });
.on('data', chunk => { requestBodyAsString += chunk; }) request.on('end', () => { callback(JSON.parse(requestBodyAsString)); });
.on('end', () => { callback(JSON.parse(requestBodyAsString)); });
} }
function respondWithError(res: http.ServerResponse, errorValue: any) { function respondWithError(res: http.ServerResponse, errorValue: any) {

View File

@@ -105,15 +105,16 @@ class VirtualConnectionsCollection {
} }
}; };
const newVirtualConnection = new VirtualConnection(beginWriteCallback) const newVirtualConnection = new VirtualConnection(beginWriteCallback);
.on('end', () => { newVirtualConnection.on('end', () => {
// The virtual connection was closed remotely. Clean up locally. // The virtual connection was closed remotely. Clean up locally.
this._onVirtualConnectionWasClosed(header.connectionIdString); this._onVirtualConnectionWasClosed(header.connectionIdString);
}).on('finish', () => { });
// The virtual connection was closed locally. Clean up locally, and notify the remote that we're done. newVirtualConnection.on('finish', () => {
this._onVirtualConnectionWasClosed(header.connectionIdString); // The virtual connection was closed locally. Clean up locally, and notify the remote that we're done.
this._sendFrame(header.connectionIdBinary, new Buffer(0)); this._onVirtualConnectionWasClosed(header.connectionIdString);
}); this._sendFrame(header.connectionIdBinary, new Buffer(0));
});
this._virtualConnections[header.connectionIdString] = newVirtualConnection; this._virtualConnections[header.connectionIdString] = newVirtualConnection;
this._onVirtualConnectionCallback(newVirtualConnection); this._onVirtualConnectionCallback(newVirtualConnection);

View File

@@ -10,6 +10,13 @@
}, },
"author": "Microsoft", "author": "Microsoft",
"license": "Apache-2.0", "license": "Apache-2.0",
"bugs": {
"url": "https://github.com/aspnet/JavaScriptServices/issues"
},
"repository": {
"type": "git",
"url": "https://github.com/aspnet/JavaScriptServices.git"
},
"devDependencies": { "devDependencies": {
"rimraf": "^2.5.4", "rimraf": "^2.5.4",
"typescript": "^1.8.10" "typescript": "^1.8.10"

View File

@@ -9,7 +9,7 @@
"defaultNamespace": "Microsoft.AspNetCore.ReactServices" "defaultNamespace": "Microsoft.AspNetCore.ReactServices"
}, },
"dependencies": { "dependencies": {
"Microsoft.AspNetCore.Mvc.TagHelpers": "1.0.0", "Microsoft.AspNetCore.Mvc.TagHelpers": "1.0.1",
"Microsoft.AspNetCore.SpaServices": "1.0.0-*" "Microsoft.AspNetCore.SpaServices": "1.0.0-*"
}, },
"frameworks": { "frameworks": {

View File

@@ -4,7 +4,15 @@ module.exports.renderToString = function (callback) {
try { try {
aspNetPrerendering = require('aspnet-prerendering'); aspNetPrerendering = require('aspnet-prerendering');
} catch (ex) { } catch (ex) {
callback('To use prerendering, you must install the \'aspnet-prerendering\' NPM package.'); // Developers sometimes have trouble with badly-configured Node installations, where it's unable
// to find node_modules. Or they accidentally fail to deploy node_modules, or even to run 'npm install'.
// Make sure such errors are reported back to the .NET part of the app.
callback(
'Prerendering failed because of an error while loading \'aspnet-prerendering\'. Error was: '
+ ex.stack
+ '\nCurrent directory is: '
+ process.cwd()
);
return; return;
} }

View File

@@ -4,7 +4,15 @@ module.exports.createWebpackDevServer = function (callback) {
try { try {
aspNetWebpack = require('aspnet-webpack'); aspNetWebpack = require('aspnet-webpack');
} catch (ex) { } catch (ex) {
callback('To use webpack dev middleware, you must install the \'aspnet-webpack\' NPM package.'); // Developers sometimes have trouble with badly-configured Node installations, where it's unable
// to find node_modules. Or they accidentally fail to deploy node_modules, or even to run 'npm install'.
// Make sure such errors are reported back to the .NET part of the app.
callback(
'Webpack dev middleware failed because of an error while loading \'aspnet-webpack\'. Error was: '
+ ex.stack
+ '\nCurrent directory is: '
+ process.cwd()
);
return; return;
} }

View File

@@ -85,6 +85,15 @@ namespace Microsoft.AspNetCore.SpaServices.Prerendering
unencodedPathAndQuery, unencodedPathAndQuery,
CustomDataParameter, CustomDataParameter,
TimeoutMillisecondsParameter); TimeoutMillisecondsParameter);
if (!string.IsNullOrEmpty(result.RedirectUrl))
{
// It's a redirection
ViewContext.HttpContext.Response.Redirect(result.RedirectUrl);
return;
}
// It's some HTML to inject
output.Content.SetHtmlContent(result.Html); output.Content.SetHtmlContent(result.Html);
// Also attach any specified globals to the 'window' object. This is useful for transferring // Also attach any specified globals to the 'window' object. This is useful for transferring

View File

@@ -6,5 +6,6 @@ namespace Microsoft.AspNetCore.SpaServices.Prerendering
{ {
public JObject Globals { get; set; } public JObject Globals { get; set; }
public string Html { get; set; } public string Html { get; set; }
public string RedirectUrl { get; set; }
} }
} }

View File

@@ -378,17 +378,64 @@ So that's enough to build TypeScript. Here's where webpack dev middleware comes
### Example: A simple Webpack setup that builds LESS ### Example: A simple Webpack setup that builds LESS
Following on from the preceding example that builds TypeScript, you could extend your Webpack configuration further to support building LESS. There are two major approaches to doing this: Following on from the preceding example that builds TypeScript, you could extend your Webpack configuration further to support building LESS. There are three major approaches to doing this:
1. **Have each build embed the style information into your JavaScript code**. At runtime, Webpack can dynamically attach the styles to your document via JavaScript. This has certain benefits during development. 1. **If using Angular 2, use its native style loader to attach the styles to components**. This is extremely simple and is usually the right choice if you are using Angular 2. However it only applies to Angular 2 components, not to any other part of the host page, so sometimes you might want to combine this technique with options 2 or 3 below.
2. **Or, have each build write a standalone `.css` file to disk**. At runtime, load it using a regular `<link rel='stylesheet'>` tag. This is likely to be the approach you'll want for production use as it's the most robust and best-performing option. 2. **Or, use Webpack's style loader to attach the styles at runtime**. The CSS markup will be included in your JavaScript bundles and will be attached to the document dynamically. This has certain benefits during development but isn't recommended in production.
3. **Or, have each build write a standalone `.css` file to disk**. At runtime, load it using a regular `<link rel='stylesheet'>` tag. This is likely to be the approach you'll want for production use (at least for non-Angular 2 applications, such as React applications) as it's the most robust and best-performing option.
If instead of LESS you prefer SASS or another CSS preprocessor, the exact same techniques should work, but of course you'll need to replace the `less-loader` with an equivalent Webpack loader for SASS or your chosen preprocessor. If instead of LESS you prefer SASS or another CSS preprocessor, the exact same techniques should work, but of course you'll need to replace the `less-loader` with an equivalent Webpack loader for SASS or your chosen preprocessor.
#### Approach 1: Loading the styles using JavaScript #### Approach 1: Scoping styles to Angular 2 components
This technique is a little simpler to set up than technique 2, plus it works flawlessly with Hot Module Replacement (HMR). The downside is that it's really only good for development time, because in production you probably don't want users to wait until JavaScript is loaded before styles are applied to the page (this would mean they'd see a 'flash of unstyled content' while the page is being loaded). If you are using Angular 2, this is the easiest way to perform styling. It works with both server and client rendering, supports Hot Module Replacement, and robustly scopes styles to particular components (and optionally, their descendant elements).
This repository's Angular 2 template uses this technique to scope styles to components out of the box. It defines those styles as `.css` files. For example, its components reference `.css` files like this:
```javascript
@Component({
...
styles: [require('./somecomponent.css')]
})
export class SomeComponent { ... }
```
To make this work, the template has Webpack configured to inject the contents of the `.css` file as a string literal in the built file. Here's the configuration that enables this:
```javascript
// This goes into webpack.config.js, in the module loaders array:
{ test: /\.css/, include: /ClientApp/, loader: 'raw' }
```
Now if you want to use LESS instead of plain CSS, you just need to include a LESS loader. Run the following in a command prompt at your project root:
```
npm install --save less-loader less
```
Next, add the following loader configuration to the `loaders` array in `webpack.config.js`:
```javascript
{ test: /\.less/, include: /ClientApp/, loader: 'raw!less' }
```
Notice how this chains together the `less` loader (which transforms `.less` syntax to plain CSS syntax), then the `raw` loader (which turn the result into a string literal). With this in place, you can reference `.less` files from your Angular 2 components in the obvious way:
```javascript
@Component({
...
styles: [require('./somecomponent.less')]
})
export class SomeComponent { ... }
```
... and your styles will be applied in both server-side and client-side rendering.
#### Approach 2: Loading the styles using Webpack and JavaScript
This technique works with any client-side framework (not just Angular 2), and can also apply styles to the entire document rather than just individual components. It's a little simpler to set up than technique 3, plus it works flawlessly with Hot Module Replacement (HMR). The downside is that it's really only good for development time, because in production you probably don't want users to wait until JavaScript is loaded before styles are applied to the page (this would mean they'd see a 'flash of unstyled content' while the page is being loaded).
First create a `.less` file in your project. For example, create a file at `ClientApp/styles/mystyles.less` containing: First create a `.less` file in your project. For example, create a file at `ClientApp/styles/mystyles.less` containing:
@@ -422,40 +469,9 @@ This means that when you `import` or `require` a `.less` file, it should pass it
That's all you need to do! Restart your site and you should see the LESS styles being applied. This technique is compatible with both source maps and Hot Module Replacement (HMR), so you can edit your `.less` files at will and see the changes appearing live in the browser. That's all you need to do! Restart your site and you should see the LESS styles being applied. This technique is compatible with both source maps and Hot Module Replacement (HMR), so you can edit your `.less` files at will and see the changes appearing live in the browser.
**Scoping styles in Angular 2 components** #### Approach 3: Building LESS to CSS files on disk
If you're using Angular 2, you can define styles on a per-component basis rather than just globally for your whole app. Angular then takes care of ensuring that only the intended styles are applied to each component, even if the selector names would otherwise clash. To extend the above technique to per-component styling, first install the `to-string-loader` NPM module: This technique takes a little more work to set up than technique 2, and lacks compatibility with HMR. But it's much better for production use if your styles are applied to the whole page (not just elements constructed via JavaScript), because it loads the CSS independently of JavaScript.
```
npm install --save to-string-loader
```
Then in your `webpack.config.js`, simplify the `loader` entry for LESS files so that it just outputs `css` (without preparing it for use in a `style` tag):
```javascript
{ test: /\.less/, loader: 'css!less' }
```
Now **you must remove any direct global references to the `.less` file**, since you'll no longer be loading it globally. So if you previously loaded `mystyles.less` using an `import` or `require` statement in `boot-client.ts` or similar, remove that line.
Finally, load the LESS file scoped to a particular Angular 2 component by declaring a `styles` value for that component. For example,
```javascript
@ng.Component({
selector: ... leave value unchanged ...,
template: ... leave value unchanged ...,
styles: [require('to-string!../../styles/mystyles.less')]
})
export class YourComponent {
... code remains here ...
}
```
Now when you reload your page, you should file that the styles in `mystyles.less` are applied, but only to the component where you attached it. It's reasonable to use this technique in production because, even though the styles now depend on JavaScript to be applied, they are only used on elements that are injected via JavaScript anyway.
#### Approach 2: Building LESS to CSS files on disk
This technique takes a little more work to set up than technique 1, and lacks compatibility with HMR. But it's much better for production use if your styles are applied to the whole page (not just elements constructed via JavaScript), because it loads the CSS independently of JavaScript.
First add a `.less` file into your project. For example, create a file at `ClientApp/styles/mystyles.less` containing: First add a `.less` file into your project. For example, create a file at `ClientApp/styles/mystyles.less` containing:

View File

@@ -42,6 +42,11 @@ namespace Microsoft.AspNetCore.Builder
// as fast as some theoretical future alternative. // as fast as some theoretical future alternative.
var nodeServicesOptions = new NodeServicesOptions(appBuilder.ApplicationServices); var nodeServicesOptions = new NodeServicesOptions(appBuilder.ApplicationServices);
nodeServicesOptions.WatchFileExtensions = new string[] {}; // Don't watch anything nodeServicesOptions.WatchFileExtensions = new string[] {}; // Don't watch anything
if (!string.IsNullOrEmpty(options.ProjectPath))
{
nodeServicesOptions.ProjectPath = options.ProjectPath;
}
var nodeServices = NodeServicesFactory.CreateNodeServices(nodeServicesOptions); var nodeServices = NodeServicesFactory.CreateNodeServices(nodeServicesOptions);
// Get a filename matching the middleware Node script // Get a filename matching the middleware Node script
@@ -50,17 +55,23 @@ namespace Microsoft.AspNetCore.Builder
var nodeScript = new StringAsTempFile(script); // Will be cleaned up on process exit var nodeScript = new StringAsTempFile(script); // Will be cleaned up on process exit
// Tell Node to start the server hosting webpack-dev-middleware // Tell Node to start the server hosting webpack-dev-middleware
var hostEnv = (IHostingEnvironment)appBuilder.ApplicationServices.GetService(typeof(IHostingEnvironment));
var projectPath = options.ProjectPath ?? hostEnv.ContentRootPath;
var devServerOptions = new var devServerOptions = new
{ {
webpackConfigPath = Path.Combine(projectPath, options.ConfigFile ?? DefaultConfigFile), webpackConfigPath = Path.Combine(nodeServicesOptions.ProjectPath, options.ConfigFile ?? DefaultConfigFile),
suppliedOptions = options suppliedOptions = options,
understandsMultiplePublicPaths = true
}; };
var devServerInfo = var devServerInfo =
nodeServices.InvokeExportAsync<WebpackDevServerInfo>(nodeScript.FileName, "createWebpackDevServer", nodeServices.InvokeExportAsync<WebpackDevServerInfo>(nodeScript.FileName, "createWebpackDevServer",
JsonConvert.SerializeObject(devServerOptions)).Result; JsonConvert.SerializeObject(devServerOptions)).Result;
// 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.
if (devServerInfo.PublicPaths == null)
{
devServerInfo.PublicPaths = new[] { devServerInfo.PublicPath };
}
// Proxy the corresponding requests through ASP.NET and into the Node listener // Proxy the corresponding requests through ASP.NET and into the Node listener
// Note that this is hardcoded to make requests to "localhost" regardless of the hostname of the // Note that this is hardcoded to make requests to "localhost" regardless of the hostname of the
// server as far as the client is concerned. This is because ConditionalProxyMiddlewareOptions is // server as far as the client is concerned. This is because ConditionalProxyMiddlewareOptions is
@@ -70,7 +81,10 @@ namespace Microsoft.AspNetCore.Builder
// able to make outbound requests to it from here. // able to make outbound requests to it from here.
var proxyOptions = new ConditionalProxyMiddlewareOptions(WebpackDevMiddlewareScheme, var proxyOptions = new ConditionalProxyMiddlewareOptions(WebpackDevMiddlewareScheme,
"localhost", devServerInfo.Port.ToString()); "localhost", devServerInfo.Port.ToString());
appBuilder.UseMiddleware<ConditionalProxyMiddleware>(devServerInfo.PublicPath, proxyOptions); foreach (var publicPath in devServerInfo.PublicPaths)
{
appBuilder.UseMiddleware<ConditionalProxyMiddleware>(publicPath, proxyOptions);
}
// While it would be nice to proxy the /__webpack_hmr requests too, these return an EventStream, // While it would be nice to proxy the /__webpack_hmr requests too, these return an EventStream,
// and the Microsoft.AspNetCore.Proxy code doesn't handle that entirely - it throws an exception after // and the Microsoft.AspNetCore.Proxy code doesn't handle that entirely - it throws an exception after
@@ -92,6 +106,10 @@ namespace Microsoft.AspNetCore.Builder
class WebpackDevServerInfo class WebpackDevServerInfo
{ {
public int Port { get; set; } public int Port { get; set; }
public string[] PublicPaths { get; set; }
// For back-compatibility with older versions of aspnet-webpack, in the case where your webpack
// configuration contains exactly one config entry. This will be removed soon.
public string PublicPath { get; set; } public string PublicPath { get; set; }
} }
} }

View File

@@ -1,6 +1,6 @@
{ {
"name": "aspnet-prerendering", "name": "aspnet-prerendering",
"version": "1.0.5", "version": "1.0.7",
"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": {
@@ -9,6 +9,13 @@
}, },
"author": "Microsoft", "author": "Microsoft",
"license": "Apache-2.0", "license": "Apache-2.0",
"bugs": {
"url": "https://github.com/aspnet/JavaScriptServices/issues"
},
"repository": {
"type": "git",
"url": "https://github.com/aspnet/JavaScriptServices.git"
},
"dependencies": { "dependencies": {
"domain-task": "^2.0.1", "domain-task": "^2.0.1",
"es6-promise": "^3.1.2" "es6-promise": "^3.1.2"

View File

@@ -84,7 +84,7 @@ export function renderToString(callback: RenderToStringCallback, applicationBase
// Actually perform the rendering // Actually perform the rendering
bootFuncPromiseWithTimeout.then(successResult => { bootFuncPromiseWithTimeout.then(successResult => {
callback(null, { html: successResult.html, globals: successResult.globals }); callback(null, successResult);
}, error => { }, error => {
callback(error, null); callback(error, null);
}); });
@@ -128,7 +128,7 @@ function findBootModule<T>(applicationBasePath: string, bootModule: BootModuleIn
try { try {
aspNetWebpackModule = require('aspnet-webpack'); aspNetWebpackModule = require('aspnet-webpack');
} catch (ex) { } catch (ex) {
callback('To load your boot module via webpack (i.e., if you specify a \'webpackConfig\' option), you must install the \'aspnet-webpack\' NPM package.', null); callback('To load your boot module via webpack (i.e., if you specify a \'webpackConfig\' option), you must install the \'aspnet-webpack\' NPM package. Error encountered while loading \'aspnet-webpack\': ' + ex.stack, null);
return; return;
} }

View File

@@ -9,6 +9,13 @@
}, },
"author": "Microsoft", "author": "Microsoft",
"license": "Apache-2.0", "license": "Apache-2.0",
"bugs": {
"url": "https://github.com/aspnet/JavaScriptServices/issues"
},
"repository": {
"type": "git",
"url": "https://github.com/aspnet/JavaScriptServices.git"
},
"dependencies": { "dependencies": {
"babel-core": "^6.7.2", "babel-core": "^6.7.2",
"babel-loader": "^6.2.4", "babel-loader": "^6.2.4",

View File

@@ -1,6 +1,6 @@
{ {
"name": "aspnet-webpack", "name": "aspnet-webpack",
"version": "1.0.9", "version": "1.0.16",
"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": {
@@ -9,17 +9,27 @@
}, },
"author": "Microsoft", "author": "Microsoft",
"license": "Apache-2.0", "license": "Apache-2.0",
"bugs": {
"url": "https://github.com/aspnet/JavaScriptServices/issues"
},
"repository": {
"type": "git",
"url": "https://github.com/aspnet/JavaScriptServices.git"
},
"dependencies": { "dependencies": {
"es6-promise": "^3.1.2",
"connect": "^3.4.1", "connect": "^3.4.1",
"es6-promise": "^3.1.2",
"memory-fs": "^0.3.0", "memory-fs": "^0.3.0",
"require-from-string": "^1.1.0", "require-from-string": "^1.1.0",
"webpack": "^1.12.14", "webpack-dev-middleware": "^1.6.1",
"webpack-dev-middleware": "^1.5.1", "webpack-node-externals": "^1.4.3"
"webpack-externals-plugin": "^1.0.0"
}, },
"devDependencies": { "devDependencies": {
"tsd": "0.6.5",
"rimraf": "^2.5.4", "rimraf": "^2.5.4",
"typescript": "^1.8.10" "typescript": "^1.8.10"
},
"peerDependencies": {
"webpack": "^1.13.2"
} }
} }

View File

@@ -9,10 +9,9 @@ import * as webpack from 'webpack';
import { requireNewCopy } from './RequireNewCopy'; import { requireNewCopy } from './RequireNewCopy';
// Strange import syntax to work around https://github.com/Microsoft/TypeScript/issues/2719 // Strange import syntax to work around https://github.com/Microsoft/TypeScript/issues/2719
import { webpackexternals } from './typings/webpack-externals-plugin';
import { requirefromstring } from './typings/require-from-string'; import { requirefromstring } from './typings/require-from-string';
import { memoryfs } from './typings/memory-fs'; import { memoryfs } from './typings/memory-fs';
const ExternalsPlugin = require('webpack-externals-plugin') as typeof webpackexternals.ExternalsPlugin; const nodeExternals = require('webpack-node-externals');
const requireFromString = require('require-from-string') as typeof requirefromstring.requireFromString; const requireFromString = require('require-from-string') as typeof requirefromstring.requireFromString;
const MemoryFS = require('memory-fs') as typeof memoryfs.MemoryFS; const MemoryFS = require('memory-fs') as typeof memoryfs.MemoryFS;
@@ -57,11 +56,38 @@ function loadViaWebpackNoCache<T>(webpackConfigPath: string, modulePath: string)
webpackConfig.output.libraryTarget = 'commonjs'; webpackConfig.output.libraryTarget = 'commonjs';
const outputVirtualPath = path.join(webpackConfig.output.path, webpackConfig.output.filename); const outputVirtualPath = path.join(webpackConfig.output.path, webpackConfig.output.filename);
// In Node, we want anything under /node_modules/ to be loaded natively and not bundled into the output // In Node, we want any JavaScript modules under /node_modules/ to be loaded natively and not bundled into the
// (partly because it's faster, but also because otherwise there'd be different instances of modules // output (partly because it's faster, but also because otherwise there'd be different instances of modules
// depending on how they were loaded, which could lead to errors) // depending on how they were loaded, which could lead to errors).
webpackConfig.plugins = webpackConfig.plugins || []; // ---
webpackConfig.plugins.push(new ExternalsPlugin({ type: 'commonjs', include: /node_modules/ })); // NOTE: We have to use webpack-node-externals rather than webpack-externals-plugin because
// webpack-externals-plugin doesn't correctly resolve relative paths, which means you can't
// use css-loader, since tries to require('./../../node_modules/css-loader/lib/css-base.js') (see #132)
// ---
// So, ensure that webpackConfig.externals is an array, and push WebpackNodeExternals into it:
let externalsArray: any[] = (webpackConfig.externals as any[]) || [];
if (!(externalsArray instanceof Array)) {
externalsArray = [externalsArray];
}
webpackConfig.externals = externalsArray;
externalsArray.push(nodeExternals({
// However, we do *not* want to treat non-JS files under /node_modules/ as externals (i.e., things
// that should be loaded via regular CommonJS 'require' statements). For example, if you reference
// a .css file inside an NPM module (e.g., require('somepackage/somefile.css')), then we do need to
// load that via Webpack rather than as a regular CommonJS module.
//
// So, configure webpack-externals-plugin to 'whitelist' (i.e., not treat as external) any file
// that has an extension other than .js. Also, since some libraries such as font-awesome refer to
// their own files with cache-busting querystrings (e.g., (url('./something.css?v=4.1.2'))), we
// need to treat '?' as an alternative 'end of filename' marker.
//
// The complex, awkward regex can be eliminated once webpack-externals-plugin merges
// https://github.com/liady/webpack-node-externals/pull/12
//
// This regex looks for at least one dot character that is *not* followed by "js<end-or-questionmark>", but
// is followed by some series of non-dot characters followed by <end-or-questionmark>:
whitelist: [/\.(?!js(\?|$))([^.]+(\?|$))/]
}));
// The CommonsChunkPlugin is not compatible with a CommonJS environment like Node, nor is it needed in that case // The CommonsChunkPlugin is not compatible with a CommonJS environment like Node, nor is it needed in that case
webpackConfig.plugins = webpackConfig.plugins.filter(plugin => { webpackConfig.plugins = webpackConfig.plugins.filter(plugin => {

View File

@@ -3,8 +3,14 @@ import * as webpack from 'webpack';
import * as url from 'url'; import * as url from 'url';
import { requireNewCopy } from './RequireNewCopy'; import { requireNewCopy } from './RequireNewCopy';
export type CreateDevServerResult = {
Port: number,
PublicPaths: string[],
PublicPath: string // For backward compatibility with older verions of Microsoft.AspNetCore.SpaServices. Will be removed soon.
};
export interface CreateDevServerCallback { export interface CreateDevServerCallback {
(error: any, result: { Port: number, PublicPath: string }): void; (error: any, result: CreateDevServerResult): void;
} }
// These are the options passed by WebpackDevMiddleware.cs // These are the options passed by WebpackDevMiddleware.cs
@@ -20,13 +26,78 @@ interface DevServerOptions {
ReactHotModuleReplacement: boolean; ReactHotModuleReplacement: boolean;
} }
function attachWebpackDevMiddleware(app: any, webpackConfig: webpack.Configuration, enableHotModuleReplacement: boolean, enableReactHotModuleReplacement: boolean) {
// Build the final Webpack config based on supplied options
if (enableHotModuleReplacement) {
// For this, we only support the key/value config format, not string or string[], since
// those ones don't clearly indicate what the resulting bundle name will be
const entryPoints = webpackConfig.entry;
const isObjectStyleConfig = entryPoints
&& typeof entryPoints === 'object'
&& !(entryPoints instanceof Array);
if (!isObjectStyleConfig) {
throw new Error('To use HotModuleReplacement, your webpack config must specify an \'entry\' value as a key-value object (e.g., "entry: { main: \'ClientApp/boot-client.ts\' }")');
}
// Augment all entry points so they support HMR
Object.getOwnPropertyNames(entryPoints).forEach(entryPointName => {
if (typeof entryPoints[entryPointName] === 'string') {
entryPoints[entryPointName] = ['webpack-hot-middleware/client', entryPoints[entryPointName]];
} else {
entryPoints[entryPointName].unshift('webpack-hot-middleware/client');
}
});
webpackConfig.plugins = [].concat(webpackConfig.plugins || []); // Be sure not to mutate the original array, as it might be shared
webpackConfig.plugins.push(
new webpack.HotModuleReplacementPlugin()
);
// Set up React HMR support if requested. This requires the 'aspnet-webpack-react' package.
if (enableReactHotModuleReplacement) {
let aspNetWebpackReactModule: any;
try {
aspNetWebpackReactModule = require('aspnet-webpack-react');
} catch(ex) {
throw new Error('ReactHotModuleReplacement failed because of an error while loading \'aspnet-webpack-react\'. Error was: ' + ex.stack);
}
aspNetWebpackReactModule.addReactHotModuleReplacementBabelTransform(webpackConfig);
}
}
// Attach Webpack dev middleware and optional 'hot' middleware
const compiler = webpack(webpackConfig);
app.use(require('webpack-dev-middleware')(compiler, {
noInfo: true,
publicPath: webpackConfig.output.publicPath
}));
if (enableHotModuleReplacement) {
let webpackHotMiddlewareModule;
try {
webpackHotMiddlewareModule = require('webpack-hot-middleware');
} catch (ex) {
throw new Error('HotModuleReplacement failed because of an error while loading \'webpack-hot-middleware\'. Error was: ' + ex.stack);
}
app.use(webpackHotMiddlewareModule(compiler));
}
}
function beginWebpackWatcher(webpackConfig: webpack.Configuration) {
const compiler = webpack(webpackConfig);
compiler.watch({ /* watchOptions */ }, (err, stats) => {
// The default error reporter is fine for now, but could be customized here in the future if desired
});
}
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);
const webpackConfig: webpack.Configuration = requireNewCopy(options.webpackConfigPath);
const publicPath = (webpackConfig.output.publicPath || '').trim(); // Read the webpack config's export, and normalize it into the more general 'array of configs' format
if (!publicPath) { let webpackConfigArray: webpack.Configuration[] = requireNewCopy(options.webpackConfigPath);
callback('To use the Webpack dev server, you must specify a value for \'publicPath\' on the \'output\' section of your webpack.config.', null); if (!(webpackConfigArray instanceof Array)) {
return; webpackConfigArray = [webpackConfigArray as webpack.Configuration];
} }
const enableHotModuleReplacement = options.suppliedOptions.HotModuleReplacement; const enableHotModuleReplacement = options.suppliedOptions.HotModuleReplacement;
@@ -41,55 +112,40 @@ export function createWebpackDevServer(callback: CreateDevServerCallback, option
const app = connect(); const app = connect();
const listener = app.listen(suggestedHMRPortOrZero, () => { const listener = app.listen(suggestedHMRPortOrZero, () => {
// Build the final Webpack config based on supplied options try {
if (enableHotModuleReplacement) { // For each webpack config that specifies a public path, add webpack dev middleware for it
// TODO: Stop assuming there's an entry point called 'main' const normalizedPublicPaths: string[] = [];
if (typeof webpackConfig.entry['main'] === 'string') { webpackConfigArray.forEach(webpackConfig => {
webpackConfig.entry['main'] = ['webpack-hot-middleware/client', webpackConfig.entry['main']]; if (webpackConfig.target === 'node') {
} else { // For configs that target Node, it's meaningless to set up an HTTP listener, since
webpackConfig.entry['main'].unshift('webpack-hot-middleware/client'); // Node isn't going to load those modules over HTTP anyway. It just loads them directly
} // from disk. So the most relevant thing we can do with such configs is just write
webpackConfig.plugins.push( // updated builds to disk, just like "webpack --watch".
new webpack.HotModuleReplacementPlugin() beginWebpackWatcher(webpackConfig);
); } else {
// For configs that target browsers, we can set up an HTTP listener, and dynamically
// Set up React HMR support if requested. This requires the 'aspnet-webpack-react' package. // modify the config to enable HMR etc. This just requires that we have a publicPath.
if (enableReactHotModuleReplacement) { const publicPath = (webpackConfig.output.publicPath || '').trim();
let aspNetWebpackReactModule: any; if (!publicPath) {
try { 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)');
aspNetWebpackReactModule = require('aspnet-webpack-react'); }
} catch(ex) { normalizedPublicPaths.push(removeTrailingSlash(publicPath));
callback('To use ReactHotModuleReplacement, you must install the NPM package \'aspnet-webpack-react\'.', null); attachWebpackDevMiddleware(app, webpackConfig, enableHotModuleReplacement, enableReactHotModuleReplacement);
return;
} }
});
aspNetWebpackReactModule.addReactHotModuleReplacementBabelTransform(webpackConfig); // Tell the ASP.NET app what addresses we're listening on, so that it can proxy requests here
} callback(null, {
Port: listener.address().port,
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) {
callback(ex.stack, null);
} }
// Attach Webpack dev middleware and optional 'hot' middleware
const compiler = webpack(webpackConfig);
app.use(require('webpack-dev-middleware')(compiler, {
noInfo: true,
publicPath: publicPath
}));
if (enableHotModuleReplacement) {
let webpackHotMiddlewareModule;
try {
webpackHotMiddlewareModule = require('webpack-hot-middleware');
} catch (ex) {
callback('To use HotModuleReplacement, you must install the NPM package \'webpack-hot-middleware\'.', null);
return;
}
app.use(webpackHotMiddlewareModule(compiler));
}
// Tell the ASP.NET app what addresses we're listening on, so that it can proxy requests here
callback(null, {
Port: listener.address().port,
PublicPath: removeTrailingSlash(getPath(publicPath))
});
}); });
} }

View File

@@ -1,12 +0,0 @@
import * as webpack from 'webpack';
export namespace webpackexternals {
export interface ExternalsPluginOptions {
type: string;
include: webpack.LoaderCondition;
}
export class ExternalsPlugin {
constructor(options: ExternalsPluginOptions);
}
}

View File

@@ -0,0 +1,2 @@
declare module 'webpack-node-externals' {
}

View File

@@ -9,6 +9,13 @@
}, },
"author": "Microsoft", "author": "Microsoft",
"license": "Apache-2.0", "license": "Apache-2.0",
"bugs": {
"url": "https://github.com/aspnet/JavaScriptServices/issues"
},
"repository": {
"type": "git",
"url": "https://github.com/aspnet/JavaScriptServices.git"
},
"dependencies": { "dependencies": {
"domain-context": "^0.5.1", "domain-context": "^0.5.1",
"isomorphic-fetch": "^2.2.1" "isomorphic-fetch": "^2.2.1"

View File

@@ -8,7 +8,7 @@
"Microsoft" "Microsoft"
], ],
"dependencies": { "dependencies": {
"Microsoft.AspNetCore.Mvc": "1.0.0", "Microsoft.AspNetCore.Mvc": "1.0.1",
"Microsoft.AspNetCore.NodeServices": "1.0.0-*" "Microsoft.AspNetCore.NodeServices": "1.0.0-*"
}, },
"frameworks": { "frameworks": {

View File

@@ -5,16 +5,16 @@
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath> <VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
<TypeScriptCompileBlocked>true</TypeScriptCompileBlocked> <TypeScriptCompileBlocked>true</TypeScriptCompileBlocked>
</PropertyGroup> </PropertyGroup>
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.Props" Condition="'$(VSToolsPath)' != ''" /> <Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.Props" Condition="'$(VSToolsPath)' != ''" />
<PropertyGroup Label="Globals"> <PropertyGroup Label="Globals">
<ProjectGuid>8f5cb8a9-3086-4b49-a1c2-32a9f89bca11</ProjectGuid> <ProjectGuid>8f5cb8a9-3086-4b49-a1c2-32a9f89bca11</ProjectGuid>
<RootNamespace>Angular2Spa</RootNamespace> <RootNamespace>Angular2Spa</RootNamespace>
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\..\..\JavaScriptServices.sln\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath> <BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">.\obj</BaseIntermediateOutputPath>
<OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath> <OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath>
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
</PropertyGroup> </PropertyGroup>
<PropertyGroup> <PropertyGroup>
<SchemaVersion>2.0</SchemaVersion> <SchemaVersion>2.0</SchemaVersion>
<DevelopmentServerPort>2018</DevelopmentServerPort>
</PropertyGroup> </PropertyGroup>
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.targets" Condition="'$(VSToolsPath)' != ''" /> <Import Project="$(VSToolsPath)\DotNet.Web\Microsoft.DotNet.Web.targets" Condition="'$(VSToolsPath)' != ''" />
</Project> </Project>

View File

@@ -0,0 +1,31 @@
import { NgModule } from '@angular/core';
import { RouterModule } from '@angular/router';
import { UniversalModule } from 'angular2-universal';
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({
bootstrap: [ AppComponent ],
declarations: [
AppComponent,
NavMenuComponent,
CounterComponent,
FetchDataComponent,
HomeComponent
],
imports: [
UniversalModule, // Must be first import. This automatically imports BrowserModule, HttpModule, and JsonpModule too.
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 AppModule {
}

View File

@@ -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;
}
}

View File

@@ -0,0 +1,9 @@
import { Component } from '@angular/core';
@Component({
selector: 'app',
template: require('./app.component.html'),
styles: [require('./app.component.css')]
})
export class AppComponent {
}

View File

@@ -0,0 +1,13 @@
import { Component } from '@angular/core';
@Component({
selector: 'counter',
template: require('./counter.component.html')
})
export class CounterComponent {
public currentCount = 0;
public incrementCounter() {
this.currentCount++;
}
}

View File

@@ -1,11 +1,11 @@
import * as ng from '@angular/core'; import { Component } from '@angular/core';
import { Http } from '@angular/http'; import { Http } from '@angular/http';
@ng.Component({ @Component({
selector: 'fetch-data', selector: 'fetchdata',
template: require('./fetch-data.html') template: require('./fetchdata.component.html')
}) })
export class FetchData { export class FetchDataComponent {
public forecasts: WeatherForecast[]; public forecasts: WeatherForecast[];
constructor(http: Http) { constructor(http: Http) {

View File

@@ -0,0 +1,8 @@
import { Component } from '@angular/core';
@Component({
selector: 'home',
template: require('./home.component.html')
})
export class HomeComponent {
}

View File

@@ -1,18 +1,11 @@
@media (max-width: 767px) { li .glyphicon {
/* On small screens, the nav menu spans the full width of the screen. Leave a space for it. */
.body-content {
padding-top: 50px;
}
}
.main-nav li .glyphicon {
margin-right: 10px; margin-right: 10px;
} }
/* Highlighting rules for nav menu items */ /* Highlighting rules for nav menu items */
.main-nav li.link-active a, li.link-active a,
.main-nav li.link-active a:hover, li.link-active a:hover,
.main-nav li.link-active a:focus { li.link-active a:focus {
background-color: #4189C7; background-color: #4189C7;
color: white; color: white;
} }
@@ -32,31 +25,31 @@
height: 100%; height: 100%;
width: calc(25% - 20px); width: calc(25% - 20px);
} }
.main-nav .navbar { .navbar {
border-radius: 0px; border-radius: 0px;
border-width: 0px; border-width: 0px;
height: 100%; height: 100%;
} }
.main-nav .navbar-header { .navbar-header {
float: none; float: none;
} }
.main-nav .navbar-collapse { .navbar-collapse {
border-top: 1px solid #444; border-top: 1px solid #444;
padding: 0px; padding: 0px;
} }
.main-nav .navbar ul { .navbar ul {
float: none; float: none;
} }
.main-nav .navbar li { .navbar li {
float: none; float: none;
font-size: 15px; font-size: 15px;
margin: 6px; margin: 6px;
} }
.main-nav .navbar li a { .navbar li a {
padding: 10px 16px; padding: 10px 16px;
border-radius: 4px; border-radius: 4px;
} }
.main-nav .navbar a { .navbar a {
/* If a menu item's text is too long, truncate it */ /* If a menu item's text is too long, truncate it */
width: 100%; width: 100%;
white-space: nowrap; white-space: nowrap;

View File

@@ -1,5 +1,5 @@
<div class='main-nav'> <div class='main-nav'>
<div class='navbar navbar-inverse'> <div class='navbar navbar-inverse'>
<div class='navbar-header'> <div class='navbar-header'>
<button type='button' class='navbar-toggle' data-toggle='collapse' data-target='.navbar-collapse'> <button type='button' class='navbar-toggle' data-toggle='collapse' data-target='.navbar-collapse'>
<span class='sr-only'>Toggle navigation</span> <span class='sr-only'>Toggle navigation</span>
@@ -19,6 +19,7 @@
</li> </li>
<li [routerLinkActive]="['link-active']"> <li [routerLinkActive]="['link-active']">
<a [routerLink]="['/counter']"> <a [routerLink]="['/counter']">
<i class="fa fa-camera-retro"></i>
<span class='glyphicon glyphicon-education'></span> Counter <span class='glyphicon glyphicon-education'></span> Counter
</a> </a>
</li> </li>

View File

@@ -0,0 +1,9 @@
import { Component } from '@angular/core';
@Component({
selector: 'nav-menu',
template: require('./navmenu.component.html'),
styles: [require('./navmenu.component.css')]
})
export class NavMenuComponent {
}

View File

@@ -1,25 +1,22 @@
import 'es6-shim'; import 'angular2-universal-polyfills/browser';
require('zone.js'); import { enableProdMode } from '@angular/core';
import { platformUniversalDynamic } from 'angular2-universal';
import { AppModule } from './app/app.module';
import 'bootstrap'; import 'bootstrap';
import 'reflect-metadata';
import './styles/site.css';
import { bootstrap } from '@angular/platform-browser-dynamic'; // Enable either Hot Module Reloading or production mode
import { FormBuilder } from '@angular/common'; if (module['hot']) {
import { provideRouter } from '@angular/router'; module['hot'].accept();
import { HTTP_PROVIDERS } from '@angular/http'; module['hot'].dispose(() => { platform.destroy(); });
import { App } from './components/app/app'; } else {
import { routes } from './routes'; enableProdMode();
}
bootstrap(App, [
...HTTP_PROVIDERS, // Boot the application, either now or when the DOM content is loaded
FormBuilder, const platform = platformUniversalDynamic();
provideRouter(routes) const bootApplication = () => { platform.bootstrapModule(AppModule); };
]); if (document.readyState === 'complete') {
bootApplication();
// Basic hot reloading support. Automatically reloads and restarts the Angular 2 app each time } else {
// you modify source files. This will not preserve any application state other than the URL. document.addEventListener('DOMContentLoaded', bootApplication);
declare var module: any;
if (module.hot) {
module.hot.accept();
} }

View File

@@ -1,36 +1,34 @@
import 'angular2-universal/polyfills'; import 'angular2-universal-polyfills';
import * as ngCore from '@angular/core'; import 'zone.js';
import { APP_BASE_HREF } from '@angular/common'; import { enableProdMode } from '@angular/core';
import { provideRouter } from '@angular/router'; import { platformNodeDynamic } from 'angular2-universal';
import * as ngUniversal from 'angular2-universal'; import { AppModule } from './app/app.module';
import { BASE_URL, ORIGIN_URL, REQUEST_URL } from 'angular2-universal/common';
import { App } from './components/app/app';
import { routes } from './routes';
const bootloader = ngUniversal.bootloader({ enableProdMode();
async: true, const platform = platformNodeDynamic();
preboot: false,
platformProviders: [
ngCore.provide(APP_BASE_HREF, { useValue: '/' }),
]
});
export default function (params: any): Promise<{ html: string, globals?: any }> { export default function (params: any) : Promise<{ html: string, globals?: any }> {
const config: ngUniversal.AppConfig = { return new Promise((resolve, reject) => {
directives: [App], const requestZone = Zone.current.fork({
providers: [ name: 'angular-universal request',
ngCore.provide(ORIGIN_URL, { useValue: params.origin }), properties: {
ngCore.provide(REQUEST_URL, { useValue: params.url }), baseUrl: '/',
...ngUniversal.NODE_HTTP_PROVIDERS, requestUrl: params.url,
provideRouter(routes), originUrl: params.origin,
...ngUniversal.NODE_LOCATION_PROVIDERS, preboot: false,
], // TODO: Render just the <app> component instead of wrapping it inside an extra HTML document
// TODO: Render just the <app> component instead of wrapping it inside an extra HTML document // Waiting on https://github.com/angular/universal/issues/347
// Waiting on https://github.com/angular/universal/issues/347 document: '<!DOCTYPE html><html><head></head><body><app></app></body></html>'
template: '<!DOCTYPE html>\n<html><head></head><body><app></app></body></html>' },
}; onHandleError: (parentZone, currentZone, targetZone, error) => {
// If any error occurs while rendering the module, reject the whole operation
reject(error);
return true;
}
});
return bootloader.serializeApplication(config).then(html => { return requestZone.run<Promise<string>>(() => platform.serializeModule(AppModule)).then(html => {
return { html }; resolve({ html: html });
}, reject);
}); });
} }

View File

@@ -1,11 +0,0 @@
import * as ng from '@angular/core';
import { ROUTER_DIRECTIVES } from '@angular/router';
import { NavMenu } from '../nav-menu/nav-menu';
@ng.Component({
selector: 'app',
template: require('./app.html'),
directives: [...ROUTER_DIRECTIVES, NavMenu]
})
export class App {
}

View File

@@ -1,13 +0,0 @@
import * as ng from '@angular/core';
@ng.Component({
selector: 'counter',
template: require('./counter.html')
})
export class Counter {
public currentCount = 0;
public incrementCounter() {
this.currentCount++;
}
}

View File

@@ -1,8 +0,0 @@
import * as ng from '@angular/core';
@ng.Component({
selector: 'home',
template: require('./home.html')
})
export class Home {
}

View File

@@ -1,10 +0,0 @@
import * as ng from '@angular/core';
import { ROUTER_DIRECTIVES } from '@angular/router';
@ng.Component({
selector: 'nav-menu',
template: require('./nav-menu.html'),
directives: [...ROUTER_DIRECTIVES]
})
export class NavMenu {
}

View File

@@ -1,12 +0,0 @@
import { RouterConfig } from '@angular/router';
import { Home } from './components/home/home';
import { FetchData } from './components/fetch-data/fetch-data';
import { Counter } from './components/counter/counter';
export const routes: RouterConfig = [
{ path: '', redirectTo: 'home', pathMatch: 'full' },
{ path: 'home', component: Home },
{ path: 'counter', component: Counter },
{ path: 'fetch-data', component: FetchData },
{ path: '**', redirectTo: 'home' }
];

View File

@@ -1,18 +0,0 @@
import 'angular2-universal-polyfills';
import { assert } from 'chai';
import { Counter } from '../components/counter/counter';
describe('Counter component', () => {
it('should start with value 0', () => {
const instance = new Counter();
assert.equal(instance.currentCount, 0);
});
it('should increment the counter by 1 when requested', () => {
const instance = new Counter();
instance.incrementCounter();
assert.equal(instance.currentCount, 1);
instance.incrementCounter();
assert.equal(instance.currentCount, 2);
});
});

View File

@@ -5,10 +5,10 @@
"sourceMap": true, "sourceMap": true,
"experimentalDecorators": true, "experimentalDecorators": true,
"emitDecoratorMetadata": true, "emitDecoratorMetadata": true,
"skipDefaultLibCheck": true "skipDefaultLibCheck": true,
"lib": [ "es6", "dom" ],
"types": [ "node" ]
}, },
"exclude": [ "exclude": [ "bin", "node_modules" ],
"bin", "atom": { "rewriteTsconfig": false }
"node_modules"
]
} }

View File

@@ -2,10 +2,9 @@
ViewData["Title"] = "Home Page"; ViewData["Title"] = "Home Page";
} }
<app asp-prerender-module="ClientApp/boot-server" <app asp-prerender-module="ClientApp/dist/main-server">Loading...</app>
asp-prerender-webpack-config="webpack.config.js">Loading...</app>
<script src="~/dist/vendor.js" asp-append-version="true"></script> <script src="~/dist/vendor.js" asp-append-version="true"></script>
@section scripts { @section scripts {
<script src="~/dist/main.js" asp-append-version="true"></script> <script src="~/dist/main-client.js" asp-append-version="true"></script>
} }

View File

@@ -6,7 +6,6 @@
<title>@ViewData["Title"] - WebApplicationBasic</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" />
<link rel="stylesheet" href="~/dist/styles.css" asp-append-version="true" />
</head> </head>
<body> <body>
@RenderBody() @RenderBody()

View File

@@ -1,26 +0,0 @@
module.exports = function(config) {
config.set({
frameworks: ['jasmine', 'chai'],
reporters: ['progress'],
logLevel: config.LOG_INFO,
browsers: ['Chrome'],
autoWatch: true,
autoWatchBatchDelay: 300,
files: [
// Note: you must have already run 'webpack --config webpack.config.vendor.js' for this file to exist
'./wwwroot/dist/vendor.js',
'./ClientApp/tests/*.ts',
'./ClientApp/tests/**/*.ts'
],
preprocessors: {
'./ClientApp/tests/*.ts': ['webpack'],
'./ClientApp/tests/**/*.ts': ['webpack']
},
webpack: require('./webpack.config.js'),
webpackMiddleware: { stats: 'errors-only' }
});
};

View File

@@ -1,47 +1,46 @@
{ {
"name": "WebApplicationBasic", "name": "Angular2Spa",
"version": "0.0.0", "version": "0.0.0",
"devDependencies": { "devDependencies": {
"aspnet-webpack": "^1.0.6", "aspnet-webpack": "^1.0.11",
"bootstrap": "^3.3.6", "css": "^2.2.1",
"chai": "^3.5.0", "css-loader": "^0.25.0",
"css-loader": "^0.23.1",
"expose-loader": "^0.7.1", "expose-loader": "^0.7.1",
"extendify": "^1.0.0",
"extract-text-webpack-plugin": "^1.0.1", "extract-text-webpack-plugin": "^1.0.1",
"file-loader": "^0.8.5", "file-loader": "^0.9.0",
"jasmine-core": "^2.5.1",
"jquery": "^2.2.1",
"karma": "^1.2.0",
"karma-chai": "^0.1.0",
"karma-chrome-launcher": "^2.0.0",
"karma-jasmine": "^1.0.2",
"karma-webpack": "^1.8.0",
"raw-loader": "^0.5.1", "raw-loader": "^0.5.1",
"style-loader": "^0.13.0", "style-loader": "^0.13.0",
"ts-loader": "^0.8.1", "to-string-loader": "^1.1.5",
"typescript": "^1.8.2", "ts-loader": "^0.8.2",
"typescript": "^2.0.0",
"url-loader": "^0.5.7", "url-loader": "^0.5.7",
"webpack": "^1.12.14", "webpack": "^1.12.14",
"webpack-hot-middleware": "^2.10.0" "webpack-externals-plugin": "^1.0.0",
"webpack-hot-middleware": "^2.10.0",
"webpack-merge": "^0.14.1"
}, },
"dependencies": { "dependencies": {
"@angular/common": "2.0.0-rc.4", "@angular/common": "2.0.0",
"@angular/compiler": "2.0.0-rc.4", "@angular/compiler": "2.0.0",
"@angular/core": "2.0.0-rc.4", "@angular/core": "2.0.0",
"@angular/http": "2.0.0-rc.4", "@angular/forms": "2.0.0",
"@angular/platform-browser": "2.0.0-rc.4", "@angular/http": "2.0.0",
"@angular/platform-browser-dynamic": "2.0.0-rc.4", "@angular/platform-browser": "2.0.0",
"@angular/platform-server": "2.0.0-rc.4", "@angular/platform-browser-dynamic": "2.0.0",
"@angular/router": "3.0.0-beta.2", "@angular/platform-server": "2.0.0",
"angular2-universal": "^0.104.5", "@angular/router": "3.0.0",
"aspnet-prerendering": "^1.0.2", "@types/node": "^6.0.38",
"css": "^2.2.1", "angular2-platform-node": "~2.0.10",
"angular2-universal": "~2.0.10",
"angular2-universal-polyfills": "~2.0.10",
"aspnet-prerendering": "^1.0.6",
"bootstrap": "^3.3.7",
"es6-shim": "^0.35.1", "es6-shim": "^0.35.1",
"font-awesome": "^4.6.3",
"isomorphic-fetch": "^2.2.1", "isomorphic-fetch": "^2.2.1",
"preboot": "^2.0.10", "jquery": "^2.2.1",
"rxjs": "5.0.0-beta.6", "preboot": "^4.5.2",
"webpack-externals-plugin": "^1.0.0", "rxjs": "5.0.0-beta.12",
"zone.js": "^0.6.12" "zone.js": "^0.6.21"
} }
} }

View File

@@ -1,18 +1,18 @@
{ {
"dependencies": { "dependencies": {
"Microsoft.NETCore.App": { "Microsoft.NETCore.App": {
"version": "1.0.0", "version": "1.0.1",
"type": "platform" "type": "platform"
}, },
"Microsoft.AspNetCore.AngularServices": "1.0.0-*", "Microsoft.AspNetCore.AngularServices": "1.0.0-*",
"Microsoft.AspNetCore.Diagnostics": "1.0.0", "Microsoft.AspNetCore.Diagnostics": "1.0.0",
"Microsoft.AspNetCore.Mvc": "1.0.0", "Microsoft.AspNetCore.Mvc": "1.0.1",
"Microsoft.AspNetCore.Razor.Tools": { "Microsoft.AspNetCore.Razor.Tools": {
"version": "1.0.0-preview2-final", "version": "1.0.0-preview2-final",
"type": "build" "type": "build"
}, },
"Microsoft.AspNetCore.Server.IISIntegration": "1.0.0", "Microsoft.AspNetCore.Server.IISIntegration": "1.0.0",
"Microsoft.AspNetCore.Server.Kestrel": "1.0.0", "Microsoft.AspNetCore.Server.Kestrel": "1.0.1",
"Microsoft.AspNetCore.StaticFiles": "1.0.0", "Microsoft.AspNetCore.StaticFiles": "1.0.0",
"Microsoft.Extensions.Configuration.EnvironmentVariables": "1.0.0", "Microsoft.Extensions.Configuration.EnvironmentVariables": "1.0.0",
"Microsoft.Extensions.Configuration.Json": "1.0.0", "Microsoft.Extensions.Configuration.Json": "1.0.0",
@@ -52,14 +52,10 @@
"publishOptions": { "publishOptions": {
"include": [ "include": [
"appsettings.json", "appsettings.json",
"ClientApp", "ClientApp/dist",
"node_modules", "node_modules",
"typings",
"Views", "Views",
"tsconfig.json",
"tsd.json",
"web.config", "web.config",
"webpack.*.js",
"wwwroot" "wwwroot"
] ]
}, },
@@ -67,8 +63,8 @@
"scripts": { "scripts": {
"prepublish": [ "prepublish": [
"npm install", "npm install",
"node node_modules/webpack/bin/webpack.js --config webpack.config.vendor.js", "node node_modules/webpack/bin/webpack.js --config webpack.config.vendor.js --env.prod",
"node node_modules/webpack/bin/webpack.js" "node node_modules/webpack/bin/webpack.js --env.prod"
], ],
"postpublish": [ "dotnet publish-iis --publish-folder %publish:OutputPath% --framework %publish:FullTargetFramework%" ] "postpublish": [ "dotnet publish-iis --publish-folder %publish:OutputPath% --framework %publish:FullTargetFramework%" ]
}, },

View File

@@ -29,6 +29,7 @@ Obj/
# Visual Studio 2015 cache/options directory # Visual Studio 2015 cache/options directory
.vs/ .vs/
/wwwroot/dist/ /wwwroot/dist/
/ClientApp/dist/
# MSTest test Results # MSTest test Results
[Tt]est[Rr]esult*/ [Tt]est[Rr]esult*/

View File

@@ -1,24 +0,0 @@
{
"version": "v4",
"repo": "borisyankov/DefinitelyTyped",
"ref": "master",
"path": "typings",
"bundle": "typings/tsd.d.ts",
"installed": {
"requirejs/require.d.ts": {
"commit": "dade4414712ce84e3c63393f1aae407e9e7e6af7"
},
"es6-shim/es6-shim.d.ts": {
"commit": "c0d876601e0f8236fd6b57626eb62c4e485f1563"
},
"chai/chai.d.ts": {
"commit": "15d88ee05780bd6bbc4e376c5202b160895017f5"
},
"assertion-error/assertion-error.d.ts": {
"commit": "15d88ee05780bd6bbc4e376c5202b160895017f5"
},
"jasmine/jasmine.d.ts": {
"commit": "15d88ee05780bd6bbc4e376c5202b160895017f5"
}
}
}

View File

@@ -1,15 +0,0 @@
// Type definitions for assertion-error 1.0.0
// Project: https://github.com/chaijs/assertion-error
// Definitions by: Bart van der Schoor <https://github.com/Bartvds>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
declare module 'assertion-error' {
class AssertionError implements Error {
constructor(message: string, props?: any, ssf?: Function);
name: string;
message: string;
showDiff: boolean;
stack: string;
}
export = AssertionError;
}

View File

@@ -1,414 +0,0 @@
// Type definitions for chai 3.4.0
// Project: http://chaijs.com/
// Definitions by: Jed Mao <https://github.com/jedmao/>,
// Bart van der Schoor <https://github.com/Bartvds>,
// Andrew Brown <https://github.com/AGBrown>,
// Olivier Chevet <https://github.com/olivr70>,
// Matt Wistrand <https://github.com/mwistrand>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
// <reference path="../assertion-error/assertion-error.d.ts"/>
declare namespace Chai {
interface ChaiStatic {
expect: ExpectStatic;
should(): Should;
/**
* Provides a way to extend the internals of Chai
*/
use(fn: (chai: any, utils: any) => void): ChaiStatic;
assert: AssertStatic;
config: Config;
AssertionError: typeof AssertionError;
}
export interface ExpectStatic extends AssertionStatic {
fail(actual?: any, expected?: any, message?: string, operator?: string): void;
}
export interface AssertStatic extends Assert {
}
export interface AssertionStatic {
(target: any, message?: string): Assertion;
}
interface ShouldAssertion {
equal(value1: any, value2: any, message?: string): void;
Throw: ShouldThrow;
throw: ShouldThrow;
exist(value: any, message?: string): void;
}
interface Should extends ShouldAssertion {
not: ShouldAssertion;
fail(actual: any, expected: any, message?: string, operator?: string): void;
}
interface ShouldThrow {
(actual: Function): void;
(actual: Function, expected: string|RegExp, message?: string): void;
(actual: Function, constructor: Error|Function, expected?: string|RegExp, message?: string): void;
}
interface Assertion extends LanguageChains, NumericComparison, TypeComparison {
not: Assertion;
deep: Deep;
any: KeyFilter;
all: KeyFilter;
a: TypeComparison;
an: TypeComparison;
include: Include;
includes: Include;
contain: Include;
contains: Include;
ok: Assertion;
true: Assertion;
false: Assertion;
null: Assertion;
undefined: Assertion;
NaN: Assertion;
exist: Assertion;
empty: Assertion;
arguments: Assertion;
Arguments: Assertion;
equal: Equal;
equals: Equal;
eq: Equal;
eql: Equal;
eqls: Equal;
property: Property;
ownProperty: OwnProperty;
haveOwnProperty: OwnProperty;
ownPropertyDescriptor: OwnPropertyDescriptor;
haveOwnPropertyDescriptor: OwnPropertyDescriptor;
length: Length;
lengthOf: Length;
match: Match;
matches: Match;
string(string: string, message?: string): Assertion;
keys: Keys;
key(string: string): Assertion;
throw: Throw;
throws: Throw;
Throw: Throw;
respondTo: RespondTo;
respondsTo: RespondTo;
itself: Assertion;
satisfy: Satisfy;
satisfies: Satisfy;
closeTo: CloseTo;
approximately: CloseTo;
members: Members;
increase: PropertyChange;
increases: PropertyChange;
decrease: PropertyChange;
decreases: PropertyChange;
change: PropertyChange;
changes: PropertyChange;
extensible: Assertion;
sealed: Assertion;
frozen: Assertion;
oneOf(list: any[], message?: string): Assertion;
}
interface LanguageChains {
to: Assertion;
be: Assertion;
been: Assertion;
is: Assertion;
that: Assertion;
which: Assertion;
and: Assertion;
has: Assertion;
have: Assertion;
with: Assertion;
at: Assertion;
of: Assertion;
same: Assertion;
}
interface NumericComparison {
above: NumberComparer;
gt: NumberComparer;
greaterThan: NumberComparer;
least: NumberComparer;
gte: NumberComparer;
below: NumberComparer;
lt: NumberComparer;
lessThan: NumberComparer;
most: NumberComparer;
lte: NumberComparer;
within(start: number, finish: number, message?: string): Assertion;
}
interface NumberComparer {
(value: number, message?: string): Assertion;
}
interface TypeComparison {
(type: string, message?: string): Assertion;
instanceof: InstanceOf;
instanceOf: InstanceOf;
}
interface InstanceOf {
(constructor: Object, message?: string): Assertion;
}
interface CloseTo {
(expected: number, delta: number, message?: string): Assertion;
}
interface Deep {
equal: Equal;
include: Include;
property: Property;
members: Members;
}
interface KeyFilter {
keys: Keys;
}
interface Equal {
(value: any, message?: string): Assertion;
}
interface Property {
(name: string, value?: any, message?: string): Assertion;
}
interface OwnProperty {
(name: string, message?: string): Assertion;
}
interface OwnPropertyDescriptor {
(name: string, descriptor: PropertyDescriptor, message?: string): Assertion;
(name: string, message?: string): Assertion;
}
interface Length extends LanguageChains, NumericComparison {
(length: number, message?: string): Assertion;
}
interface Include {
(value: Object, message?: string): Assertion;
(value: string, message?: string): Assertion;
(value: number, message?: string): Assertion;
keys: Keys;
members: Members;
any: KeyFilter;
all: KeyFilter;
}
interface Match {
(regexp: RegExp|string, message?: string): Assertion;
}
interface Keys {
(...keys: string[]): Assertion;
(keys: any[]): Assertion;
(keys: Object): Assertion;
}
interface Throw {
(): Assertion;
(expected: string, message?: string): Assertion;
(expected: RegExp, message?: string): Assertion;
(constructor: Error, expected?: string, message?: string): Assertion;
(constructor: Error, expected?: RegExp, message?: string): Assertion;
(constructor: Function, expected?: string, message?: string): Assertion;
(constructor: Function, expected?: RegExp, message?: string): Assertion;
}
interface RespondTo {
(method: string, message?: string): Assertion;
}
interface Satisfy {
(matcher: Function, message?: string): Assertion;
}
interface Members {
(set: any[], message?: string): Assertion;
}
interface PropertyChange {
(object: Object, prop: string, msg?: string): Assertion;
}
export interface Assert {
/**
* @param expression Expression to test for truthiness.
* @param message Message to display on error.
*/
(expression: any, message?: string): void;
fail(actual?: any, expected?: any, msg?: string, operator?: string): void;
ok(val: any, msg?: string): void;
isOk(val: any, msg?: string): void;
notOk(val: any, msg?: string): void;
isNotOk(val: any, msg?: string): void;
equal(act: any, exp: any, msg?: string): void;
notEqual(act: any, exp: any, msg?: string): void;
strictEqual(act: any, exp: any, msg?: string): void;
notStrictEqual(act: any, exp: any, msg?: string): void;
deepEqual(act: any, exp: any, msg?: string): void;
notDeepEqual(act: any, exp: any, msg?: string): void;
isTrue(val: any, msg?: string): void;
isFalse(val: any, msg?: string): void;
isNotTrue(val: any, msg?: string): void;
isNotFalse(val: any, msg?: string): void;
isNull(val: any, msg?: string): void;
isNotNull(val: any, msg?: string): void;
isUndefined(val: any, msg?: string): void;
isDefined(val: any, msg?: string): void;
isNaN(val: any, msg?: string): void;
isNotNaN(val: any, msg?: string): void;
isAbove(val: number, abv: number, msg?: string): void;
isBelow(val: number, blw: number, msg?: string): void;
isAtLeast(val: number, atlst: number, msg?: string): void;
isAtMost(val: number, atmst: number, msg?: string): void;
isFunction(val: any, msg?: string): void;
isNotFunction(val: any, msg?: string): void;
isObject(val: any, msg?: string): void;
isNotObject(val: any, msg?: string): void;
isArray(val: any, msg?: string): void;
isNotArray(val: any, msg?: string): void;
isString(val: any, msg?: string): void;
isNotString(val: any, msg?: string): void;
isNumber(val: any, msg?: string): void;
isNotNumber(val: any, msg?: string): void;
isBoolean(val: any, msg?: string): void;
isNotBoolean(val: any, msg?: string): void;
typeOf(val: any, type: string, msg?: string): void;
notTypeOf(val: any, type: string, msg?: string): void;
instanceOf(val: any, type: Function, msg?: string): void;
notInstanceOf(val: any, type: Function, msg?: string): void;
include(exp: string, inc: any, msg?: string): void;
include(exp: any[], inc: any, msg?: string): void;
notInclude(exp: string, inc: any, msg?: string): void;
notInclude(exp: any[], inc: any, msg?: string): void;
match(exp: any, re: RegExp, msg?: string): void;
notMatch(exp: any, re: RegExp, msg?: string): void;
property(obj: Object, prop: string, msg?: string): void;
notProperty(obj: Object, prop: string, msg?: string): void;
deepProperty(obj: Object, prop: string, msg?: string): void;
notDeepProperty(obj: Object, prop: string, msg?: string): void;
propertyVal(obj: Object, prop: string, val: any, msg?: string): void;
propertyNotVal(obj: Object, prop: string, val: any, msg?: string): void;
deepPropertyVal(obj: Object, prop: string, val: any, msg?: string): void;
deepPropertyNotVal(obj: Object, prop: string, val: any, msg?: string): void;
lengthOf(exp: any, len: number, msg?: string): void;
//alias frenzy
throw(fn: Function, msg?: string): void;
throw(fn: Function, regExp: RegExp): void;
throw(fn: Function, errType: Function, msg?: string): void;
throw(fn: Function, errType: Function, regExp: RegExp): void;
throws(fn: Function, msg?: string): void;
throws(fn: Function, regExp: RegExp): void;
throws(fn: Function, errType: Function, msg?: string): void;
throws(fn: Function, errType: Function, regExp: RegExp): void;
Throw(fn: Function, msg?: string): void;
Throw(fn: Function, regExp: RegExp): void;
Throw(fn: Function, errType: Function, msg?: string): void;
Throw(fn: Function, errType: Function, regExp: RegExp): void;
doesNotThrow(fn: Function, msg?: string): void;
doesNotThrow(fn: Function, regExp: RegExp): void;
doesNotThrow(fn: Function, errType: Function, msg?: string): void;
doesNotThrow(fn: Function, errType: Function, regExp: RegExp): void;
operator(val: any, operator: string, val2: any, msg?: string): void;
closeTo(act: number, exp: number, delta: number, msg?: string): void;
approximately(act: number, exp: number, delta: number, msg?: string): void;
sameMembers(set1: any[], set2: any[], msg?: string): void;
sameDeepMembers(set1: any[], set2: any[], msg?: string): void;
includeMembers(superset: any[], subset: any[], msg?: string): void;
ifError(val: any, msg?: string): void;
isExtensible(obj: {}, msg?: string): void;
extensible(obj: {}, msg?: string): void;
isNotExtensible(obj: {}, msg?: string): void;
notExtensible(obj: {}, msg?: string): void;
isSealed(obj: {}, msg?: string): void;
sealed(obj: {}, msg?: string): void;
isNotSealed(obj: {}, msg?: string): void;
notSealed(obj: {}, msg?: string): void;
isFrozen(obj: Object, msg?: string): void;
frozen(obj: Object, msg?: string): void;
isNotFrozen(obj: Object, msg?: string): void;
notFrozen(obj: Object, msg?: string): void;
oneOf(inList: any, list: any[], msg?: string): void;
}
export interface Config {
/**
* Default: false
*/
includeStack: boolean;
/**
* Default: true
*/
showDiff: boolean;
/**
* Default: 40
*/
truncateThreshold: number;
}
export class AssertionError {
constructor(message: string, _props?: any, ssf?: Function);
name: string;
message: string;
showDiff: boolean;
stack: string;
}
}
declare var chai: Chai.ChaiStatic;
declare module "chai" {
export = chai;
}
interface Object {
should: Chai.Assertion;
}

View File

@@ -1,668 +0,0 @@
// Type definitions for es6-shim v0.31.2
// Project: https://github.com/paulmillr/es6-shim
// Definitions by: Ron Buckton <http://github.com/rbuckton>
// Definitions: https://github.com/borisyankov/DefinitelyTyped
declare type PropertyKey = string | number | symbol;
interface IteratorResult<T> {
done: boolean;
value?: T;
}
interface IterableShim<T> {
/**
* Shim for an ES6 iterable. Not intended for direct use by user code.
*/
"_es6-shim iterator_"(): Iterator<T>;
}
interface Iterator<T> {
next(value?: any): IteratorResult<T>;
return?(value?: any): IteratorResult<T>;
throw?(e?: any): IteratorResult<T>;
}
interface IterableIteratorShim<T> extends IterableShim<T>, Iterator<T> {
/**
* Shim for an ES6 iterable iterator. Not intended for direct use by user code.
*/
"_es6-shim iterator_"(): IterableIteratorShim<T>;
}
interface StringConstructor {
/**
* Return the String value whose elements are, in order, the elements in the List elements.
* If length is 0, the empty string is returned.
*/
fromCodePoint(...codePoints: number[]): string;
/**
* String.raw is intended for use as a tag function of a Tagged Template String. When called
* as such the first argument will be a well formed template call site object and the rest
* parameter will contain the substitution values.
* @param template A well-formed template string call site representation.
* @param substitutions A set of substitution values.
*/
raw(template: TemplateStringsArray, ...substitutions: any[]): string;
}
interface String {
/**
* Returns a nonnegative integer Number less than 1114112 (0x110000) that is the code point
* value of the UTF-16 encoded code point starting at the string element at position pos in
* the String resulting from converting this object to a String.
* If there is no element at that position, the result is undefined.
* If a valid UTF-16 surrogate pair does not begin at pos, the result is the code unit at pos.
*/
codePointAt(pos: number): number;
/**
* Returns true if searchString appears as a substring of the result of converting this
* object to a String, at one or more positions that are
* greater than or equal to position; otherwise, returns false.
* @param searchString search string
* @param position If position is undefined, 0 is assumed, so as to search all of the String.
*/
includes(searchString: string, position?: number): boolean;
/**
* Returns true if the sequence of elements of searchString converted to a String is the
* same as the corresponding elements of this object (converted to a String) starting at
* endPosition length(this). Otherwise returns false.
*/
endsWith(searchString: string, endPosition?: number): boolean;
/**
* Returns a String value that is made from count copies appended together. If count is 0,
* T is the empty String is returned.
* @param count number of copies to append
*/
repeat(count: number): string;
/**
* Returns true if the sequence of elements of searchString converted to a String is the
* same as the corresponding elements of this object (converted to a String) starting at
* position. Otherwise returns false.
*/
startsWith(searchString: string, position?: number): boolean;
/**
* Returns an <a> HTML anchor element and sets the name attribute to the text value
* @param name
*/
anchor(name: string): string;
/** Returns a <big> HTML element */
big(): string;
/** Returns a <blink> HTML element */
blink(): string;
/** Returns a <b> HTML element */
bold(): string;
/** Returns a <tt> HTML element */
fixed(): string
/** Returns a <font> HTML element and sets the color attribute value */
fontcolor(color: string): string
/** Returns a <font> HTML element and sets the size attribute value */
fontsize(size: number): string;
/** Returns a <font> HTML element and sets the size attribute value */
fontsize(size: string): string;
/** Returns an <i> HTML element */
italics(): string;
/** Returns an <a> HTML element and sets the href attribute value */
link(url: string): string;
/** Returns a <small> HTML element */
small(): string;
/** Returns a <strike> HTML element */
strike(): string;
/** Returns a <sub> HTML element */
sub(): string;
/** Returns a <sup> HTML element */
sup(): string;
/**
* Shim for an ES6 iterable. Not intended for direct use by user code.
*/
"_es6-shim iterator_"(): IterableIteratorShim<string>;
}
interface ArrayConstructor {
/**
* Creates an array from an array-like object.
* @param arrayLike An array-like object to convert to an array.
* @param mapfn A mapping function to call on every element of the array.
* @param thisArg Value of 'this' used to invoke the mapfn.
*/
from<T, U>(arrayLike: ArrayLike<T>, mapfn: (v: T, k: number) => U, thisArg?: any): Array<U>;
/**
* Creates an array from an iterable object.
* @param iterable An iterable object to convert to an array.
* @param mapfn A mapping function to call on every element of the array.
* @param thisArg Value of 'this' used to invoke the mapfn.
*/
from<T, U>(iterable: IterableShim<T>, mapfn: (v: T, k: number) => U, thisArg?: any): Array<U>;
/**
* Creates an array from an array-like object.
* @param arrayLike An array-like object to convert to an array.
*/
from<T>(arrayLike: ArrayLike<T>): Array<T>;
/**
* Creates an array from an iterable object.
* @param iterable An iterable object to convert to an array.
*/
from<T>(iterable: IterableShim<T>): Array<T>;
/**
* Returns a new array from a set of elements.
* @param items A set of elements to include in the new array object.
*/
of<T>(...items: T[]): Array<T>;
}
interface Array<T> {
/**
* Returns the value of the first element in the array where predicate is true, and undefined
* otherwise.
* @param predicate find calls predicate once for each element of the array, in ascending
* order, until it finds one where predicate returns true. If such an element is found, find
* immediately returns that element value. Otherwise, find returns undefined.
* @param thisArg If provided, it will be used as the this value for each invocation of
* predicate. If it is not provided, undefined is used instead.
*/
find(predicate: (value: T, index: number, obj: Array<T>) => boolean, thisArg?: any): T;
/**
* Returns the index of the first element in the array where predicate is true, and undefined
* otherwise.
* @param predicate find calls predicate once for each element of the array, in ascending
* order, until it finds one where predicate returns true. If such an element is found, find
* immediately returns that element value. Otherwise, find returns undefined.
* @param thisArg If provided, it will be used as the this value for each invocation of
* predicate. If it is not provided, undefined is used instead.
*/
findIndex(predicate: (value: T) => boolean, thisArg?: any): number;
/**
* Returns the this object after filling the section identified by start and end with value
* @param value value to fill array section with
* @param start index to start filling the array at. If start is negative, it is treated as
* length+start where length is the length of the array.
* @param end index to stop filling the array at. If end is negative, it is treated as
* length+end.
*/
fill(value: T, start?: number, end?: number): T[];
/**
* Returns the this object after copying a section of the array identified by start and end
* to the same array starting at position target
* @param target If target is negative, it is treated as length+target where length is the
* length of the array.
* @param start If start is negative, it is treated as length+start. If end is negative, it
* is treated as length+end.
* @param end If not specified, length of the this object is used as its default value.
*/
copyWithin(target: number, start: number, end?: number): T[];
/**
* Returns an array of key, value pairs for every entry in the array
*/
entries(): IterableIteratorShim<[number, T]>;
/**
* Returns an list of keys in the array
*/
keys(): IterableIteratorShim<number>;
/**
* Returns an list of values in the array
*/
values(): IterableIteratorShim<T>;
/**
* Shim for an ES6 iterable. Not intended for direct use by user code.
*/
"_es6-shim iterator_"(): IterableIteratorShim<T>;
}
interface NumberConstructor {
/**
* The value of Number.EPSILON is the difference between 1 and the smallest value greater than 1
* that is representable as a Number value, which is approximately:
* 2.2204460492503130808472633361816 x 1016.
*/
EPSILON: number;
/**
* Returns true if passed value is finite.
* Unlike the global isFininte, Number.isFinite doesn't forcibly convert the parameter to a
* number. Only finite values of the type number, result in true.
* @param number A numeric value.
*/
isFinite(number: number): boolean;
/**
* Returns true if the value passed is an integer, false otherwise.
* @param number A numeric value.
*/
isInteger(number: number): boolean;
/**
* Returns a Boolean value that indicates whether a value is the reserved value NaN (not a
* number). Unlike the global isNaN(), Number.isNaN() doesn't forcefully convert the parameter
* to a number. Only values of the type number, that are also NaN, result in true.
* @param number A numeric value.
*/
isNaN(number: number): boolean;
/**
* Returns true if the value passed is a safe integer.
* @param number A numeric value.
*/
isSafeInteger(number: number): boolean;
/**
* The value of the largest integer n such that n and n + 1 are both exactly representable as
* a Number value.
* The value of Number.MIN_SAFE_INTEGER is 9007199254740991 2^53 1.
*/
MAX_SAFE_INTEGER: number;
/**
* The value of the smallest integer n such that n and n 1 are both exactly representable as
* a Number value.
* The value of Number.MIN_SAFE_INTEGER is 9007199254740991 ((2^53 1)).
*/
MIN_SAFE_INTEGER: number;
/**
* Converts a string to a floating-point number.
* @param string A string that contains a floating-point number.
*/
parseFloat(string: string): number;
/**
* Converts A string to an integer.
* @param s A string to convert into a number.
* @param radix A value between 2 and 36 that specifies the base of the number in numString.
* If this argument is not supplied, strings with a prefix of '0x' are considered hexadecimal.
* All other strings are considered decimal.
*/
parseInt(string: string, radix?: number): number;
}
interface ObjectConstructor {
/**
* Copy the values of all of the enumerable own properties from one or more source objects to a
* target object. Returns the target object.
* @param target The target object to copy to.
* @param sources One or more source objects to copy properties from.
*/
assign(target: any, ...sources: any[]): any;
/**
* Returns true if the values are the same value, false otherwise.
* @param value1 The first value.
* @param value2 The second value.
*/
is(value1: any, value2: any): boolean;
/**
* Sets the prototype of a specified object o to object proto or null. Returns the object o.
* @param o The object to change its prototype.
* @param proto The value of the new prototype or null.
* @remarks Requires `__proto__` support.
*/
setPrototypeOf(o: any, proto: any): any;
}
interface RegExp {
/**
* Returns a string indicating the flags of the regular expression in question. This field is read-only.
* The characters in this string are sequenced and concatenated in the following order:
*
* - "g" for global
* - "i" for ignoreCase
* - "m" for multiline
* - "u" for unicode
* - "y" for sticky
*
* If no flags are set, the value is the empty string.
*/
flags: string;
}
interface Math {
/**
* Returns the number of leading zero bits in the 32-bit binary representation of a number.
* @param x A numeric expression.
*/
clz32(x: number): number;
/**
* Returns the result of 32-bit multiplication of two numbers.
* @param x First number
* @param y Second number
*/
imul(x: number, y: number): number;
/**
* Returns the sign of the x, indicating whether x is positive, negative or zero.
* @param x The numeric expression to test
*/
sign(x: number): number;
/**
* Returns the base 10 logarithm of a number.
* @param x A numeric expression.
*/
log10(x: number): number;
/**
* Returns the base 2 logarithm of a number.
* @param x A numeric expression.
*/
log2(x: number): number;
/**
* Returns the natural logarithm of 1 + x.
* @param x A numeric expression.
*/
log1p(x: number): number;
/**
* Returns the result of (e^x - 1) of x (e raised to the power of x, where e is the base of
* the natural logarithms).
* @param x A numeric expression.
*/
expm1(x: number): number;
/**
* Returns the hyperbolic cosine of a number.
* @param x A numeric expression that contains an angle measured in radians.
*/
cosh(x: number): number;
/**
* Returns the hyperbolic sine of a number.
* @param x A numeric expression that contains an angle measured in radians.
*/
sinh(x: number): number;
/**
* Returns the hyperbolic tangent of a number.
* @param x A numeric expression that contains an angle measured in radians.
*/
tanh(x: number): number;
/**
* Returns the inverse hyperbolic cosine of a number.
* @param x A numeric expression that contains an angle measured in radians.
*/
acosh(x: number): number;
/**
* Returns the inverse hyperbolic sine of a number.
* @param x A numeric expression that contains an angle measured in radians.
*/
asinh(x: number): number;
/**
* Returns the inverse hyperbolic tangent of a number.
* @param x A numeric expression that contains an angle measured in radians.
*/
atanh(x: number): number;
/**
* Returns the square root of the sum of squares of its arguments.
* @param values Values to compute the square root for.
* If no arguments are passed, the result is +0.
* If there is only one argument, the result is the absolute value.
* If any argument is +Infinity or -Infinity, the result is +Infinity.
* If any argument is NaN, the result is NaN.
* If all arguments are either +0 or 0, the result is +0.
*/
hypot(...values: number[]): number;
/**
* Returns the integral part of the a numeric expression, x, removing any fractional digits.
* If x is already an integer, the result is x.
* @param x A numeric expression.
*/
trunc(x: number): number;
/**
* Returns the nearest single precision float representation of a number.
* @param x A numeric expression.
*/
fround(x: number): number;
/**
* Returns an implementation-dependent approximation to the cube root of number.
* @param x A numeric expression.
*/
cbrt(x: number): number;
}
interface PromiseLike<T> {
/**
* Attaches callbacks for the resolution and/or rejection of the Promise.
* @param onfulfilled The callback to execute when the Promise is resolved.
* @param onrejected The callback to execute when the Promise is rejected.
* @returns A Promise for the completion of which ever callback is executed.
*/
then<TResult>(onfulfilled?: (value: T) => TResult | PromiseLike<TResult>, onrejected?: (reason: any) => TResult | PromiseLike<TResult>): PromiseLike<TResult>;
then<TResult>(onfulfilled?: (value: T) => TResult | PromiseLike<TResult>, onrejected?: (reason: any) => void): PromiseLike<TResult>;
}
/**
* Represents the completion of an asynchronous operation
*/
interface Promise<T> {
/**
* Attaches callbacks for the resolution and/or rejection of the Promise.
* @param onfulfilled The callback to execute when the Promise is resolved.
* @param onrejected The callback to execute when the Promise is rejected.
* @returns A Promise for the completion of which ever callback is executed.
*/
then<TResult>(onfulfilled?: (value: T) => TResult | PromiseLike<TResult>, onrejected?: (reason: any) => TResult | PromiseLike<TResult>): Promise<TResult>;
then<TResult>(onfulfilled?: (value: T) => TResult | PromiseLike<TResult>, onrejected?: (reason: any) => void): Promise<TResult>;
/**
* Attaches a callback for only the rejection of the Promise.
* @param onrejected The callback to execute when the Promise is rejected.
* @returns A Promise for the completion of the callback.
*/
catch(onrejected?: (reason: any) => T | PromiseLike<T>): Promise<T>;
catch(onrejected?: (reason: any) => void): Promise<T>;
}
interface PromiseConstructor {
/**
* A reference to the prototype.
*/
prototype: Promise<any>;
/**
* Creates a new Promise.
* @param executor A callback used to initialize the promise. This callback is passed two arguments:
* a resolve callback used resolve the promise with a value or the result of another promise,
* and a reject callback used to reject the promise with a provided reason or error.
*/
new <T>(executor: (resolve: (value?: T | PromiseLike<T>) => void, reject: (reason?: any) => void) => void): Promise<T>;
/**
* Creates a Promise that is resolved with an array of results when all of the provided Promises
* resolve, or rejected when any Promise is rejected.
* @param values An array of Promises.
* @returns A new Promise.
*/
all<T>(values: IterableShim<T | PromiseLike<T>>): Promise<T[]>;
/**
* Creates a Promise that is resolved or rejected when any of the provided Promises are resolved
* or rejected.
* @param values An array of Promises.
* @returns A new Promise.
*/
race<T>(values: IterableShim<T | PromiseLike<T>>): Promise<T>;
/**
* Creates a new rejected promise for the provided reason.
* @param reason The reason the promise was rejected.
* @returns A new rejected Promise.
*/
reject(reason: any): Promise<void>;
/**
* Creates a new rejected promise for the provided reason.
* @param reason The reason the promise was rejected.
* @returns A new rejected Promise.
*/
reject<T>(reason: any): Promise<T>;
/**
* Creates a new resolved promise for the provided value.
* @param value A promise.
* @returns A promise whose internal state matches the provided promise.
*/
resolve<T>(value: T | PromiseLike<T>): Promise<T>;
/**
* Creates a new resolved promise .
* @returns A resolved promise.
*/
resolve(): Promise<void>;
}
declare var Promise: PromiseConstructor;
interface Map<K, V> {
clear(): void;
delete(key: K): boolean;
forEach(callbackfn: (value: V, index: K, map: Map<K, V>) => void, thisArg?: any): void;
get(key: K): V;
has(key: K): boolean;
set(key: K, value?: V): Map<K, V>;
size: number;
entries(): IterableIteratorShim<[K, V]>;
keys(): IterableIteratorShim<K>;
values(): IterableIteratorShim<V>;
}
interface MapConstructor {
new <K, V>(): Map<K, V>;
new <K, V>(iterable: IterableShim<[K, V]>): Map<K, V>;
prototype: Map<any, any>;
}
declare var Map: MapConstructor;
interface Set<T> {
add(value: T): Set<T>;
clear(): void;
delete(value: T): boolean;
forEach(callbackfn: (value: T, index: T, set: Set<T>) => void, thisArg?: any): void;
has(value: T): boolean;
size: number;
entries(): IterableIteratorShim<[T, T]>;
keys(): IterableIteratorShim<T>;
values(): IterableIteratorShim<T>;
}
interface SetConstructor {
new <T>(): Set<T>;
new <T>(iterable: IterableShim<T>): Set<T>;
prototype: Set<any>;
}
declare var Set: SetConstructor;
interface WeakMap<K, V> {
delete(key: K): boolean;
get(key: K): V;
has(key: K): boolean;
set(key: K, value?: V): WeakMap<K, V>;
}
interface WeakMapConstructor {
new <K, V>(): WeakMap<K, V>;
new <K, V>(iterable: IterableShim<[K, V]>): WeakMap<K, V>;
prototype: WeakMap<any, any>;
}
declare var WeakMap: WeakMapConstructor;
interface WeakSet<T> {
add(value: T): WeakSet<T>;
delete(value: T): boolean;
has(value: T): boolean;
}
interface WeakSetConstructor {
new <T>(): WeakSet<T>;
new <T>(iterable: IterableShim<T>): WeakSet<T>;
prototype: WeakSet<any>;
}
declare var WeakSet: WeakSetConstructor;
declare module Reflect {
function apply(target: Function, thisArgument: any, argumentsList: ArrayLike<any>): any;
function construct(target: Function, argumentsList: ArrayLike<any>): any;
function defineProperty(target: any, propertyKey: PropertyKey, attributes: PropertyDescriptor): boolean;
function deleteProperty(target: any, propertyKey: PropertyKey): boolean;
function enumerate(target: any): IterableIteratorShim<any>;
function get(target: any, propertyKey: PropertyKey, receiver?: any): any;
function getOwnPropertyDescriptor(target: any, propertyKey: PropertyKey): PropertyDescriptor;
function getPrototypeOf(target: any): any;
function has(target: any, propertyKey: PropertyKey): boolean;
function isExtensible(target: any): boolean;
function ownKeys(target: any): Array<PropertyKey>;
function preventExtensions(target: any): boolean;
function set(target: any, propertyKey: PropertyKey, value: any, receiver?: any): boolean;
function setPrototypeOf(target: any, proto: any): boolean;
}
declare module "es6-shim" {
var String: StringConstructor;
var Array: ArrayConstructor;
var Number: NumberConstructor;
var Math: Math;
var Object: ObjectConstructor;
var Map: MapConstructor;
var Set: SetConstructor;
var WeakMap: WeakMapConstructor;
var WeakSet: WeakSetConstructor;
var Promise: PromiseConstructor;
module Reflect {
function apply(target: Function, thisArgument: any, argumentsList: ArrayLike<any>): any;
function construct(target: Function, argumentsList: ArrayLike<any>): any;
function defineProperty(target: any, propertyKey: PropertyKey, attributes: PropertyDescriptor): boolean;
function deleteProperty(target: any, propertyKey: PropertyKey): boolean;
function enumerate(target: any): Iterator<any>;
function get(target: any, propertyKey: PropertyKey, receiver?: any): any;
function getOwnPropertyDescriptor(target: any, propertyKey: PropertyKey): PropertyDescriptor;
function getPrototypeOf(target: any): any;
function has(target: any, propertyKey: PropertyKey): boolean;
function isExtensible(target: any): boolean;
function ownKeys(target: any): Array<PropertyKey>;
function preventExtensions(target: any): boolean;
function set(target: any, propertyKey: PropertyKey, value: any, receiver?: any): boolean;
function setPrototypeOf(target: any, proto: any): boolean;
}
}

View File

@@ -1,508 +0,0 @@
// Type definitions for Jasmine 2.2
// Project: http://jasmine.github.io/
// Definitions by: Boris Yankov <https://github.com/borisyankov/>, Theodore Brown <https://github.com/theodorejb>, David Pärsson <https://github.com/davidparsson/>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
// For ddescribe / iit use : https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/karma-jasmine/karma-jasmine.d.ts
declare function describe(description: string, specDefinitions: () => void): void;
declare function fdescribe(description: string, specDefinitions: () => void): void;
declare function xdescribe(description: string, specDefinitions: () => void): void;
declare function it(expectation: string, assertion?: () => void, timeout?: number): void;
declare function it(expectation: string, assertion?: (done: DoneFn) => void, timeout?: number): void;
declare function fit(expectation: string, assertion?: () => void, timeout?: number): void;
declare function fit(expectation: string, assertion?: (done: DoneFn) => void, timeout?: number): void;
declare function xit(expectation: string, assertion?: () => void, timeout?: number): void;
declare function xit(expectation: string, assertion?: (done: DoneFn) => void, timeout?: number): void;
/** If you call the function pending anywhere in the spec body, no matter the expectations, the spec will be marked pending. */
declare function pending(reason?: string): void;
declare function beforeEach(action: () => void, timeout?: number): void;
declare function beforeEach(action: (done: DoneFn) => void, timeout?: number): void;
declare function afterEach(action: () => void, timeout?: number): void;
declare function afterEach(action: (done: DoneFn) => void, timeout?: number): void;
declare function beforeAll(action: () => void, timeout?: number): void;
declare function beforeAll(action: (done: DoneFn) => void, timeout?: number): void;
declare function afterAll(action: () => void, timeout?: number): void;
declare function afterAll(action: (done: DoneFn) => void, timeout?: number): void;
declare function expect(spy: Function): jasmine.Matchers;
declare function expect(actual: any): jasmine.Matchers;
declare function fail(e?: any): void;
/** Action method that should be called when the async work is complete */
interface DoneFn extends Function {
(): void;
/** fails the spec and indicates that it has completed. If the message is an Error, Error.message is used */
fail: (message?: Error|string) => void;
}
declare function spyOn(object: any, method: string): jasmine.Spy;
declare function runs(asyncMethod: Function): void;
declare function waitsFor(latchMethod: () => boolean, failureMessage?: string, timeout?: number): void;
declare function waits(timeout?: number): void;
declare namespace jasmine {
var clock: () => Clock;
function any(aclass: any): Any;
function anything(): Any;
function arrayContaining(sample: any[]): ArrayContaining;
function objectContaining(sample: any): ObjectContaining;
function createSpy(name: string, originalFn?: Function): Spy;
function createSpyObj(baseName: string, methodNames: any[]): any;
function createSpyObj<T>(baseName: string, methodNames: any[]): T;
function pp(value: any): string;
function getEnv(): Env;
function addCustomEqualityTester(equalityTester: CustomEqualityTester): void;
function addMatchers(matchers: CustomMatcherFactories): void;
function stringMatching(str: string): Any;
function stringMatching(str: RegExp): Any;
interface Any {
new (expectedClass: any): any;
jasmineMatches(other: any): boolean;
jasmineToString(): string;
}
// taken from TypeScript lib.core.es6.d.ts, applicable to CustomMatchers.contains()
interface ArrayLike<T> {
length: number;
[n: number]: T;
}
interface ArrayContaining {
new (sample: any[]): any;
asymmetricMatch(other: any): boolean;
jasmineToString(): string;
}
interface ObjectContaining {
new (sample: any): any;
jasmineMatches(other: any, mismatchKeys: any[], mismatchValues: any[]): boolean;
jasmineToString(): string;
}
interface Block {
new (env: Env, func: SpecFunction, spec: Spec): any;
execute(onComplete: () => void): void;
}
interface WaitsBlock extends Block {
new (env: Env, timeout: number, spec: Spec): any;
}
interface WaitsForBlock extends Block {
new (env: Env, timeout: number, latchFunction: SpecFunction, message: string, spec: Spec): any;
}
interface Clock {
install(): void;
uninstall(): void;
/** Calls to any registered callback are triggered when the clock is ticked forward via the jasmine.clock().tick function, which takes a number of milliseconds. */
tick(ms: number): void;
mockDate(date?: Date): void;
}
interface CustomEqualityTester {
(first: any, second: any): boolean;
}
interface CustomMatcher {
compare<T>(actual: T, expected: T): CustomMatcherResult;
compare(actual: any, expected: any): CustomMatcherResult;
}
interface CustomMatcherFactory {
(util: MatchersUtil, customEqualityTesters: Array<CustomEqualityTester>): CustomMatcher;
}
interface CustomMatcherFactories {
[index: string]: CustomMatcherFactory;
}
interface CustomMatcherResult {
pass: boolean;
message?: string;
}
interface MatchersUtil {
equals(a: any, b: any, customTesters?: Array<CustomEqualityTester>): boolean;
contains<T>(haystack: ArrayLike<T> | string, needle: any, customTesters?: Array<CustomEqualityTester>): boolean;
buildFailureMessage(matcherName: string, isNot: boolean, actual: any, ...expected: Array<any>): string;
}
interface Env {
setTimeout: any;
clearTimeout: void;
setInterval: any;
clearInterval: void;
updateInterval: number;
currentSpec: Spec;
matchersClass: Matchers;
version(): any;
versionString(): string;
nextSpecId(): number;
addReporter(reporter: Reporter): void;
execute(): void;
describe(description: string, specDefinitions: () => void): Suite;
// ddescribe(description: string, specDefinitions: () => void): Suite; Not a part of jasmine. Angular team adds these
beforeEach(beforeEachFunction: () => void): void;
beforeAll(beforeAllFunction: () => void): void;
currentRunner(): Runner;
afterEach(afterEachFunction: () => void): void;
afterAll(afterAllFunction: () => void): void;
xdescribe(desc: string, specDefinitions: () => void): XSuite;
it(description: string, func: () => void): Spec;
// iit(description: string, func: () => void): Spec; Not a part of jasmine. Angular team adds these
xit(desc: string, func: () => void): XSpec;
compareRegExps_(a: RegExp, b: RegExp, mismatchKeys: string[], mismatchValues: string[]): boolean;
compareObjects_(a: any, b: any, mismatchKeys: string[], mismatchValues: string[]): boolean;
equals_(a: any, b: any, mismatchKeys: string[], mismatchValues: string[]): boolean;
contains_(haystack: any, needle: any): boolean;
addCustomEqualityTester(equalityTester: CustomEqualityTester): void;
addMatchers(matchers: CustomMatcherFactories): void;
specFilter(spec: Spec): boolean;
throwOnExpectationFailure(value: boolean): void;
}
interface FakeTimer {
new (): any;
reset(): void;
tick(millis: number): void;
runFunctionsWithinRange(oldMillis: number, nowMillis: number): void;
scheduleFunction(timeoutKey: any, funcToCall: () => void, millis: number, recurring: boolean): void;
}
interface HtmlReporter {
new (): any;
}
interface HtmlSpecFilter {
new (): any;
}
interface Result {
type: string;
}
interface NestedResults extends Result {
description: string;
totalCount: number;
passedCount: number;
failedCount: number;
skipped: boolean;
rollupCounts(result: NestedResults): void;
log(values: any): void;
getItems(): Result[];
addResult(result: Result): void;
passed(): boolean;
}
interface MessageResult extends Result {
values: any;
trace: Trace;
}
interface ExpectationResult extends Result {
matcherName: string;
passed(): boolean;
expected: any;
actual: any;
message: string;
trace: Trace;
}
interface Trace {
name: string;
message: string;
stack: any;
}
interface PrettyPrinter {
new (): any;
format(value: any): void;
iterateObject(obj: any, fn: (property: string, isGetter: boolean) => void): void;
emitScalar(value: any): void;
emitString(value: string): void;
emitArray(array: any[]): void;
emitObject(obj: any): void;
append(value: any): void;
}
interface StringPrettyPrinter extends PrettyPrinter {
}
interface Queue {
new (env: any): any;
env: Env;
ensured: boolean[];
blocks: Block[];
running: boolean;
index: number;
offset: number;
abort: boolean;
addBefore(block: Block, ensure?: boolean): void;
add(block: any, ensure?: boolean): void;
insertNext(block: any, ensure?: boolean): void;
start(onComplete?: () => void): void;
isRunning(): boolean;
next_(): void;
results(): NestedResults;
}
interface Matchers {
new (env: Env, actual: any, spec: Env, isNot?: boolean): any;
env: Env;
actual: any;
spec: Env;
isNot?: boolean;
message(): any;
toBe(expected: any, expectationFailOutput?: any): boolean;
toEqual(expected: any, expectationFailOutput?: any): boolean;
toMatch(expected: string | RegExp, expectationFailOutput?: any): boolean;
toBeDefined(expectationFailOutput?: any): boolean;
toBeUndefined(expectationFailOutput?: any): boolean;
toBeNull(expectationFailOutput?: any): boolean;
toBeNaN(): boolean;
toBeTruthy(expectationFailOutput?: any): boolean;
toBeFalsy(expectationFailOutput?: any): boolean;
toHaveBeenCalled(): boolean;
toHaveBeenCalledWith(...params: any[]): boolean;
toHaveBeenCalledTimes(expected: number): boolean;
toContain(expected: any, expectationFailOutput?: any): boolean;
toBeLessThan(expected: number, expectationFailOutput?: any): boolean;
toBeGreaterThan(expected: number, expectationFailOutput?: any): boolean;
toBeCloseTo(expected: number, precision?: any, expectationFailOutput?: any): boolean;
toThrow(expected?: any): boolean;
toThrowError(message?: string | RegExp): boolean;
toThrowError(expected?: new (...args: any[]) => Error, message?: string | RegExp): boolean;
not: Matchers;
Any: Any;
}
interface Reporter {
reportRunnerStarting(runner: Runner): void;
reportRunnerResults(runner: Runner): void;
reportSuiteResults(suite: Suite): void;
reportSpecStarting(spec: Spec): void;
reportSpecResults(spec: Spec): void;
log(str: string): void;
}
interface MultiReporter extends Reporter {
addReporter(reporter: Reporter): void;
}
interface Runner {
new (env: Env): any;
execute(): void;
beforeEach(beforeEachFunction: SpecFunction): void;
afterEach(afterEachFunction: SpecFunction): void;
beforeAll(beforeAllFunction: SpecFunction): void;
afterAll(afterAllFunction: SpecFunction): void;
finishCallback(): void;
addSuite(suite: Suite): void;
add(block: Block): void;
specs(): Spec[];
suites(): Suite[];
topLevelSuites(): Suite[];
results(): NestedResults;
}
interface SpecFunction {
(spec?: Spec): void;
}
interface SuiteOrSpec {
id: number;
env: Env;
description: string;
queue: Queue;
}
interface Spec extends SuiteOrSpec {
new (env: Env, suite: Suite, description: string): any;
suite: Suite;
afterCallbacks: SpecFunction[];
spies_: Spy[];
results_: NestedResults;
matchersClass: Matchers;
getFullName(): string;
results(): NestedResults;
log(arguments: any): any;
runs(func: SpecFunction): Spec;
addToQueue(block: Block): void;
addMatcherResult(result: Result): void;
expect(actual: any): any;
waits(timeout: number): Spec;
waitsFor(latchFunction: SpecFunction, timeoutMessage?: string, timeout?: number): Spec;
fail(e?: any): void;
getMatchersClass_(): Matchers;
addMatchers(matchersPrototype: CustomMatcherFactories): void;
finishCallback(): void;
finish(onComplete?: () => void): void;
after(doAfter: SpecFunction): void;
execute(onComplete?: () => void): any;
addBeforesAndAftersToQueue(): void;
explodes(): void;
spyOn(obj: any, methodName: string, ignoreMethodDoesntExist: boolean): Spy;
removeAllSpies(): void;
}
interface XSpec {
id: number;
runs(): void;
}
interface Suite extends SuiteOrSpec {
new (env: Env, description: string, specDefinitions: () => void, parentSuite: Suite): any;
parentSuite: Suite;
getFullName(): string;
finish(onComplete?: () => void): void;
beforeEach(beforeEachFunction: SpecFunction): void;
afterEach(afterEachFunction: SpecFunction): void;
beforeAll(beforeAllFunction: SpecFunction): void;
afterAll(afterAllFunction: SpecFunction): void;
results(): NestedResults;
add(suiteOrSpec: SuiteOrSpec): void;
specs(): Spec[];
suites(): Suite[];
children(): any[];
execute(onComplete?: () => void): void;
}
interface XSuite {
execute(): void;
}
interface Spy {
(...params: any[]): any;
identity: string;
and: SpyAnd;
calls: Calls;
mostRecentCall: { args: any[]; };
argsForCall: any[];
wasCalled: boolean;
}
interface SpyAnd {
/** By chaining the spy with and.callThrough, the spy will still track all calls to it but in addition it will delegate to the actual implementation. */
callThrough(): Spy;
/** By chaining the spy with and.returnValue, all calls to the function will return a specific value. */
returnValue(val: any): Spy;
/** By chaining the spy with and.returnValues, all calls to the function will return specific values in order until it reaches the end of the return values list. */
returnValues(...values: any[]): Spy;
/** By chaining the spy with and.callFake, all calls to the spy will delegate to the supplied function. */
callFake(fn: Function): Spy;
/** By chaining the spy with and.throwError, all calls to the spy will throw the specified value. */
throwError(msg: string): Spy;
/** When a calling strategy is used for a spy, the original stubbing behavior can be returned at any time with and.stub. */
stub(): Spy;
}
interface Calls {
/** By chaining the spy with calls.any(), will return false if the spy has not been called at all, and then true once at least one call happens. **/
any(): boolean;
/** By chaining the spy with calls.count(), will return the number of times the spy was called **/
count(): number;
/** By chaining the spy with calls.argsFor(), will return the arguments passed to call number index **/
argsFor(index: number): any[];
/** By chaining the spy with calls.allArgs(), will return the arguments to all calls **/
allArgs(): any[];
/** By chaining the spy with calls.all(), will return the context (the this) and arguments passed all calls **/
all(): CallInfo[];
/** By chaining the spy with calls.mostRecent(), will return the context (the this) and arguments for the most recent call **/
mostRecent(): CallInfo;
/** By chaining the spy with calls.first(), will return the context (the this) and arguments for the first call **/
first(): CallInfo;
/** By chaining the spy with calls.reset(), will clears all tracking for a spy **/
reset(): void;
}
interface CallInfo {
/** The context (the this) for the call */
object: any;
/** All arguments passed to the call */
args: any[];
/** The return value of the call */
returnValue: any;
}
interface Util {
inherit(childClass: Function, parentClass: Function): any;
formatException(e: any): any;
htmlEscape(str: string): string;
argsToArray(args: any): any;
extend(destination: any, source: any): any;
}
interface JsApiReporter extends Reporter {
started: boolean;
finished: boolean;
result: any;
messages: any;
new (): any;
suites(): Suite[];
summarize_(suiteOrSpec: SuiteOrSpec): any;
results(): any;
resultsForSpec(specId: any): any;
log(str: any): any;
resultsForSpecs(specIds: any): any;
summarizeResult_(result: any): any;
}
interface Jasmine {
Spec: Spec;
clock: Clock;
util: Util;
}
export var HtmlReporter: HtmlReporter;
export var HtmlSpecFilter: HtmlSpecFilter;
export var DEFAULT_TIMEOUT_INTERVAL: number;
}

View File

@@ -1,397 +0,0 @@
// Type definitions for RequireJS 2.1.20
// Project: http://requirejs.org/
// Definitions by: Josh Baldwin <https://github.com/jbaldwin/>
// Definitions: https://github.com/borisyankov/DefinitelyTyped
/*
require-2.1.8.d.ts may be freely distributed under the MIT license.
Copyright (c) 2013 Josh Baldwin https://github.com/jbaldwin/require.d.ts
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
*/
declare module 'module' {
var mod: {
config: () => any;
id: string;
uri: string;
}
export = mod;
}
interface RequireError extends Error {
/**
* The error ID that maps to an ID on a web page.
**/
requireType: string;
/**
* Required modules.
**/
requireModules: string[];
/**
* The original error, if there is one (might be null).
**/
originalError: Error;
}
interface RequireShim {
/**
* List of dependencies.
**/
deps?: string[];
/**
* Name the module will be exported as.
**/
exports?: string;
/**
* Initialize function with all dependcies passed in,
* if the function returns a value then that value is used
* as the module export value instead of the object
* found via the 'exports' string.
* @param dependencies
* @return
**/
init?: (...dependencies: any[]) => any;
}
interface RequireConfig {
// The root path to use for all module lookups.
baseUrl?: string;
// Path mappings for module names not found directly under
// baseUrl.
paths?: { [key: string]: any; };
// Dictionary of Shim's.
// does not cover case of key->string[]
shim?: { [key: string]: RequireShim; };
/**
* For the given module prefix, instead of loading the
* module with the given ID, substitude a different
* module ID.
*
* @example
* requirejs.config({
* map: {
* 'some/newmodule': {
* 'foo': 'foo1.2'
* },
* 'some/oldmodule': {
* 'foo': 'foo1.0'
* }
* }
* });
**/
map?: {
[id: string]: {
[id: string]: string;
};
};
/**
* Allows pointing multiple module IDs to a module ID that contains a bundle of modules.
*
* @example
* requirejs.config({
* bundles: {
* 'primary': ['main', 'util', 'text', 'text!template.html'],
* 'secondary': ['text!secondary.html']
* }
* });
**/
bundles?: { [key: string]: string[]; };
/**
* AMD configurations, use module.config() to access in
* define() functions
**/
config?: { [id: string]: {}; };
/**
* Configures loading modules from CommonJS packages.
**/
packages?: {};
/**
* The number of seconds to wait before giving up on loading
* a script. The default is 7 seconds.
**/
waitSeconds?: number;
/**
* A name to give to a loading context. This allows require.js
* to load multiple versions of modules in a page, as long as
* each top-level require call specifies a unique context string.
**/
context?: string;
/**
* An array of dependencies to load.
**/
deps?: string[];
/**
* A function to pass to require that should be require after
* deps have been loaded.
* @param modules
**/
callback?: (...modules: any[]) => void;
/**
* If set to true, an error will be thrown if a script loads
* that does not call define() or have shim exports string
* value that can be checked.
**/
enforceDefine?: boolean;
/**
* If set to true, document.createElementNS() will be used
* to create script elements.
**/
xhtml?: boolean;
/**
* Extra query string arguments appended to URLs that RequireJS
* uses to fetch resources. Most useful to cache bust when
* the browser or server is not configured correctly.
*
* @example
* urlArgs: "bust= + (new Date()).getTime()
**/
urlArgs?: string;
/**
* Specify the value for the type="" attribute used for script
* tags inserted into the document by RequireJS. Default is
* "text/javascript". To use Firefox's JavasScript 1.8
* features, use "text/javascript;version=1.8".
**/
scriptType?: string;
/**
* If set to true, skips the data-main attribute scanning done
* to start module loading. Useful if RequireJS is embedded in
* a utility library that may interact with other RequireJS
* library on the page, and the embedded version should not do
* data-main loading.
**/
skipDataMain?: boolean;
/**
* Allow extending requirejs to support Subresource Integrity
* (SRI).
**/
onNodeCreated?: (node: HTMLScriptElement, config: RequireConfig, moduleName: string, url: string) => void;
}
// todo: not sure what to do with this guy
interface RequireModule {
/**
*
**/
config(): {};
}
/**
*
**/
interface RequireMap {
/**
*
**/
prefix: string;
/**
*
**/
name: string;
/**
*
**/
parentMap: RequireMap;
/**
*
**/
url: string;
/**
*
**/
originalName: string;
/**
*
**/
fullName: string;
}
interface Require {
/**
* Configure require.js
**/
config(config: RequireConfig): Require;
/**
* CommonJS require call
* @param module Module to load
* @return The loaded module
*/
(module: string): any;
/**
* Start the main app logic.
* Callback is optional.
* Can alternatively use deps and callback.
* @param modules Required modules to load.
**/
(modules: string[]): void;
/**
* @see Require()
* @param ready Called when required modules are ready.
**/
(modules: string[], ready: Function): void;
/**
* @see http://requirejs.org/docs/api.html#errbacks
* @param ready Called when required modules are ready.
**/
(modules: string[], ready: Function, errback: Function): void;
/**
* Generate URLs from require module
* @param module Module to URL
* @return URL string
**/
toUrl(module: string): string;
/**
* Returns true if the module has already been loaded and defined.
* @param module Module to check
**/
defined(module: string): boolean;
/**
* Returns true if the module has already been requested or is in the process of loading and should be available at some point.
* @param module Module to check
**/
specified(module: string): boolean;
/**
* On Error override
* @param err
**/
onError(err: RequireError, errback?: (err: RequireError) => void): void;
/**
* Undefine a module
* @param module Module to undefine.
**/
undef(module: string): void;
/**
* Semi-private function, overload in special instance of undef()
**/
onResourceLoad(context: Object, map: RequireMap, depArray: RequireMap[]): void;
}
interface RequireDefine {
/**
* Define Simple Name/Value Pairs
* @param config Dictionary of Named/Value pairs for the config.
**/
(config: { [key: string]: any; }): void;
/**
* Define function.
* @param func: The function module.
**/
(func: () => any): void;
/**
* Define function with dependencies.
* @param deps List of dependencies module IDs.
* @param ready Callback function when the dependencies are loaded.
* callback param deps module dependencies
* callback return module definition
**/
(deps: string[], ready: Function): void;
/**
* Define module with simplified CommonJS wrapper.
* @param ready
* callback require requirejs instance
* callback exports exports object
* callback module module
* callback return module definition
**/
(ready: (require: Require, exports: { [key: string]: any; }, module: RequireModule) => any): void;
/**
* Define a module with a name and dependencies.
* @param name The name of the module.
* @param deps List of dependencies module IDs.
* @param ready Callback function when the dependencies are loaded.
* callback deps module dependencies
* callback return module definition
**/
(name: string, deps: string[], ready: Function): void;
/**
* Define a module with a name.
* @param name The name of the module.
* @param ready Callback function when the dependencies are loaded.
* callback return module definition
**/
(name: string, ready: Function): void;
/**
* Used to allow a clear indicator that a global define function (as needed for script src browser loading) conforms
* to the AMD API, any global define function SHOULD have a property called "amd" whose value is an object.
* This helps avoid conflict with any other existing JavaScript code that could have defined a define() function
* that does not conform to the AMD API.
* define.amd.jQuery is specific to jQuery and indicates that the loader is able to account for multiple version
* of jQuery being loaded simultaneously.
*/
amd: Object;
}
// Ambient declarations for 'require' and 'define'
declare var requirejs: Require;
declare var require: Require;
declare var define: RequireDefine;

View File

@@ -1,6 +0,0 @@
/// <reference path="requirejs/require.d.ts" />
/// <reference path="es6-shim/es6-shim.d.ts" />
/// <reference path="assertion-error/assertion-error.d.ts" />
/// <reference path="chai/chai.d.ts" />
/// <reference path="jasmine/jasmine.d.ts" />

View File

@@ -1,7 +0,0 @@
// This file is a workaround for angular2-universal-preview version 0.84.2 relying on the declaration of
// Node's 'url' module. Ideally it would not declare dependencies on Node APIs except where it also supplies
// the definitions itself.
declare module 'url' {
export interface Url {}
}

View File

@@ -1,3 +0,0 @@
module.exports = {
devtool: 'inline-source-map'
};

View File

@@ -1,36 +1,54 @@
var isDevBuild = process.argv.indexOf('--env.prod') < 0;
var path = require('path'); var path = require('path');
var webpack = require('webpack'); var webpack = require('webpack');
var merge = require('extendify')({ isDeep: true, arrays: 'concat' }); var nodeExternals = require('webpack-node-externals');
var ExtractTextPlugin = require('extract-text-webpack-plugin'); var merge = require('webpack-merge');
var extractCSS = new ExtractTextPlugin('styles.css'); var allFilenamesExceptJavaScript = /\.(?!js(\?|$))([^.]+(\?|$))/;
var devConfig = require('./webpack.config.dev');
var prodConfig = require('./webpack.config.prod');
var isDevelopment = process.env.ASPNETCORE_ENVIRONMENT === 'Development';
module.exports = merge({ // Configuration in common to both client-side and server-side bundles
resolve: { var sharedConfig = {
extensions: [ '', '.js', '.ts' ] resolve: { extensions: [ '', '.js', '.ts' ] },
output: {
filename: '[name].js',
publicPath: '/dist/' // Webpack dev middleware, if enabled, handles requests for this URL prefix
}, },
module: { module: {
loaders: [ loaders: [
{ test: /\.ts$/, include: /ClientApp/, loader: 'ts-loader?silent=true' }, { test: /\.ts$/, include: /ClientApp/, loader: 'ts', query: { silent: true } },
{ test: /\.html$/, loader: 'raw-loader' }, { test: /\.html$/, loader: 'raw' },
{ test: /\.css/, loader: extractCSS.extract(['css']) } { test: /\.css$/, loader: 'to-string!css' },
{ test: /\.(png|jpg|jpeg|gif|svg)$/, loader: 'url', query: { limit: 25000 } }
] ]
}, }
entry: { };
main: ['./ClientApp/boot-client.ts']
}, // Configuration for client-side bundle suitable for running in browsers
output: { var clientBundleConfig = merge(sharedConfig, {
path: path.join(__dirname, 'wwwroot', 'dist'), entry: { 'main-client': './ClientApp/boot-client.ts' },
filename: '[name].js', output: { path: path.join(__dirname, './wwwroot/dist') },
publicPath: '/dist/' devtool: isDevBuild ? 'inline-source-map' : null,
},
plugins: [ plugins: [
extractCSS,
new webpack.DllReferencePlugin({ new webpack.DllReferencePlugin({
context: __dirname, context: __dirname,
manifest: require('./wwwroot/dist/vendor-manifest.json') manifest: require('./wwwroot/dist/vendor-manifest.json')
}) })
] ].concat(isDevBuild ? [] : [
}, isDevelopment ? devConfig : prodConfig); // Plugins that apply in production builds only
new webpack.optimize.OccurenceOrderPlugin(),
new webpack.optimize.UglifyJsPlugin()
])
});
// Configuration for server-side (prerendering) bundle suitable for running in Node
var serverBundleConfig = merge(sharedConfig, {
entry: { 'main-server': './ClientApp/boot-server.ts' },
output: {
libraryTarget: 'commonjs',
path: path.join(__dirname, './ClientApp/dist')
},
target: 'node',
devtool: 'inline-source-map',
externals: [nodeExternals({ whitelist: [allFilenamesExceptJavaScript] })] // Don't bundle .js files from node_modules
});
module.exports = [clientBundleConfig, serverBundleConfig];

View File

@@ -1,12 +0,0 @@
var webpack = require('webpack');
module.exports = {
plugins: [
new webpack.optimize.OccurenceOrderPlugin(),
new webpack.optimize.UglifyJsPlugin({
compress: { warnings: false },
minimize: true,
mangle: false // Due to https://github.com/angular/angular/issues/6678
})
]
};

View File

@@ -1,8 +1,8 @@
var isDevBuild = process.argv.indexOf('--env.prod') < 0;
var path = require('path'); var path = require('path');
var webpack = require('webpack'); var webpack = require('webpack');
var ExtractTextPlugin = require('extract-text-webpack-plugin'); var ExtractTextPlugin = require('extract-text-webpack-plugin');
var extractCSS = new ExtractTextPlugin('vendor.css'); var extractCSS = new ExtractTextPlugin('vendor.css');
var isDevelopment = process.env.ASPNETCORE_ENVIRONMENT === 'Development';
module.exports = { module.exports = {
resolve: { resolve: {
@@ -10,17 +10,12 @@ module.exports = {
}, },
module: { module: {
loaders: [ loaders: [
{ test: /\.(png|woff|woff2|eot|ttf|svg)$/, loader: 'url-loader?limit=100000' }, { test: /\.(png|woff|woff2|eot|ttf|svg)(\?|$)/, loader: 'url-loader?limit=100000' },
{ test: /\.css/, loader: extractCSS.extract(['css']) } { test: /\.css(\?|$)/, loader: extractCSS.extract(['css']) }
] ]
}, },
entry: { entry: {
vendor: [ vendor: [
'bootstrap',
'bootstrap/dist/css/bootstrap.css',
'es6-shim',
'style-loader',
'jquery',
'@angular/common', '@angular/common',
'@angular/compiler', '@angular/compiler',
'@angular/core', '@angular/core',
@@ -29,6 +24,15 @@ module.exports = {
'@angular/platform-browser-dynamic', '@angular/platform-browser-dynamic',
'@angular/router', '@angular/router',
'@angular/platform-server', '@angular/platform-server',
'angular2-universal',
'angular2-universal-polyfills',
'bootstrap',
'bootstrap/dist/css/bootstrap.css',
'es6-shim',
'es6-promise',
'font-awesome/css/font-awesome.css',
'jquery',
'zone.js',
] ]
}, },
output: { output: {
@@ -44,11 +48,7 @@ module.exports = {
path: path.join(__dirname, 'wwwroot', 'dist', '[name]-manifest.json'), path: path.join(__dirname, 'wwwroot', 'dist', '[name]-manifest.json'),
name: '[name]_[hash]' name: '[name]_[hash]'
}) })
].concat(isDevelopment ? [] : [ ].concat(isDevBuild ? [] : [
new webpack.optimize.UglifyJsPlugin({ new webpack.optimize.UglifyJsPlugin({ compress: { warnings: false } })
compress: { warnings: false },
minimize: true,
mangle: false // Due to https://github.com/angular/angular/issues/6678
})
]) ])
}; };

View File

@@ -5,16 +5,16 @@
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath> <VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
<TypeScriptCompileBlocked>true</TypeScriptCompileBlocked> <TypeScriptCompileBlocked>true</TypeScriptCompileBlocked>
</PropertyGroup> </PropertyGroup>
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.Props" Condition="'$(VSToolsPath)' != ''" /> <Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.Props" Condition="'$(VSToolsPath)' != ''" />
<PropertyGroup Label="Globals"> <PropertyGroup Label="Globals">
<ProjectGuid>85231b41-6998-49ae-abd2-5124c83dbef2</ProjectGuid> <ProjectGuid>85231b41-6998-49ae-abd2-5124c83dbef2</ProjectGuid>
<RootNamespace>KnockoutSpa</RootNamespace> <RootNamespace>KnockoutSpa</RootNamespace>
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\..\..\JavaScriptServices.sln\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath> <BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">.\obj</BaseIntermediateOutputPath>
<OutputPath Condition="'$(OutputPath)'=='' ">..\..\..\JavaScriptServices.sln\artifacts\bin\$(MSBuildProjectName)\</OutputPath> <OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath>
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
</PropertyGroup> </PropertyGroup>
<PropertyGroup> <PropertyGroup>
<SchemaVersion>2.0</SchemaVersion> <SchemaVersion>2.0</SchemaVersion>
<DevelopmentServerPort>2018</DevelopmentServerPort>
</PropertyGroup> </PropertyGroup>
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.targets" Condition="'$(VSToolsPath)' != ''" /> <Import Project="$(VSToolsPath)\DotNet.Web\Microsoft.DotNet.Web.targets" Condition="'$(VSToolsPath)' != ''" />
</Project> </Project>

View File

@@ -19,9 +19,7 @@
"ts-loader": "^0.8.1", "ts-loader": "^0.8.1",
"typescript": "^1.8.2", "typescript": "^1.8.2",
"url-loader": "^0.5.7", "url-loader": "^0.5.7",
"webpack": "^1.12.14" "webpack": "^1.12.14",
},
"dependencies": {
"webpack-hot-middleware": "^2.10.0" "webpack-hot-middleware": "^2.10.0"
} }
} }

View File

@@ -1,18 +1,18 @@
{ {
"dependencies": { "dependencies": {
"Microsoft.NETCore.App": { "Microsoft.NETCore.App": {
"version": "1.0.0", "version": "1.0.1",
"type": "platform" "type": "platform"
}, },
"Microsoft.AspNetCore.SpaServices": "1.0.0-*", "Microsoft.AspNetCore.SpaServices": "1.0.0-*",
"Microsoft.AspNetCore.Diagnostics": "1.0.0", "Microsoft.AspNetCore.Diagnostics": "1.0.0",
"Microsoft.AspNetCore.Mvc": "1.0.0", "Microsoft.AspNetCore.Mvc": "1.0.1",
"Microsoft.AspNetCore.Razor.Tools": { "Microsoft.AspNetCore.Razor.Tools": {
"version": "1.0.0-preview2-final", "version": "1.0.0-preview2-final",
"type": "build" "type": "build"
}, },
"Microsoft.AspNetCore.Server.IISIntegration": "1.0.0", "Microsoft.AspNetCore.Server.IISIntegration": "1.0.0",
"Microsoft.AspNetCore.Server.Kestrel": "1.0.0", "Microsoft.AspNetCore.Server.Kestrel": "1.0.1",
"Microsoft.AspNetCore.StaticFiles": "1.0.0", "Microsoft.AspNetCore.StaticFiles": "1.0.0",
"Microsoft.Extensions.Configuration.EnvironmentVariables": "1.0.0", "Microsoft.Extensions.Configuration.EnvironmentVariables": "1.0.0",
"Microsoft.Extensions.Configuration.Json": "1.0.0", "Microsoft.Extensions.Configuration.Json": "1.0.0",

View File

@@ -5,15 +5,22 @@ import { match, RouterContext } from 'react-router';
import createMemoryHistory from 'history/lib/createMemoryHistory'; import createMemoryHistory from 'history/lib/createMemoryHistory';
import routes from './routes'; import routes from './routes';
import configureStore from './configureStore'; import configureStore from './configureStore';
type BootResult = { html?: string, globals?: { [key: string]: any }, redirectUrl?: string};
export default function (params: any): Promise<{ html: string }> { export default function (params: any): Promise<{ html: string }> {
return new Promise<{ html: string, globals: { [key: string]: any } }>((resolve, reject) => { return new Promise<BootResult>((resolve, reject) => {
// Match the incoming request against the list of client-side routes // Match the incoming request against the list of client-side routes
match({ routes, location: params.location }, (error, redirectLocation, renderProps: any) => { match({ routes, location: params.location }, (error, redirectLocation, renderProps: any) => {
if (error) { if (error) {
throw error; throw error;
} }
// If there's a redirection, just send this information back to the host application
if (redirectLocation) {
resolve({ redirectUrl: redirectLocation.pathname });
return;
}
// If it didn't match any route, renderProps will be undefined // If it didn't match any route, renderProps will be undefined
if (!renderProps) { if (!renderProps) {
throw new Error(`The location '${ params.url }' doesn't match any route configured in react-router.`); throw new Error(`The location '${ params.url }' doesn't match any route configured in react-router.`);

View File

@@ -5,16 +5,16 @@
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath> <VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
<TypeScriptCompileBlocked>true</TypeScriptCompileBlocked> <TypeScriptCompileBlocked>true</TypeScriptCompileBlocked>
</PropertyGroup> </PropertyGroup>
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.Props" Condition="'$(VSToolsPath)' != ''" /> <Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.Props" Condition="'$(VSToolsPath)' != ''" />
<PropertyGroup Label="Globals"> <PropertyGroup Label="Globals">
<ProjectGuid>dbfc6db0-a6d1-4694-a108-1c604b988da3</ProjectGuid> <ProjectGuid>dbfc6db0-a6d1-4694-a108-1c604b988da3</ProjectGuid>
<RootNamespace>ReactReduxSpa</RootNamespace> <RootNamespace>ReactReduxSpa</RootNamespace>
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\..\..\JavaScriptServices.sln\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath> <BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">.\obj</BaseIntermediateOutputPath>
<OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath> <OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath>
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
</PropertyGroup> </PropertyGroup>
<PropertyGroup> <PropertyGroup>
<SchemaVersion>2.0</SchemaVersion> <SchemaVersion>2.0</SchemaVersion>
<DevelopmentServerPort>2018</DevelopmentServerPort>
</PropertyGroup> </PropertyGroup>
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.targets" Condition="'$(VSToolsPath)' != ''" /> <Import Project="$(VSToolsPath)\DotNet.Web\Microsoft.DotNet.Web.targets" Condition="'$(VSToolsPath)' != ''" />
</Project> </Project>

View File

@@ -1,29 +1,21 @@
{ {
"name": "WebApplicationBasic", "name": "WebApplicationBasic",
"version": "0.0.0", "version": "0.0.0",
"devDependencies": { "dependencies": {
"aspnet-prerendering": "^1.0.2",
"aspnet-webpack": "^1.0.6", "aspnet-webpack": "^1.0.6",
"aspnet-webpack-react": "^1.0.2", "aspnet-webpack-react": "^1.0.2",
"babel-core": "^6.5.2",
"babel-loader": "^6.2.3", "babel-loader": "^6.2.3",
"babel-preset-es2015": "^6.5.0", "babel-preset-es2015": "^6.5.0",
"babel-preset-react": "^6.5.0", "babel-preset-react": "^6.5.0",
"bootstrap": "^3.3.6", "bootstrap": "^3.3.6",
"css-loader": "^0.23.1", "css-loader": "^0.23.1",
"domain-task": "^2.0.0",
"extendify": "^1.0.0", "extendify": "^1.0.0",
"extract-text-webpack-plugin": "^1.0.1", "extract-text-webpack-plugin": "^1.0.1",
"file-loader": "^0.8.5", "file-loader": "^0.8.5",
"jquery": "^2.2.1", "jquery": "^2.2.1",
"style-loader": "^0.13.0",
"ts-loader": "^0.8.1",
"typescript": "^1.8.2",
"url-loader": "^0.5.7",
"webpack": "^1.12.14",
"webpack-hot-middleware": "^2.10.0"
},
"dependencies": {
"aspnet-prerendering": "^1.0.2",
"babel-core": "^6.5.2",
"domain-task": "^2.0.0",
"react": "^15.0.1", "react": "^15.0.1",
"react-dom": "^15.0.1", "react-dom": "^15.0.1",
"react-redux": "^4.4.4", "react-redux": "^4.4.4",
@@ -32,6 +24,12 @@
"redux": "^3.4.0", "redux": "^3.4.0",
"redux-thunk": "^2.0.1", "redux-thunk": "^2.0.1",
"redux-typed": "^1.0.0", "redux-typed": "^1.0.0",
"webpack-externals-plugin": "^1.0.0" "style-loader": "^0.13.0",
"ts-loader": "^0.8.1",
"typescript": "^1.8.2",
"url-loader": "^0.5.7",
"webpack-externals-plugin": "^1.0.0",
"webpack": "^1.12.14",
"webpack-hot-middleware": "^2.10.0"
} }
} }

View File

@@ -1,18 +1,18 @@
{ {
"dependencies": { "dependencies": {
"Microsoft.NETCore.App": { "Microsoft.NETCore.App": {
"version": "1.0.0", "version": "1.0.1",
"type": "platform" "type": "platform"
}, },
"Microsoft.AspNetCore.ReactServices": "1.0.0-*", "Microsoft.AspNetCore.ReactServices": "1.0.0-*",
"Microsoft.AspNetCore.Diagnostics": "1.0.0", "Microsoft.AspNetCore.Diagnostics": "1.0.0",
"Microsoft.AspNetCore.Mvc": "1.0.0", "Microsoft.AspNetCore.Mvc": "1.0.1",
"Microsoft.AspNetCore.Razor.Tools": { "Microsoft.AspNetCore.Razor.Tools": {
"version": "1.0.0-preview2-final", "version": "1.0.0-preview2-final",
"type": "build" "type": "build"
}, },
"Microsoft.AspNetCore.Server.IISIntegration": "1.0.0", "Microsoft.AspNetCore.Server.IISIntegration": "1.0.0",
"Microsoft.AspNetCore.Server.Kestrel": "1.0.0", "Microsoft.AspNetCore.Server.Kestrel": "1.0.1",
"Microsoft.AspNetCore.StaticFiles": "1.0.0", "Microsoft.AspNetCore.StaticFiles": "1.0.0",
"Microsoft.Extensions.Configuration.EnvironmentVariables": "1.0.0", "Microsoft.Extensions.Configuration.EnvironmentVariables": "1.0.0",
"Microsoft.Extensions.Configuration.Json": "1.0.0", "Microsoft.Extensions.Configuration.Json": "1.0.0",

View File

@@ -5,16 +5,16 @@
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath> <VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
<TypeScriptCompileBlocked>true</TypeScriptCompileBlocked> <TypeScriptCompileBlocked>true</TypeScriptCompileBlocked>
</PropertyGroup> </PropertyGroup>
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.Props" Condition="'$(VSToolsPath)' != ''" /> <Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.Props" Condition="'$(VSToolsPath)' != ''" />
<PropertyGroup Label="Globals"> <PropertyGroup Label="Globals">
<ProjectGuid>e9d1a695-f0e6-46f2-b5e3-72f4af805387</ProjectGuid> <ProjectGuid>e9d1a695-f0e6-46f2-b5e3-72f4af805387</ProjectGuid>
<RootNamespace>ReactSpa</RootNamespace> <RootNamespace>ReactSpa</RootNamespace>
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\..\..\JavaScriptServices.sln\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath> <BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">.\obj</BaseIntermediateOutputPath>
<OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath> <OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath>
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
</PropertyGroup> </PropertyGroup>
<PropertyGroup> <PropertyGroup>
<SchemaVersion>2.0</SchemaVersion> <SchemaVersion>2.0</SchemaVersion>
<DevelopmentServerPort>2018</DevelopmentServerPort>
</PropertyGroup> </PropertyGroup>
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.targets" Condition="'$(VSToolsPath)' != ''" /> <Import Project="$(VSToolsPath)\DotNet.Web\Microsoft.DotNet.Web.targets" Condition="'$(VSToolsPath)' != ''" />
</Project> </Project>

View File

@@ -4,6 +4,7 @@
"devDependencies": { "devDependencies": {
"aspnet-webpack": "^1.0.6", "aspnet-webpack": "^1.0.6",
"aspnet-webpack-react": "^1.0.2", "aspnet-webpack-react": "^1.0.2",
"babel-core": "^6.5.2",
"babel-loader": "^6.2.3", "babel-loader": "^6.2.3",
"babel-preset-es2015": "^6.5.0", "babel-preset-es2015": "^6.5.0",
"babel-preset-react": "^6.5.0", "babel-preset-react": "^6.5.0",
@@ -12,19 +13,16 @@
"extendify": "^1.0.0", "extendify": "^1.0.0",
"extract-text-webpack-plugin": "^1.0.1", "extract-text-webpack-plugin": "^1.0.1",
"file-loader": "^0.8.5", "file-loader": "^0.8.5",
"isomorphic-fetch": "^2.2.1",
"jquery": "^2.2.1", "jquery": "^2.2.1",
"react": "^15.0.1",
"react-dom": "^15.0.1",
"react-router": "^2.1.1",
"style-loader": "^0.13.0", "style-loader": "^0.13.0",
"ts-loader": "^0.8.1", "ts-loader": "^0.8.1",
"typescript": "^1.8.2", "typescript": "^1.8.2",
"url-loader": "^0.5.7", "url-loader": "^0.5.7",
"webpack": "^1.12.14", "webpack": "^1.12.14",
"webpack-hot-middleware": "^2.10.0" "webpack-hot-middleware": "^2.10.0"
},
"dependencies": {
"babel-core": "^6.5.2",
"isomorphic-fetch": "^2.2.1",
"react": "^15.0.1",
"react-dom": "^15.0.1",
"react-router": "^2.1.1"
} }
} }

View File

@@ -1,18 +1,18 @@
{ {
"dependencies": { "dependencies": {
"Microsoft.NETCore.App": { "Microsoft.NETCore.App": {
"version": "1.0.0", "version": "1.0.1",
"type": "platform" "type": "platform"
}, },
"Microsoft.AspNetCore.ReactServices": "1.0.0-*", "Microsoft.AspNetCore.ReactServices": "1.0.0-*",
"Microsoft.AspNetCore.Diagnostics": "1.0.0", "Microsoft.AspNetCore.Diagnostics": "1.0.0",
"Microsoft.AspNetCore.Mvc": "1.0.0", "Microsoft.AspNetCore.Mvc": "1.0.1",
"Microsoft.AspNetCore.Razor.Tools": { "Microsoft.AspNetCore.Razor.Tools": {
"version": "1.0.0-preview2-final", "version": "1.0.0-preview2-final",
"type": "build" "type": "build"
}, },
"Microsoft.AspNetCore.Server.IISIntegration": "1.0.0", "Microsoft.AspNetCore.Server.IISIntegration": "1.0.0",
"Microsoft.AspNetCore.Server.Kestrel": "1.0.0", "Microsoft.AspNetCore.Server.Kestrel": "1.0.1",
"Microsoft.AspNetCore.StaticFiles": "1.0.0", "Microsoft.AspNetCore.StaticFiles": "1.0.0",
"Microsoft.Extensions.Configuration.EnvironmentVariables": "1.0.0", "Microsoft.Extensions.Configuration.EnvironmentVariables": "1.0.0",
"Microsoft.Extensions.Configuration.Json": "1.0.0", "Microsoft.Extensions.Configuration.Json": "1.0.0",

View File

@@ -5,16 +5,16 @@
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath> <VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
<TypeScriptCompileBlocked>true</TypeScriptCompileBlocked> <TypeScriptCompileBlocked>true</TypeScriptCompileBlocked>
</PropertyGroup> </PropertyGroup>
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.Props" Condition="'$(VSToolsPath)' != ''" /> <Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.Props" Condition="'$(VSToolsPath)' != ''" />
<PropertyGroup Label="Globals"> <PropertyGroup Label="Globals">
<ProjectGuid>cb4398d6-b7f1-449a-ae02-828769679232</ProjectGuid> <ProjectGuid>cb4398d6-b7f1-449a-ae02-828769679232</ProjectGuid>
<RootNamespace>WebApplicationBasic</RootNamespace> <RootNamespace>WebApplicationBasic</RootNamespace>
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\..\..\JavaScriptServices.sln\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath> <BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">.\obj</BaseIntermediateOutputPath>
<OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath> <OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath>
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
</PropertyGroup> </PropertyGroup>
<PropertyGroup> <PropertyGroup>
<SchemaVersion>2.0</SchemaVersion> <SchemaVersion>2.0</SchemaVersion>
<DevelopmentServerPort>2018</DevelopmentServerPort>
</PropertyGroup> </PropertyGroup>
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.targets" Condition="'$(VSToolsPath)' != ''" /> <Import Project="$(VSToolsPath)\DotNet.Web\Microsoft.DotNet.Web.targets" Condition="'$(VSToolsPath)' != ''" />
</Project> </Project>

View File

@@ -1,17 +1,17 @@
{ {
"dependencies": { "dependencies": {
"Microsoft.NETCore.App": { "Microsoft.NETCore.App": {
"version": "1.0.0", "version": "1.0.1",
"type": "platform" "type": "platform"
}, },
"Microsoft.AspNetCore.Diagnostics": "1.0.0", "Microsoft.AspNetCore.Diagnostics": "1.0.0",
"Microsoft.AspNetCore.Mvc": "1.0.0", "Microsoft.AspNetCore.Mvc": "1.0.1",
"Microsoft.AspNetCore.Razor.Tools": { "Microsoft.AspNetCore.Razor.Tools": {
"version": "1.0.0-preview2-final", "version": "1.0.0-preview2-final",
"type": "build" "type": "build"
}, },
"Microsoft.AspNetCore.Server.IISIntegration": "1.0.0", "Microsoft.AspNetCore.Server.IISIntegration": "1.0.0",
"Microsoft.AspNetCore.Server.Kestrel": "1.0.0", "Microsoft.AspNetCore.Server.Kestrel": "1.0.1",
"Microsoft.AspNetCore.StaticFiles": "1.0.0", "Microsoft.AspNetCore.StaticFiles": "1.0.0",
"Microsoft.Extensions.Configuration.EnvironmentVariables": "1.0.0", "Microsoft.Extensions.Configuration.EnvironmentVariables": "1.0.0",
"Microsoft.Extensions.Configuration.Json": "1.0.0", "Microsoft.Extensions.Configuration.Json": "1.0.0",

View File

@@ -11,8 +11,8 @@ const isWindows = /^win/.test(process.platform);
const textFileExtensions = ['.gitignore', 'template_gitignore', '.config', '.cs', '.cshtml', 'Dockerfile', '.html', '.js', '.json', '.jsx', '.md', '.nuspec', '.ts', '.tsx', '.xproj']; const textFileExtensions = ['.gitignore', 'template_gitignore', '.config', '.cs', '.cshtml', 'Dockerfile', '.html', '.js', '.json', '.jsx', '.md', '.nuspec', '.ts', '.tsx', '.xproj'];
const yeomanGeneratorSource = './src/yeoman'; const yeomanGeneratorSource = './src/yeoman';
const templates: { [key: string]: { dir: string, dotNetNewId: string, displayName: string } } = { const templates: { [key: string]: { dir: string, dotNetNewId: string, displayName: string, forceInclusion?: RegExp } } = {
'angular-2': { dir: '../../templates/Angular2Spa/', dotNetNewId: 'Angular', displayName: 'Angular 2' }, 'angular-2': { dir: '../../templates/Angular2Spa/', dotNetNewId: 'Angular', displayName: 'Angular 2', forceInclusion: /^wwwroot\/dist\// },
'knockout': { dir: '../../templates/KnockoutSpa/', dotNetNewId: 'Knockout', displayName: 'Knockout.js' }, 'knockout': { dir: '../../templates/KnockoutSpa/', dotNetNewId: 'Knockout', displayName: 'Knockout.js' },
'react-redux': { dir: '../../templates/ReactReduxSpa/', dotNetNewId: 'ReactRedux', displayName: 'React.js and Redux' }, 'react-redux': { dir: '../../templates/ReactReduxSpa/', dotNetNewId: 'ReactRedux', displayName: 'React.js and Redux' },
'react': { dir: '../../templates/ReactSpa/', dotNetNewId: 'React', displayName: 'React.js' } 'react': { dir: '../../templates/ReactSpa/', dotNetNewId: 'React', displayName: 'React.js' }
@@ -28,7 +28,7 @@ function writeFileEnsuringDirExists(root: string, filename: string, contents: st
fs.writeFileSync(fullPath, contents); fs.writeFileSync(fullPath, contents);
} }
function listFilesExcludingGitignored(root: string): string[] { function listFilesExcludingGitignored(root: string, forceInclusion: RegExp): string[] {
// Note that the gitignore files, prior to be written by the generator, are called 'template_gitignore' // Note that the gitignore files, prior to be written by the generator, are called 'template_gitignore'
// instead of '.gitignore'. This is a workaround for Yeoman doing strange stuff with .gitignore files // instead of '.gitignore'. This is a workaround for Yeoman doing strange stuff with .gitignore files
// (it renames them to .npmignore, which is not helpful). // (it renames them to .npmignore, which is not helpful).
@@ -37,11 +37,11 @@ function listFilesExcludingGitignored(root: string): string[] {
? gitignore.compile(fs.readFileSync(gitIgnorePath, 'utf8')) ? gitignore.compile(fs.readFileSync(gitIgnorePath, 'utf8'))
: { accepts: () => true }; : { accepts: () => true };
return glob.sync('**/*', { cwd: root, dot: true, nodir: true }) return glob.sync('**/*', { cwd: root, dot: true, nodir: true })
.filter(fn => gitignoreEvaluator.accepts(fn)); .filter(fn => gitignoreEvaluator.accepts(fn) || (forceInclusion && forceInclusion.test(fn)));
} }
function writeTemplate(sourceRoot: string, destRoot: string, contentReplacements: { from: RegExp, to: string }[], filenameReplacements: { from: RegExp, to: string }[]) { function writeTemplate(sourceRoot: string, destRoot: string, contentReplacements: { from: RegExp, to: string }[], filenameReplacements: { from: RegExp, to: string }[], forceInclusion: RegExp) {
listFilesExcludingGitignored(sourceRoot).forEach(fn => { listFilesExcludingGitignored(sourceRoot, forceInclusion).forEach(fn => {
let sourceContent = fs.readFileSync(path.join(sourceRoot, fn)); let sourceContent = fs.readFileSync(path.join(sourceRoot, fn));
// For text files, replace hardcoded values with template tags // For text files, replace hardcoded values with template tags
@@ -89,7 +89,7 @@ function buildYeomanNpmPackage() {
]; ];
_.forEach(templates, (templateConfig, templateName) => { _.forEach(templates, (templateConfig, templateName) => {
const outputDir = path.join(outputTemplatesRoot, templateName); const outputDir = path.join(outputTemplatesRoot, templateName);
writeTemplate(templateConfig.dir, outputDir, contentReplacements, filenameReplacements); writeTemplate(templateConfig.dir, outputDir, contentReplacements, filenameReplacements, templateConfig.forceInclusion);
}); });
// Also copy the generator files (that's the compiled .js files, plus all other non-.ts files) // Also copy the generator files (that's the compiled .js files, plus all other non-.ts files)
@@ -125,7 +125,7 @@ function buildDotNetNewNuGetPackage() {
_.forEach(templates, (templateConfig, templateName) => { _.forEach(templates, (templateConfig, templateName) => {
const templateOutputDir = path.join(outputRoot, 'templates', templateName); const templateOutputDir = path.join(outputRoot, 'templates', templateName);
const templateOutputProjectDir = path.join(templateOutputDir, sourceProjectName); const templateOutputProjectDir = path.join(templateOutputDir, sourceProjectName);
writeTemplate(templateConfig.dir, templateOutputProjectDir, contentReplacements, filenameReplacements); writeTemplate(templateConfig.dir, templateOutputProjectDir, contentReplacements, filenameReplacements, templateConfig.forceInclusion);
// Add a .netnew.json file // Add a .netnew.json file
fs.writeFileSync(path.join(templateOutputDir, '.netnew.json'), JSON.stringify({ fs.writeFileSync(path.join(templateOutputDir, '.netnew.json'), JSON.stringify({
@@ -145,7 +145,7 @@ function buildDotNetNewNuGetPackage() {
const yeomanPackageVersion = JSON.parse(fs.readFileSync(path.join(yeomanGeneratorSource, 'package.json'), 'utf8')).version; const yeomanPackageVersion = JSON.parse(fs.readFileSync(path.join(yeomanGeneratorSource, 'package.json'), 'utf8')).version;
writeTemplate('./src/dotnetnew', outputRoot, [ writeTemplate('./src/dotnetnew', outputRoot, [
{ from: /\{version\}/g, to: yeomanPackageVersion }, { from: /\{version\}/g, to: yeomanPackageVersion },
], []); ], [], null);
const nugetExe = path.join(process.cwd(), './bin/NuGet.exe'); const nugetExe = path.join(process.cwd(), './bin/NuGet.exe');
const nugetStartInfo = { cwd: outputRoot, stdio: 'inherit' }; const nugetStartInfo = { cwd: outputRoot, stdio: 'inherit' };
if (isWindows) { if (isWindows) {
@@ -160,5 +160,21 @@ function buildDotNetNewNuGetPackage() {
rimraf.sync('./tmp'); rimraf.sync('./tmp');
} }
// TODO: Instead of just showing this warning, improve build script so it actually does build them
// in the correct format. Can do this once we've moved away from using ASPNETCORE_ENVIRONMENT to
// control the build output mode. The templates we warn about here are the ones where we ship some
// files that wouldn't normally be under source control (e.g., /wwwroot/dist/*).
const templatesWithForceIncludes = Object.getOwnPropertyNames(templates)
.filter(templateName => !!templates[templateName].forceInclusion);
if (templatesWithForceIncludes.length > 0) {
console.warn(`
---
WARNING: Ensure that the following templates are already built in the configuration desired for publishing.
For example, build the dist files in debug mode.
TEMPLATES: ${templatesWithForceIncludes.join(', ')}
---
`);
}
buildYeomanNpmPackage(); buildYeomanNpmPackage();
buildDotNetNewNuGetPackage(); buildDotNetNewNuGetPackage();

View File

@@ -0,0 +1,12 @@
Generates ASP.NET Core projects for single-page applications.
Can generate projects with:
* Angular 2
* Knockout
* React
* React with Redux
For more information about features and usage, see [this blog post](http://blog.stevensanderson.com/2016/05/02/angular2-react-knockout-apps-on-aspnet-core/).
To learn more about the underlying technologies, or to report any issues, see [this project's GitHub repo](https://github.com/aspnet/JavaScriptServices).

View File

@@ -5,6 +5,9 @@ import * as glob from 'glob';
const yosay = require('yosay'); const yosay = require('yosay');
const toPascalCase = require('to-pascal-case'); const toPascalCase = require('to-pascal-case');
type YeomanPrompt = (opt: yeoman.IPromptOptions | yeoman.IPromptOptions[], callback: (answers: any) => void) => void;
const optionOrPrompt: YeomanPrompt = require('yeoman-option-or-prompt');
const templates = [ const templates = [
{ value: 'angular-2', name: 'Angular 2' }, { value: 'angular-2', name: 'Angular 2' },
{ value: 'knockout', name: 'Knockout' }, { value: 'knockout', name: 'Knockout' },
@@ -14,16 +17,19 @@ const templates = [
class MyGenerator extends yeoman.Base { class MyGenerator extends yeoman.Base {
private _answers: any; private _answers: any;
private _optionOrPrompt: YeomanPrompt;
constructor(args: string | string[], options: any) { constructor(args: string | string[], options: any) {
super(args, options); super(args, options);
this._optionOrPrompt = optionOrPrompt;
this.log(yosay('Welcome to the ASP.NET Core Single-Page App generator!')); this.log(yosay('Welcome to the ASP.NET Core Single-Page App generator!'));
} }
prompting() { prompting() {
const done = this.async(); const done = this.async();
this.prompt([{ this.option('projectguid');
this._optionOrPrompt([{
type: 'list', type: 'list',
name: 'framework', name: 'framework',
message: 'Framework', message: 'Framework',
@@ -36,7 +42,7 @@ class MyGenerator extends yeoman.Base {
}], answers => { }], answers => {
this._answers = answers; this._answers = answers;
this._answers.namePascalCase = toPascalCase(answers.name); this._answers.namePascalCase = toPascalCase(answers.name);
this._answers.projectGuid = uuid.v4(); this._answers.projectGuid = this.options['projectguid'] || uuid.v4();
done(); done();
}); });
} }

View File

@@ -1,6 +1,6 @@
{ {
"name": "generator-aspnetcore-spa", "name": "generator-aspnetcore-spa",
"version": "0.2.6", "version": "0.3.0",
"description": "Single-Page App templates for ASP.NET Core", "description": "Single-Page App templates for ASP.NET Core",
"author": "Microsoft", "author": "Microsoft",
"license": "Apache-2.0", "license": "Apache-2.0",
@@ -10,11 +10,19 @@
"keywords": [ "keywords": [
"yeoman-generator" "yeoman-generator"
], ],
"bugs": {
"url": "https://github.com/aspnet/JavaScriptServices/issues"
},
"repository": {
"type": "git",
"url": "https://github.com/aspnet/JavaScriptServices.git"
},
"dependencies": { "dependencies": {
"glob": "^7.0.3", "glob": "^7.0.3",
"node-uuid": "^1.4.7", "node-uuid": "^1.4.7",
"to-pascal-case": "^1.0.0", "to-pascal-case": "^1.0.0",
"yeoman-generator": "^0.20.2", "yeoman-generator": "^0.20.2",
"yeoman-option-or-prompt": "^1.0.2",
"yosay": "^1.1.1" "yosay": "^1.1.1"
} }
} }