Compare commits

..

63 Commits

Author SHA1 Message Date
SteveSandersonMS
bd42deef7e Publish templates v0.6.2 2016-11-29 19:12:00 +00:00
SteveSandersonMS
939e0aeee0 Make 'fetchdata' components in templates compatible with latest TypeScript compiler 2016-11-29 19:10:48 +00:00
SteveSandersonMS
28b8136fa6 Detect legacy aspnet-prerendering mode earlier to fix #470 2016-11-29 17:23:14 +00:00
SteveSandersonMS
3ff4447924 Add XML docs to core packages 2016-11-29 16:03:15 +00:00
SteveSandersonMS
3b91ad9b39 Make core package project.json files conform to org-wide conventions 2016-11-29 14:02:26 +00:00
SteveSandersonMS
bebf24952e Add AssemblyInfo files to core packages 2016-11-29 13:04:21 +00:00
SteveSandersonMS
834301e50d Publish generator-aspnetcore-spa 0.6.1 2016-11-28 17:48:08 +00:00
SteveSandersonMS
03774253eb Fix AureliaSpa TypeScript compile error introduced by newer version of TypeScript 2016-11-28 17:35:00 +00:00
SteveSandersonMS
a3cba50e88 Make ReactReduxSpa able to do prerendering without node_modules at runtime 2016-11-28 17:30:09 +00:00
SteveSandersonMS
9cfea61f1e Make Angular2Spa able to do prerendering without node_modules at runtime 2016-11-28 17:30:04 +00:00
SteveSandersonMS
157b74a0cd Update Angular2Spa and ReactReduxSpa to use aspnet-prerendering 2.0.0 2016-11-28 16:56:02 +00:00
SteveSandersonMS
17f9ecec29 Support new prerendering mode that doesn't require you to deploy node_modules to production. This is a breaking change in aspnet-prerendering, hence the major version bump. The NuGet package is back-compatible though. 2016-11-28 16:56:02 +00:00
SteveSandersonMS
9f6b0b0573 Build SpaServices 'Node/Content/*.js' files from TypeScript sources 2016-11-28 16:56:02 +00:00
SteveSandersonMS
dd97ae7316 Specify publicPath in all vendor build configs (otherwise, file-loader won't generate correct URLs to any static resources from the vendor bundle) 2016-11-28 16:55:53 +00:00
SteveSandersonMS
ea2cfc277c Fix Angular2Spa "template parse errors" in production builds (was caused by html-loader's HTML minification feature) 2016-11-28 16:09:08 +00:00
SteveSandersonMS
fadb2b3127 Remove README.md files from templates, as much of the content is irrelevant or outdated. Fixes #463. 2016-11-25 10:19:55 +00:00
SteveSandersonMS
69a0a29057 Handle Webpack 2.1.0 beta 23 renaming 'loaders' to 'rules'. Fixes #460. 2016-11-25 10:15:38 +00:00
SteveSandersonMS
8401bbf33a Add global.json to templates specifying SDK preview 2 (otherwise, preview 3 breaks it). Will need to exclude/modify this file when emitting csproj projects. 2016-11-25 09:56:53 +00:00
Andrei Tserakhau
e3a4fad951 fix sln for templates 2016-11-21 15:05:42 +00:00
Scott Addie
3a4936dbf7 Add '-loader' suffix to all Webpack loader references 2016-11-21 10:14:37 +00:00
WrathZA
bbbcb5ef18 Update README.md
Fixed very minor spelling mistake on line 521.

You = Your
2016-11-18 17:03:24 +00:00
SteveSandersonMS
d6c6408457 In AureliaSpa, lock local copy of Webpack to 2.1.0-beta.25 (not any later 2.1.0 beta) due to fix #436 2016-11-18 15:46:05 +00:00
SteveSandersonMS
9b048c54d4 Remove 'redux-typed' from ReactReduxSpa template, making it more standard as a Redux application 2016-11-11 15:32:51 -08:00
SteveSandersonMS
cdd6c16dc6 Preparing to publish new generator-aspnetcore-spa 2016-11-10 13:38:36 -08:00
SteveSandersonMS
4f15bd6c50 Produce correct package.json from generator-aspnetcore-spa 2016-11-10 08:16:30 -08:00
SteveSandersonMS
828ed07cef In generator-aspnetcore-spa, offer user the choice of whether to include tests 2016-11-09 14:05:41 -08:00
SteveSandersonMS
a734a31745 Add Karma/Jasmine/Chai test starting point to Angular2Spa 2016-11-09 13:10:43 -08:00
SteveSandersonMS
ea81671828 Update docs to remove references to deprecated 'asp-prerender-webpack-config'. Fixes #359 2016-11-07 14:52:33 -08:00
SteveSandersonMS
b3dbb6e0f1 Yeoman generator, when running on Windows, ensures you have NPM 3+. Fixes #82. 2016-11-07 14:10:03 -08:00
SteveSandersonMS
11c45321aa In Angular2Spa, use angular2-template loader as a step towards AoT compilation. Implements #356 2016-11-07 13:45:29 -08:00
SteveSandersonMS
fadcb586c6 Support specifying environment variables for the Webpack dev middleware Node instance. Resolves #311. 2016-11-07 12:29:01 -08:00
SteveSandersonMS
2c97326721 In domain-task, avoid use of "new Function" because of CSP. Fixes #345 2016-11-07 12:21:02 -08:00
SteveSandersonMS
1b4dd93fa6 Update React MusicStore sample to use current technologies (TypeScript 2, .NET Core 1.0.1, etc.). Fixes #417 2016-11-07 10:16:41 -08:00
SteveSandersonMS
7ee8a7b15e Update aspnet-webpack peerDependency to allow Webpack 2.1.0beta+ as well as Webpack 1.x 2016-10-31 17:14:29 +00:00
SteveSandersonMS
64903fe0c6 Fix aspnet-webpack build on machines that don't already have tsd in the node_modules dir here 2016-10-31 16:49:37 +00:00
SteveSandersonMS
077f91847a Fix AngularServices NPM package dependency restoration following third-party package changes 2016-10-31 16:35:06 +00:00
SteveSandersonMS
7ee3346a72 Fix Angular 2 MusicStore sample so packages can be restored on NPM 2.x (started failing because peerDependencies ceased to be valid following third-party package updates) 2016-10-31 16:19:36 +00:00
SteveSandersonMS
f9145a43f6 In Angular2Spa server-side rendering, only render the <app> element, not an entire <html> doc 2016-10-31 11:46:00 +00:00
SteveSandersonMS
da51cd588b In WebpackDevMiddleware, when copying files, create any needed subdirectories. Fixes #408. 2016-10-31 10:49:31 +00:00
SteveSandersonMS
54f222e88f Update templates for Yarn compatibility 2016-10-28 17:36:55 +01:00
SteveSandersonMS
6259b7b938 In generator-aspnetcore-spa, use 'yarn' (if available) instead of 'npm' to restore dependencies because it's > 10x faster 2016-10-28 16:55:39 +01:00
SteveSandersonMS
dfcaae6fda Include AureliaSpa in generator-aspnetcore-spa 2016-10-28 15:52:15 +01:00
SteveSandersonMS
4b507004b1 In AureliaSpa, use Webpack build mode to decide whether or not to enable debug logging 2016-10-28 15:52:15 +01:00
SteveSandersonMS
bd86026bb9 Change AureliaSpa to use external source maps for compatibility with VS/VSCode debugging 2016-10-28 15:52:15 +01:00
SteveSandersonMS
996216c751 Tell aurelia-webpack-plugin to filter the set of dependencies it auto-imports. Note that this will have no effect until the next version of aurelia-webpack-plugin is published to NPM. 2016-10-28 15:52:14 +01:00
SteveSandersonMS
6bceb234d8 In AureliaSpa, use whatwg-fetch to provide type info 2016-10-28 15:52:14 +01:00
SteveSandersonMS
acfb253a40 Change AureliaSpa to use vendor bundle like the other templates 2016-10-28 15:52:04 +01:00
SteveSandersonMS
3087352ea1 Simplify AureliaSpa's webpack.config.js 2016-10-28 11:40:32 +01:00
kmkatsma
e60ea04f86 Add AureliaSpa template (#398) 2016-10-28 11:16:21 +01:00
SteveSandersonMS
867e60d7fd Take dependency on newer webpack-dev-middleware because it fixes ambiguities in path handling 2016-10-28 10:56:19 +01:00
SteveSandersonMS
8cf116bca8 Switch back to regular KoreBuild now it's updated 2016-10-24 16:29:28 +01:00
SteveSandersonMS
3dc9ac979c Add docs note about TypeScriptCompileBlocked as requested in #399 2016-10-24 10:26:00 +01:00
SteveSandersonMS
bf71e3e71c Publish updated generator-aspnetcore-spa 2016-10-24 10:09:58 +01:00
SteveSandersonMS
c140b5014a Fix WebApplicationBasic config 2016-10-24 10:08:14 +01:00
SteveSandersonMS
de9460fba5 Update KO template type dependencies. Fixes #397. 2016-10-24 10:06:26 +01:00
SteveSandersonMS
d858c09b7b Minor doc tweaks 2016-10-21 15:17:28 +01:00
SteveSandersonMS
ca6acc807d Attempt to fix headings in docs 2016-10-21 15:12:50 +01:00
SteveSandersonMS
8285bb0c74 Some extra links in docs 2016-10-21 15:10:30 +01:00
SteveSandersonMS
75abf1a2ab Add docs about debugging 2016-10-21 15:09:04 +01:00
SteveSandersonMS
a427d5f0f0 Fix source map generation in projects that also use ExtractTextPlugin 2016-10-21 13:53:34 +01:00
SteveSandersonMS
e0c18ab269 Publish updated Yeoman generators 2016-10-21 10:52:10 +01:00
SteveSandersonMS
f20ad391b6 Change ReactReduxSpa template to require redux-typed 2.0.0 (because the template uses TS 2.0 compiler) 2016-10-21 10:39:22 +01:00
SteveSandersonMS
496338ccca Publish redux-typed 2.0.0 which depends on TypeScript 2.0 for usage (its .d.ts files use the "/// <reference types="..." />" syntax) 2016-10-21 10:37:05 +01:00
175 changed files with 3047 additions and 5377 deletions

1
.gitignore vendored
View File

@@ -37,4 +37,5 @@ npm-debug.log
/templates/*/node_modules/
/templates/*/wwwroot/dist/
/templates/*/ClientApp/dist/
/templates/*/yarn.lock
.vscode/

View File

@@ -1,7 +1,7 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.25123.0
VisualStudioVersion = 14.0.25420.1
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Samples", "Samples", "{E6E88944-4800-40BA-8AF5-069EA3ADFEB8}"
EndProject
@@ -46,6 +46,10 @@ Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "MusicStore", "samples\react
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Angular", "Angular", "{4867A616-83D6-48DC-964D-6AE743596631}"
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Aurelia", "templates\AureliaSpa\Aurelia.xproj", "{33D8DAD9-74F9-471D-8BAD-55F828FAA736}"
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "KnockoutSpa", "templates\KnockoutSpa\KnockoutSpa.xproj", "{85231B41-6998-49AE-ABD2-5124C83DBEF2}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -108,6 +112,14 @@ Global
{C870A92C-9E3F-4BF2-82B8-5758545A8B7C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C870A92C-9E3F-4BF2-82B8-5758545A8B7C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C870A92C-9E3F-4BF2-82B8-5758545A8B7C}.Release|Any CPU.Build.0 = Release|Any CPU
{33D8DAD9-74F9-471D-8BAD-55F828FAA736}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{33D8DAD9-74F9-471D-8BAD-55F828FAA736}.Debug|Any CPU.Build.0 = Debug|Any CPU
{33D8DAD9-74F9-471D-8BAD-55F828FAA736}.Release|Any CPU.ActiveCfg = Release|Any CPU
{33D8DAD9-74F9-471D-8BAD-55F828FAA736}.Release|Any CPU.Build.0 = Release|Any CPU
{85231B41-6998-49AE-ABD2-5124C83DBEF2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{85231B41-6998-49AE-ABD2-5124C83DBEF2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{85231B41-6998-49AE-ABD2-5124C83DBEF2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{85231B41-6998-49AE-ABD2-5124C83DBEF2}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -126,5 +138,7 @@ Global
{E0EBA813-4478-4C02-B11D-FB3793113FE4} = {E6E88944-4800-40BA-8AF5-069EA3ADFEB8}
{C870A92C-9E3F-4BF2-82B8-5758545A8B7C} = {E0EBA813-4478-4C02-B11D-FB3793113FE4}
{4867A616-83D6-48DC-964D-6AE743596631} = {E6E88944-4800-40BA-8AF5-069EA3ADFEB8}
{33D8DAD9-74F9-471D-8BAD-55F828FAA736} = {727E6D58-6830-4792-96C6-E138A33959FB}
{85231B41-6998-49AE-ABD2-5124C83DBEF2} = {727E6D58-6830-4792-96C6-E138A33959FB}
EndGlobalSection
EndGlobal

View File

@@ -33,7 +33,7 @@ cd $PSScriptRoot
$repoFolder = $PSScriptRoot
$env:REPO_FOLDER = $repoFolder
$koreBuildZip="https://codeload.github.com/aspnet/KoreBuild/zip/stevesa/npm-in-series"
$koreBuildZip="https://github.com/aspnet/KoreBuild/archive/dev.zip"
if ($env:KOREBUILD_ZIP)
{
$koreBuildZip=$env:KOREBUILD_ZIP

View File

@@ -2,7 +2,7 @@
repoFolder="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
cd $repoFolder
koreBuildZip="https://codeload.github.com/aspnet/KoreBuild/zip/stevesa/npm-in-series"
koreBuildZip="https://github.com/aspnet/KoreBuild/archive/dev.zip"
if [ ! -z $KOREBUILD_ZIP ]; then
koreBuildZip=$KOREBUILD_ZIP
fi

View File

@@ -5,6 +5,8 @@
"angular2": "2.0.0-beta.15",
"angular2-aspnet": "^0.0.6",
"angular2-universal": "0.98.1",
"angular2-express-engine": "0.11.1",
"angular2-hapi-engine": "0.11.1",
"aspnet-prerendering": "^1.0.1",
"bootstrap": "^3.3.5",
"css": "^2.2.1",

View File

@@ -2,7 +2,7 @@ module.exports = {
devtool: 'inline-source-map',
module: {
loaders: [
{ test: /\.less$/, loader: 'style!css!less' }
{ test: /\.less$/, loader: 'style-loader!css-loader!less-loader' }
]
}
};

View File

@@ -5,7 +5,7 @@ var extractLESS = new ExtractTextPlugin('my-styles.css');
module.exports = {
module: {
loaders: [
{ test: /\.less$/, loader: extractLESS.extract(['css', 'less']) },
{ test: /\.less$/, loader: extractLESS.extract(['css-loader', 'less-loader']) },
]
},
plugins: [

View File

@@ -1,3 +1,4 @@
music-db.sqlite
/wwwroot/dist/
/node_modules/
yarn.lock

View File

@@ -5,19 +5,29 @@ import { match, RouterContext } from 'react-router';
import createMemoryHistory from 'history/lib/createMemoryHistory';
import { routes } from './routes';
import configureStore from './configureStore';
React;
type BootResult = { html?: string, globals?: { [key: string]: any }, redirectUrl?: 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({ routes, location: params.location }, (error, redirectLocation, renderProps: any) => {
if (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 (!renderProps) {
throw new Error(`The location '${ params.url }' doesn't match any route configured in react-router.`);
}
// Build an instance of the application
const history = createMemoryHistory(params.url);
const store = configureStore(history);
const store = configureStore();
const app = (
<Provider store={ store }>
<RouterContext {...renderProps} />

View File

@@ -1,21 +1,25 @@
import './styles/styles.css';
import 'bootstrap/dist/css/bootstrap.css';
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { browserHistory, Router } from 'react-router';
import { Provider } from 'react-redux';
React; // Need this reference otherwise TypeScript doesn't think we're using it and ignores the import
import './styles/styles.css';
import 'bootstrap/dist/css/bootstrap.css';
import configureStore from './configureStore';
import { syncHistoryWithStore } from 'react-router-redux';
import { routes } from './routes';
import configureStore from './configureStore';
import { ApplicationState } from './store';
// Get the application-wide store instance, prepopulating with state from the server where available.
const initialState = (window as any).initialReduxState as ApplicationState;
const store = configureStore(browserHistory, initialState);
const store = configureStore(initialState);
const history = syncHistoryWithStore(browserHistory, store);
// This code starts up the React app when it runs in a browser. It sets up the routing configuration
// and injects the app into a DOM element.
ReactDOM.render(
<Provider store={ store }>
<Router history={ browserHistory } children={ routes } />
<Router history={ history } children={ routes } />
</Provider>,
document.getElementById('react-app')
);

View File

@@ -1,28 +1,22 @@
import { createStore, applyMiddleware, compose, combineReducers } from 'redux';
import * as thunkModule from 'redux-thunk';
import { syncHistory, routeReducer } from 'react-router-redux';
import { createStore, applyMiddleware, compose, combineReducers, GenericStoreEnhancer } from 'redux';
import thunk from 'redux-thunk';
import { routerReducer } from 'react-router-redux';
import * as Store from './store';
import { typedToPlain } from 'redux-typed';
export default function configureStore(history: HistoryModule.History, initialState?: Store.ApplicationState) {
// Build middleware
const thunk = (thunkModule as any).default; // Workaround for TypeScript not importing thunk module as expected
const reduxRouterMiddleware = syncHistory(history);
const middlewares = [thunk, reduxRouterMiddleware, typedToPlain];
const devToolsExtension = null;//(window as any).devToolsExtension; // If devTools is installed, connect to it
const finalCreateStore = compose(
applyMiddleware(...middlewares),
export default function configureStore(initialState?: Store.ApplicationState) {
// Build middleware. These are functions that can process the actions before they reach the store.
const windowIfDefined = typeof window === 'undefined' ? null : window as any;
// If devTools is installed, connect to it
const devToolsExtension = windowIfDefined && windowIfDefined.devToolsExtension as () => GenericStoreEnhancer;
const createStoreWithMiddleware = compose(
applyMiddleware(thunk, typedToPlain),
devToolsExtension ? devToolsExtension() : f => f
)(createStore)
)(createStore);
// Combine all reducers
// Combine all reducers and instantiate the app-wide store instance
const allReducers = buildRootReducer(Store.reducers);
const store = finalCreateStore(allReducers, initialState) as Redux.Store;
// Required for replaying actions from devtools to work
reduxRouterMiddleware.listenForReplays(store);
const store = createStoreWithMiddleware(allReducers, initialState) as Redux.Store<Store.ApplicationState>;
// Enable Webpack hot module replacement for reducers
if (module.hot) {
@@ -36,5 +30,5 @@ export default function configureStore(history: HistoryModule.History, initialSt
}
function buildRootReducer(allReducers) {
return combineReducers(Object.assign({}, allReducers, { routing: routeReducer })) as Redux.Reducer;
return combineReducers<Store.ApplicationState>(Object.assign({}, allReducers, { routing: routerReducer }));
}

View File

@@ -1,45 +1,52 @@
{
"name": "MusicStore",
"name": "music-store",
"version": "0.0.0",
"devDependencies": {
"babel-loader": "^6.2.1",
"babel-plugin-react-transform": "^2.0.0",
"babel-preset-es2015": "^6.3.13",
"babel-preset-react": "^6.3.13",
"dependencies": {
"@types/react": "^0.14.29",
"@types/react-bootstrap": "^0.0.35",
"@types/react-dom": "^0.14.14",
"@types/react-redux": "^4.4.29",
"@types/react-router": "^2.0.30",
"@types/react-router-bootstrap": "^0.0.27",
"@types/react-router-redux": "^4.0.30",
"@types/redux": "3.5.27",
"@types/redux-thunk": "^2.1.28",
"@types/source-map": "^0.1.28",
"@types/uglify-js": "^2.0.27",
"@types/webpack": "^1.12.35",
"@types/webpack-env": "^1.12.1",
"@types/whatwg-fetch": "0.0.28",
"aspnet-prerendering": "^1.0.7",
"aspnet-webpack": "^1.0.17",
"aspnet-webpack-react": "^1.0.2",
"babel-core": "^6.5.2",
"babel-loader": "^6.2.3",
"babel-preset-es2015": "^6.5.0",
"babel-preset-react": "^6.5.0",
"bootstrap": "^3.3.6",
"css-loader": "^0.23.1",
"express": "^4.13.4",
"domain-task": "^2.0.1",
"event-source-polyfill": "^0.0.7",
"extract-text-webpack-plugin": "^1.0.1",
"file-loader": "^0.8.5",
"react-transform-hmr": "^1.0.2",
"jquery": "^2.2.1",
"react": "^15.3.2",
"react-bootstrap": "^0.30.6",
"react-dom": "^15.3.2",
"react-redux": "^4.4.5",
"react-router": "^2.8.1",
"react-router-bootstrap": "^0.23.1",
"react-router-redux": "^4.0.6",
"redux": "^3.6.0",
"redux-thunk": "^2.1.0",
"redux-typed": "^2.0.0",
"style-loader": "^0.13.0",
"ts-loader": "^0.8.0",
"typescript": "^1.7.5",
"ts-loader": "^0.8.1",
"typescript": "2.0.3",
"url-loader": "^0.5.7",
"webpack": "^1.12.12",
"webpack-dev-middleware": "^1.5.1",
"webpack-hot-middleware": "^2.6.4"
},
"dependencies": {
"aspnet-prerendering": "^1.0.0",
"aspnet-webpack": "^1.0.3",
"aspnet-webpack-react": "^1.0.1",
"bootstrap": "^3.3.6",
"domain-context": "^0.5.1",
"domain-task": "^2.0.0",
"history": "^2.0.0",
"isomorphic-fetch": "^2.2.1",
"memory-fs": "^0.3.0",
"react": "^0.14.7",
"react-bootstrap": "^0.28.2",
"react-dom": "^0.14.7",
"react-redux": "^4.2.1",
"react-router": "^2.0.0-rc5",
"react-router-bootstrap": "^0.20.1",
"react-router-redux": "^2.1.0",
"redux": "^3.2.1",
"redux-thunk": "^1.0.3",
"redux-typed": "^1.0.0",
"require-from-string": "^1.1.0",
"webpack-externals-plugin": "^1.0.0"
"webpack": "^1.13.2",
"webpack-hot-middleware": "^2.12.2",
"webpack-merge": "^0.14.1",
"webpack-node-externals": "^1.4.3"
}
}

View File

@@ -1,56 +1,83 @@
{
"version": "1.0.0-*",
"buildOptions": {
"emitEntryPoint": true,
"preserveCompilationContext": true
},
"runtimeOptions": {
"gcServer": true
},
"tooling": {
"defaultNamespace": "MusicStore"
},
"dependencies": {
"dependencies": {
"Microsoft.NETCore.App": {
"version": "1.0.0",
"version": "1.0.1",
"type": "platform"
},
"Microsoft.AspNetCore.ReactServices": "1.0.0-*",
"Microsoft.AspNetCore.Diagnostics": "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.Mvc": "1.0.0",
"Microsoft.AspNetCore.Mvc.TagHelpers": "1.0.0",
"Microsoft.AspNetCore.Server.Kestrel": "1.0.0",
"Microsoft.AspNetCore.Server.Kestrel": "1.0.1",
"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.AspNetCore.ReactServices": "1.0.0-*",
"AutoMapper": "5.0.2"
"Microsoft.Extensions.Configuration.EnvironmentVariables": "1.0.0",
"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": {
"netcoreapp1.0": {
"imports": [
"dotnet5.6",
"dnxcore50",
"portable-net45+win8"
]
}
},
"buildOptions": {
"emitEntryPoint": true,
"preserveCompilationContext": true,
"compile": {
"exclude": ["node_modules"]
}
},
"runtimeOptions": {
"configProperties": {
"System.GC.Server": true
}
},
"publishOptions": {
"exclude": [
"include": [
"appsettings.json",
"ClientApp/dist",
"node_modules",
"bower_components",
"**.xproj",
"**.user",
"**.vspscc"
"Views",
"web.config",
"wwwroot"
],
"exclude": [
"wwwroot/dist/*.map"
]
},
"scripts": {
"prepublish": [ "npm install" ],
"prepublish": [
"npm install",
"node node_modules/webpack/bin/webpack.js"
],
"postpublish": [ "dotnet publish-iis --publish-folder %publish:OutputPath% --framework %publish:FullTargetFramework%" ]
},
"tooling": {
"defaultNamespace": "MusicStore"
}
}

View File

@@ -4,7 +4,8 @@
"target": "es6",
"jsx": "preserve",
"sourceMap": true,
"experimentalDecorators": true
"experimentalDecorators": true,
"types": [ "webpack-env", "whatwg-fetch" ]
},
"exclude": [
"node_modules"

View File

@@ -1,45 +0,0 @@
{
"version": "v4",
"repo": "borisyankov/DefinitelyTyped",
"ref": "master",
"path": "typings",
"bundle": "typings/tsd.d.ts",
"installed": {
"react/react.d.ts": {
"commit": "e69fe60f2d6377ea4fae539493997b098f52cad1"
},
"react/react-dom.d.ts": {
"commit": "86dbea8fc37d9473fee465da4f0a21bea4f8cbd9"
},
"redux/redux.d.ts": {
"commit": "e69fe60f2d6377ea4fae539493997b098f52cad1"
},
"webpack/webpack-env.d.ts": {
"commit": "717a5fdb079f8dd7c19f1b22f7f656dd990f0ccf"
},
"react-redux/react-redux.d.ts": {
"commit": "717a5fdb079f8dd7c19f1b22f7f656dd990f0ccf"
},
"react-bootstrap/react-bootstrap.d.ts": {
"commit": "e69fe60f2d6377ea4fae539493997b098f52cad1"
},
"react-router/react-router.d.ts": {
"commit": "e69fe60f2d6377ea4fae539493997b098f52cad1"
},
"react-router/history.d.ts": {
"commit": "e69fe60f2d6377ea4fae539493997b098f52cad1"
},
"react-router-bootstrap/react-router-bootstrap.d.ts": {
"commit": "e69fe60f2d6377ea4fae539493997b098f52cad1"
},
"react-router-redux/react-router-redux.d.ts": {
"commit": "e69fe60f2d6377ea4fae539493997b098f52cad1"
},
"redux-thunk/redux-thunk.d.ts": {
"commit": "e69fe60f2d6377ea4fae539493997b098f52cad1"
},
"whatwg-fetch/whatwg-fetch.d.ts": {
"commit": "f4b1797c1201b6c575668f5d7ea12d9b1ab21846"
}
}
}

View File

@@ -1,976 +0,0 @@
// Type definitions for react-bootstrap
// Project: https://github.com/react-bootstrap/react-bootstrap
// Definitions by: Walker Burgin <https://github.com/walkerburgin>
// Definitions: https://github.com/borisyankov/DefinitelyTyped
///<reference path="../react/react.d.ts"/>
declare module "react-bootstrap" {
// Import React
import React = require("react");
// <Button />
// ----------------------------------------
interface ButtonProps extends React.Props<ButtonClass>{
// Optional
active?: boolean;
disabled?: boolean;
block?: boolean;
bsStyle?: string;
bsSize?: string;
className?: string;
navItem?: boolean;
navDropdown?: boolean;
componentClass?: string;
href?: string;
onClick?: Function; // Add more specific type
target?: string;
type?: string;
}
interface Button extends React.ReactElement<ButtonProps> { }
interface ButtonClass extends React.ComponentClass<ButtonProps> { }
var Button: ButtonClass;
// <ButtonToolbar />
// ----------------------------------------
interface ButtonToolbarProps extends React.Props<ButtonToolbarClass> {
// Optional
block?: boolean;
bsSize?: string;
bsStyle?: string;
className?: string;
justified?: boolean;
vertical?: boolean;
}
interface ButtonToolbar extends React.ReactElement<ButtonToolbarProps> { }
interface ButtonToolbarClass extends React.ComponentClass<ButtonToolbarProps> { }
var ButtonToolbar: ButtonToolbarClass;
// <ButtonGroup />
// ----------------------------------------
interface ButtonGroupProps extends React.Props<ButtonGroupClass> {
// Optional
block?: boolean;
bsSize?: string;
bsStyle?: string;
className?: string;
justified?: boolean;
vertical?: boolean;
}
interface ButtonGroup extends React.ReactElement<ButtonGroupProps> { }
interface ButtonGroupClass extends React.ComponentClass<ButtonGroupProps> { }
var ButtonGroup: ButtonGroupClass;
// <DropdownButton />
// ----------------------------------------
interface DropdownButtonProps extends React.Props<DropdownButtonClass> {
bsStyle?: string;
bsSize?: string;
buttonClassName?: string;
className?: string;
dropup?: boolean;
href?: string;
id?: string | number;
navItem?: boolean;
noCaret?: boolean;
onClick?: Function; // TODO: Add more specifc type
onSelect?: Function; // TODO: Add more specific type
pullRight?: boolean;
title?: any; // TODO: Add more specific type
}
interface DropdownButton extends React.ReactElement<DropdownButtonProps> { }
interface DropdownButtonClass extends React.ComponentClass<DropdownButtonProps> { }
var DropdownButton: DropdownButtonClass;
// <SplitButton />
// ----------------------------------------
interface SplitButtonProps extends React.Props<SplitButtonClass>{
bsStyle?: string;
bsSize?: string;
className?: string;
disabled?: boolean;
dropdownTitle?: any; // TODO: Add more specific type
dropup?: boolean;
href?: string;
id?: string;
onClick?: Function; // TODO: Add more specific type
onSelect?: Function; // TODO: Add more specific type
pullRight?: boolean;
target?: string;
title?: any; // TODO: Add more specific type
}
interface SplitButton extends React.ReactElement<SplitButtonProps> { }
interface SplitButtonClass extends React.ComponentClass<SplitButtonProps> { }
var SplitButton: SplitButtonClass;
// <MenuItem />
// ----------------------------------------
interface MenuItemProps extends React.Props<MenuItemClass> {
active?: boolean;
className?: string;
disabled?: boolean;
divider?: boolean;
eventKey?: any;
header?: boolean;
href?: string;
onClick?: Function;
onKeyDown?: Function;
onSelect?: Function;
target?: string;
title?: string;
}
interface MenuItem extends React.ReactElement<MenuItemProps> { }
interface MenuItemClass extends React.ComponentClass<MenuItemProps> { }
var MenuItem: MenuItemClass;
// <Panel />
// ----------------------------------------
interface PanelProps extends React.Props<PanelClass> {
className?: string;
bsSize?: string;
bsStyle?: string;
collapsible?: boolean;
defaultExpanded?: boolean;
eventKey?: any;
expanded?: boolean;
footer?: any; // TODO: Add more specific type
header?: any; // TODO: Add more specific type
id?: string;
onSelect?: Function; // TODO: Add more specific type
onClick?: Function; // TODO: Add more specific type
}
interface Panel extends React.ReactElement<PanelProps> { }
interface PanelClass extends React.ComponentClass<PanelProps> { }
var Panel: PanelClass;
// <Accordion />
// ----------------------------------------
interface AccordionProps extends React.Props<AccordionClass> {
bsSize?: string;
bsStyle?: string;
collapsible?: boolean;
defaultExpanded?: boolean;
eventKey?: any;
expanded?: boolean;
footer?: any; // TODO: Add more specific type
header?: any; // TODO: Add more specific type
id?: string;
onSelect?: Function; // TODO: Add more specific type
}
interface Accordion extends React.ReactElement<AccordionProps> { }
interface AccordionClass extends React.ComponentClass<AccordionProps> { }
var Accordion: AccordionClass;
// <PanelGroup />
// ----------------------------------------
interface PanelGroupProps extends React.Props<PanelGroupClass> {
accordion?: boolean;
activeKey?: any;
bsSize?: string;
bsStyle?: string;
className?: string;
defaultActiveKey?: any;
onSelect?: Function;
}
interface PanelGroup extends React.ReactElement<PanelGroupProps> { }
interface PanelGroupClass extends React.ComponentClass<PanelGroupProps> { }
var PanelGroup: PanelGroupClass;
// <Modal.Dialog />
// ----------------------------------------
interface ModalDialogProps extends React.Props<ModalDialogClass> {
// TODO: Add more specific type
}
interface ModalDialog extends React.ReactElement<ModalDialogProps> { }
interface ModalDialogClass extends React.ComponentClass<ModalHeaderProps> { }
// <Modal.Header />
// ----------------------------------------
interface ModalHeaderProps extends React.Props<ModalHeaderClass> {
className?: string;
closeButton?: boolean;
modalClassName?: string;
onHide?: Function;
// undefined?: string;
}
interface ModalHeader extends React.ReactElement<ModalHeaderProps> { }
interface ModalHeaderClass extends React.ComponentClass<ModalHeaderProps> { }
// <Modal.Title/>
// ----------------------------------------
interface ModalTitleProps extends React.Props<ModalTitleClass> {
className?: string;
modalClassName?: string;
}
interface ModalTitle extends React.ReactElement<ModalTitleProps> { }
interface ModalTitleClass extends React.ComponentClass<ModalTitleProps> { }
// <Modal.Body />
// ----------------------------------------
interface ModalBodyProps extends React.Props<ModalBodyClass> {
className?: string;
modalClassName?: string;
}
interface ModalBody extends React.ReactElement<ModalBodyProps> { }
interface ModalBodyClass extends React.ComponentClass<ModalBodyProps> { }
// <Modal.Footer />
// ----------------------------------------
interface ModalFooterProps extends React.Props<ModalFooterClass> {
className?: string;
modalClassName?: string;
}
interface ModalFooter extends React.ReactElement<ModalFooterProps> { }
interface ModalFooterClass extends React.ComponentClass<ModalFooterProps> { }
// <Modal />
// ----------------------------------------
interface ModalProps extends React.Props<ModalClass> {
// Required
onHide: Function;
// Optional
animation?: boolean;
autoFocus?: boolean;
backdrop?: boolean|string;
bsSize?: string;
container?: any; // TODO: Add more specific type
dialogClassName?: string;
dialogComponent?: any; // TODO: Add more specific type
enforceFocus?: boolean;
keyboard?: boolean;
show?: boolean;
}
interface Modal extends React.ReactElement<ModalProps> { }
interface ModalClass extends React.ComponentClass<ModalProps> {
Header: ModalHeaderClass;
Title: ModalTitleClass;
Body: ModalBodyClass;
Footer: ModalFooterClass;
Dialog: ModalDialogClass;
}
var Modal: ModalClass;
// <OverlayTrigger />
// ----------------------------------------
interface OverlayTriggerProps extends React.Props<OverlayTriggerClass> {
// Required
overlay: any; // TODO: Add more specific type
// Optional
animation?: any; // TODO: Add more specific type
container?: any; // TODO: Add more specific type
containerPadding?: number;
defaultOverlayShown?: boolean;
delay?: number;
delayHide?: number;
delayShow?: number;
onEnter?: Function;
onEntered?: Function;
onEntering?: Function;
onExit?: Function;
onExited?: Function;
onExiting?: Function;
placement?: string;
rootClose?: boolean;
trigger?: string;
}
interface OverlayTrigger extends React.ReactElement<OverlayTriggerProps> { }
interface OverlayTriggerClass extends React.ComponentClass<OverlayTriggerProps> { }
var OverlayTrigger: OverlayTriggerClass;
// <Tooltip />
// ----------------------------------------
interface TooltipProps extends React.Props<TooltipClass> {
// Optional
arrowOffsetLeft?: number | string;
arrowOffsetTop?: number | string;
bsSize?: string;
bsStyle?: string;
className?: string;
id?: string;
placement?: string;
positionLeft?: number;
positionTop?: number;
title?: any; // TODO: Add more specific type
}
interface Tooltip extends React.ReactElement<TooltipProps> { }
interface TooltipClass extends React.ComponentClass<TooltipProps> { }
var Tooltip: TooltipClass;
// <Popover/>
// ----------------------------------------
interface PopoverProps extends React.Props<PopoverClass> {
// Optional
arrowOffsetLeft?: number | string;
arrowOffsetTop?: number | string;
bsSize?: string;
bsStyle?: string;
className?: string;
id?: string;
placement?: string;
positionLeft?: number;
positionTop?: number;
title?: any; // TODO: Add more specific type
}
interface Popover extends React.ReactElement<PopoverProps> { }
interface PopoverClass extends React.ComponentClass<PopoverProps> { }
var Popover: PopoverClass;
// <Overlay />
// ----------------------------------------
interface OverlayProps extends React.Props<OverlayClass> {
// Optional
animation?: any; // TODO: Add more specific type
container?: any; // TODO: Add more specific type
containerPadding?: number; // TODO: Add more specific type
onEnter?: Function;
onEntered?: Function;
onEntering?: Function;
onExit?: Function;
onExited?: Function;
onExiting?: Function;
onHide?: Function;
placement?: string;
rootClose?: boolean;
show?: boolean;
target?: Function;
}
interface Overlay extends React.ReactElement<OverlayProps> { }
interface OverlayClass extends React.ComponentClass<OverlayProps> { }
var Overlay: OverlayClass;
// <ProgressBar />
// ----------------------------------------
interface ProgressBarProps extends React.Props<ProgressBarClass> {
// Optional
active?: boolean;
bsSize?: string;
bsStyle?: string;
className?: string;
interpolatedClass?: any; // TODO: Add more specific type
label?: any; // TODO: Add more specific type
max?: number;
min?: number;
now?: number;
srOnly?: boolean;
striped?: boolean;
}
interface ProgressBar extends React.ReactElement<ProgressBarProps> { }
interface ProgressBarClass extends React.ComponentClass<ProgressBarProps> { }
var ProgressBar: ProgressBarClass;
// <Nav />
// ----------------------------------------
// TODO: This one turned into a union of two different types
interface NavProps extends React.Props<NavClass> {
// Optional
activeHref?: string;
activeKey?: any;
bsSize?: string;
bsStyle?: string;
className?: string;
collapsible?: boolean;
eventKey?: any;
expanded?: boolean;
id?: string;
justified?: boolean;
navbar?: boolean;
onSelect?: Function;
pullRight?: boolean;
right?: boolean;
stacked?: boolean;
ulClassName?: string;
ulId?: string;
}
interface Nav extends React.ReactElement<NavProps> { }
interface NavClass extends React.ComponentClass<NavProps> { }
var Nav: NavClass;
// <NavItem />
// ----------------------------------------
interface NavItemProps extends React.Props<NavItemClass> {
active?: boolean;
brand?: any; // TODO: Add more specific type
bsSize?: string;
bsStyle?: string;
className?: string;
componentClass?: any; // TODO: Add more specific type
defaultNavExpanded?: boolean;
disabled?: boolean;
eventKey?: any;
fixedBottom?: boolean;
fixedTop?: boolean;
fluid?: boolean;
href?: string;
inverse?: boolean;
linkId?: string;
navExpanded?: boolean;
onClick?: Function;
onSelect?: Function;
onToggle?: Function;
role?: string;
staticTop?: boolean;
target?: string;
title?: string;
toggleButton?: any; // TODO: Add more specific type
toggleNavKey?: string | number;
}
interface NavItem extends React.ReactElement<NavItemProps> { }
interface NavItemClass extends React.ComponentClass<NavItemProps> { }
var NavItem: NavItemClass;
// <Navbar.Brand />
// ----------------------------------------
interface NavbarBrandProps extends React.Props<NavbarBrandClass> {
}
interface NavbarBrand extends React.ReactElement<NavbarBrandProps> { }
interface NavbarBrandClass extends React.ComponentClass<NavbarBrandProps> { }
// <Navbar.Collapse />
// ----------------------------------------
interface NavbarCollapseProps extends React.Props<NavbarCollapseClass> {
}
interface NavbarCollapse extends React.ReactElement<NavbarCollapseProps> { }
interface NavbarCollapseClass extends React.ComponentClass<NavbarCollapseProps> { }
// <Navbar.Header />
// ----------------------------------------
interface NavbarHeaderProps extends React.Props<NavbarHeaderClass> {
}
interface NavbarHeader extends React.ReactElement<NavbarHeaderProps> { }
interface NavbarHeaderClass extends React.ComponentClass<NavbarHeaderProps> { }
// <Navbar.Toggle />
// ----------------------------------------
interface NavbarToggleProps extends React.Props<NavbarToggleClass> {
}
interface NavbarToggle extends React.ReactElement<NavbarToggleProps> { }
interface NavbarToggleClass extends React.ComponentClass<NavbarToggleProps> { }
// <Navbar />
// ----------------------------------------
interface NavbarProps extends React.Props<NavbarClass> {
brand?: any; // TODO: Add more specific type
bsSize?: string;
bsStyle?: string;
className?: string;
componentClass?: any; // TODO: Add more specific type
defaultNavExpanded?: boolean;
fixedBottom?: boolean;
fixedTop?: boolean;
fluid?: boolean;
inverse?: boolean;
navExpanded?: boolean;
onToggle?: Function;
role?: string;
staticTop?: boolean;
toggleButton?: any; // TODO: Add more specific type
toggleNavKey?: string | number;
}
interface Navbar extends React.ReactElement<NavbarProps> { }
interface NavbarClass extends React.ComponentClass<NavbarProps> {
Brand: NavbarBrandClass;
Collapse: NavbarCollapseClass;
Header: NavbarHeaderClass;
Toggle: NavbarToggleClass;
}
var Navbar: NavbarClass;
// <NavBrand />
// ----------------------------------------
interface NavBrandProps {
}
interface NavBrand extends React.ReactElement<NavbarProps> { }
interface NavBrandClass extends React.ComponentClass<NavbarProps> { }
var NavBrand: NavBrandClass;
// <NavDropdown />
// ----------------------------------------
interface NavDropdownProps extends React.Props<NavDropdownClass> {
className?: string;
eventKey?: any;
title?: string;
id?: string;
}
interface NavDropdown extends React.ReactElement<NavDropdownProps> { }
interface NavDropdownClass extends React.ComponentClass<NavDropdownProps> { }
var NavDropdown: NavDropdownClass;
// <Tabs />
// ----------------------------------------
interface TabsProps extends React.Props<TabsClass> {
activeKey?: any;
animation?: boolean;
bsStyle?: string;
defaultActiveKey?: any;
id?: string | number;
onSelect?: Function;
paneWidth?: any; // TODO: Add more specific type
position?: string;
tabWidth?: any; // TODO: Add more specific type
}
interface Tabs extends React.ReactElement<TabsProps> { }
interface TabsClass extends React.ComponentClass<TabsProps> { }
var Tabs: TabsClass;
// <Tab />
// ----------------------------------------
interface TabProps extends React.Props<TabClass> {
animation?: boolean;
className?: string;
disabled?: boolean;
eventKey?: any; // TODO: Add more specific type
title?: any; // TODO: Add more specific type
}
interface Tab extends React.ReactElement<TabProps> { }
interface TabClass extends React.ComponentClass<TabProps> { }
var Tab: TabClass;
// <Pager />
// ----------------------------------------
interface PagerProps extends React.Props<PagerClass> {
className?: string;
onSelect?: Function;
}
interface Pager extends React.ReactElement<PagerProps> { }
interface PagerClass extends React.ComponentClass<PagerProps> { }
var Pager: PagerClass;
// <PageItem />
// ----------------------------------------
interface PageItemProps extends React.Props<PageItemClass> {
className?: string;
disabled?: boolean;
eventKey?: any;
href?: string;
next?: boolean;
onSelect?: Function;
previous?: boolean;
target?: string;
title?: string;
}
interface PageItem extends React.ReactElement<PageItemProps> { }
interface PageItemClass extends React.ComponentClass<PageItemProps> { }
var PageItem: PageItemClass;
// <Pagination />
// ----------------------------------------
interface PaginationProps extends React.Props<PaginationClass> {
activePage?: number;
bsSize?: string;
bsStyle?: string;
buttonComponentClass?: any; // TODO: Add more specific type
className?: string;
ellipsis?: boolean;
first?: boolean;
items?: number;
last?: boolean;
maxButtons?: number;
next?: boolean;
onSelect?: Function;
prev?: boolean;
}
interface Pagination extends React.ReactElement<PaginationProps> { }
interface PaginationClass extends React.ComponentClass<PaginationProps> { }
var Pagination: PaginationClass;
// <Alert />
// ----------------------------------------
interface AlertProps extends React.Props<AlertClass> {
bsSize?: string;
bsStyle?: string;
className?: string;
closeLabel?: string;
dismissAfter?: number;
onDismiss?: Function;
}
interface Alert extends React.ReactElement<AlertProps> { }
interface AlertClass extends React.ComponentClass<AlertProps> { }
var Alert: AlertClass;
// <Carousel />
// ----------------------------------------
interface CarouselProps extends React.Props<CarouselClass> {
activeIndex?: number;
bsSize?: string;
bsStyle?: string;
className?: string;
controls?: boolean;
defaultActiveIndex?: number;
direction?: string;
indicators?: boolean;
interval?: number;
nextIcon?: any; // TODO: Add more specific type
onSelect?: Function;
onSlideEnd?: Function;
pauseOnHover?: boolean;
prevIcon?: any; // TODO: Add more specific type
slide?: boolean;
wrap?: boolean;
}
interface Carousel extends React.ReactElement<CarouselProps> { }
interface CarouselClass extends React.ComponentClass<CarouselProps> { }
var Carousel: CarouselClass;
// <CarouselItem />
// ----------------------------------------
interface CarouselItemProps extends React.Props<CarouselItemClass> {
active?: boolean;
animtateIn?: boolean;
animateOut?: boolean;
caption?: any; // TODO: Add more specific type
className?: string;
direction?: string;
index?: number;
onAnimateOutEnd?: Function;
}
interface CarouselItem extends React.ReactElement<CarouselItemProps> { }
interface CarouselItemClass extends React.ComponentClass<CarouselItemProps> { }
var CarouselItem: CarouselItemClass;
// <Grid />
// ----------------------------------------
interface GridProps extends React.Props<GridClass> {
className?: string;
componentClass?: any; // TODO: Add more specific type
fluid?: boolean;
}
interface Grid extends React.ReactElement<GridProps> { }
interface GridClass extends React.ComponentClass<GridProps> { }
var Grid: GridClass;
// <Row />
// ----------------------------------------
interface RowProps extends React.Props<RowClass> {
className?: string;
componentClass?: any; // TODO: Add more specific type
}
interface Row extends React.ReactElement<RowProps> { }
interface RowClass extends React.ComponentClass<RowProps> { }
var Row: RowClass;
// <Col />
// ----------------------------------------
interface ColProps extends React.Props<ColClass> {
className?: string;
componentClass?: any; // TODO: Add more specific type
lg?: number;
lgOffset?: number;
lgPull?: number;
lgPush?: number;
md?: number;
mdOffset?: number;
mdPull?: number;
mdPush?: number;
sm?: number;
smOffset?: number;
smPull?: number;
smPush?: number;
xs?: number;
xsOffset?: number;
xsPull?: number;
xsPush?: number;
}
interface Col extends React.ReactElement<ColProps> { }
interface ColClass extends React.ComponentClass<ColProps> { }
var Col: ColClass;
// <Thumbnail />
// ----------------------------------------
interface ThumbnailProps extends React.Props<ThumbnailClass> {
alt?: string;
bsSize?: string;
bsStyle?: string;
className?: string;
href?: string;
src?: string;
}
interface Thumbnail extends React.ReactElement<ThumbnailProps> { }
interface ThumbnailClass extends React.ComponentClass<ThumbnailProps> { }
var Thumbnail: ThumbnailClass;
// <ListGroup />
// ----------------------------------------
interface ListGroupProps extends React.Props<ListGroupClass> {
className?: string;
id?: string | number;
fill?: boolean; // TODO: Add more specific type
}
interface ListGroup extends React.ReactElement<ListGroupProps> { }
interface ListGroupClass extends React.ComponentClass<ListGroupProps> { }
var ListGroup: ListGroupClass;
// <ListGroupItem />
// ----------------------------------------
interface ListGroupItemProps extends React.Props<ListGroupItemClass> {
active?: any;
bsSize?: string;
bsStyle?: string;
className?: string;
disabled?: any;
eventKey?: any;
header?: any; // TODO: Add more specific type
href?: string;
key?: any; // TODO: Add more specific type
listItem?: boolean;
onClick?: Function; // TODO: Add more specific type
target?: string;
}
interface ListGroupItem extends React.ReactElement<ListGroupItemProps> { }
interface ListGroupItemClass extends React.ComponentClass<ListGroupItemProps> { }
var ListGroupItem: ListGroupItemClass;
// <Label />
// ----------------------------------------
interface LabelProps extends React.Props<LabelClass> {
bsSize?: string;
bsStyle?: string;
className?: string;
}
interface Label extends React.ReactElement<LabelProps> { }
interface LabelClass extends React.ComponentClass<LabelProps> { }
var Label: LabelClass;
// <Badge />
// ----------------------------------------
interface BadgeProps extends React.Props<BadgeClass> {
className?: string;
pullRight?: boolean;
}
interface Badge extends React.ReactElement<BadgeProps> { }
interface BadgeClass extends React.ComponentClass<BadgeProps> { }
var Badge: BadgeClass;
// <Jumbotron />
// ----------------------------------------
interface JumbotronProps extends React.Props<JumbotronClass> {
className?: string;
componentClass?: any; // TODO: Add more specific type
}
interface Jumbotron extends React.ReactElement<JumbotronProps> { }
interface JumbotronClass extends React.ComponentClass<JumbotronProps> { }
var Jumbotron: JumbotronClass;
// <PageHeader />
// ----------------------------------------
interface PageHeaderProps extends React.Props<PageHeaderClass> {
className?: string;
}
interface PageHeader extends React.ReactElement<PageHeaderProps> { }
interface PageHeaderClass extends React.ComponentClass<PageHeaderProps> { }
var PageHeader: PageHeaderClass;
// <Well />
// ----------------------------------------
interface WellProps extends React.Props<WellClass> {
bsSize?: string;
bsStyle?: string;
className?: string;
}
interface Well extends React.ReactElement<WellProps> { }
interface WellClass extends React.ComponentClass<WellProps> { }
var Well: WellClass;
// <Glyphicon />
// ----------------------------------------
interface GlyphiconProps extends React.Props<GlyphiconClass> {
className?: string;
// Required
glyph: string;
}
interface Glyphicon extends React.ReactElement<GlyphiconProps> { }
interface GlyphiconClass extends React.ComponentClass<GlyphiconProps> { }
var Glyphicon: GlyphiconClass;
// <Table />
// ----------------------------------------
interface TableProps extends React.Props<TableClass> {
bordered?: boolean;
className?: string;
condensed?: boolean;
hover?: boolean;
responsive?: boolean;
striped?: boolean;
}
interface Table extends React.ReactElement<TableProps> { }
interface TableClass extends React.ComponentClass<TableProps> { }
var Table: TableClass;
// <Input />
// ----------------------------------------
interface InputProps extends React.Props<InputClass> {
defaultValue?:string;
addonAfter?: any; // TODO: Add more specific type
addonBefore?: any; // TODO: Add more specific type
bsSize?: string;
bsStyle?: string;
buttonAfter?: any; // TODO: Add more specific type
buttonBefore?: any; // TODO: Add more specific type
className?: string;
checked?: boolean;
disabled?: boolean;
feedbackIcon?: any; // TODO: Add more specific type
groupClassName?: string;
hasFeedback?: boolean;
help?: any; // TODO: Add more specific type
id?: string | number;
label?: any; // TODO: Add more specific type
labelClassName?: string;
multiple?: boolean;
placeholder?: string;
readOnly?: boolean;
type?: string;
onChange?: Function; // TODO: Add more specific type
onKeyDown?: Function; // TODO: Add more specific type
onKeyUp?: Function; // TODO: Add more specific type
onKeyPress?: Function; // TODO: Add more specific type
value?: any; // TODO: Add more specific type
wrapperClassName?: string;
}
interface Input extends React.ReactElement<InputProps> { }
interface InputClass extends React.ComponentClass<InputProps> { }
var Input: InputClass;
// <ButtonInput />
// ----------------------------------------
interface ButtonInputProps extends React.Props<ButtonInputClass> {
addonAfter?: any; // TODO: Add more specific type
addonBefore?: any; // TODO: Add more specific type
bsSize?: string;
bsStyle?: string;
buttonAfter?: any; // TODO: Add more specific type
buttonBefore?: any; // TODO: Add more specific type
className?: string;
disabled?: boolean;
feedbackIcon?: any; // TODO: Add more specific type
groupClassName?: string;
hasFeedback?: boolean;
help?: any; // TODO: Add more specific type
id?: string | number;
label?: any; // TODO: Add more specific type
labelClassName?: string;
multiple?: boolean;
onClick?: Function; // TODO: Add more specific type
type?: string;
value?: any; // TODO: Add more specific type
wrapperClassName?: string;
}
interface ButtonInput extends React.ReactElement<ButtonInputProps> { }
interface ButtonInputClass extends React.ComponentClass<ButtonInputProps> { }
var ButtonInput: ButtonInputClass;
// TODO: FormControls.Static
// <Portal />
// ----------------------------------------
interface PortalProps extends React.Props<PortalClass> {
dimension?: string | Function;
getDimensionValue?: Function;
in?: boolean;
onEnter?: Function;
onEntered?: Function;
onEntering?: Function;
onExit?: Function;
onExited?: Function;
onExiting?: Function;
role?: string;
timeout?: number;
transitionAppear?: boolean;
unmountOnExit?: boolean;
}
interface Portal extends React.ReactElement<PortalProps> { }
interface PortalClass extends React.ComponentClass<PortalProps> { }
var Portal: PortalClass;
// <Position />
// ----------------------------------------
interface PositionProps extends React.Props<PositionClass> {
dimension?: string | Function;
getDimensionValue?: Function;
in?: boolean;
onEnter?: Function;
onEntered?: Function;
onEntering?: Function;
onExit?: Function;
onExited?: Function;
onExiting?: Function;
role?: string;
timeout?: number;
transitionAppear?: boolean;
unmountOnExit?: boolean;
}
interface Position extends React.ReactElement<PositionProps> { }
interface PositionClass extends React.ComponentClass<PositionProps> { }
var Position: PositionClass;
// <Fade />
// ----------------------------------------
interface FadeProps extends React.Props<FadeClass> {
in?: boolean;
onEnter?: Function;
onEntered?: Function;
onEntering?: Function;
onExit?: Function;
onExited?: Function;
onExiting?: Function;
timeout?: number;
transitionAppear?: boolean;
unmountOnExit?: boolean;
}
interface Fade extends React.ReactElement<FadeProps> { }
interface FadeClass extends React.ComponentClass<FadeProps> { }
var Fade: FadeClass;
}

View File

@@ -1,69 +0,0 @@
// Type definitions for react-redux 2.1.2
// Project: https://github.com/rackt/react-redux
// Definitions by: Qubo <https://github.com/tkqubo>
// Definitions: https://github.com/borisyankov/DefinitelyTyped
/// <reference path="../react/react.d.ts" />
/// <reference path="../redux/redux.d.ts" />
declare module "react-redux" {
import { Component } from 'react';
import { Store, Dispatch, ActionCreator } from 'redux';
export class ElementClass extends Component<any, any> { }
export interface ClassDecorator {
<T extends (typeof ElementClass)>(component: T): T
}
/**
* Connects a React component to a Redux store.
* @param mapStateToProps
* @param mapDispatchToProps
* @param mergeProps
* @param options
*/
export function connect(mapStateToProps?: MapStateToProps,
mapDispatchToProps?: MapDispatchToPropsFunction|MapDispatchToPropsObject,
mergeProps?: MergeProps,
options?: Options): ClassDecorator;
interface MapStateToProps {
(state: any, ownProps?: any): any;
}
interface MapDispatchToPropsFunction {
(dispatch: Dispatch, ownProps?: any): any;
}
interface MapDispatchToPropsObject {
[name: string]: ActionCreator;
}
interface MergeProps {
(stateProps: any, dispatchProps: any, ownProps: any): any;
}
interface Options {
/**
* If true, implements shouldComponentUpdate and shallowly compares the result of mergeProps,
* preventing unnecessary updates, assuming that the component is a “pure” component
* and does not rely on any input or state other than its props and the selected Redux stores state.
* Defaults to true.
* @default true
*/
pure: boolean;
}
export interface Property {
/**
* The single Redux store in your application.
*/
store?: Store;
children?: Function;
}
/**
* Makes the Redux store available to the connect() calls in the component hierarchy below.
*/
export class Provider extends Component<Property, {}> { }
}

View File

@@ -1,46 +0,0 @@
// Type definitions for react-router-bootstrap
// Project: https://github.com/react-bootstrap/react-router-bootstrap
// Definitions by: Vincent Lesierse <https://github.com/vlesierse>
// Definitions: https://github.com/borisyankov/DefinitelyTyped
///<reference path="../react/react.d.ts"/>
///<reference path="../react-router/react-router.d.ts"/>
declare namespace ReactRouterBootstrap {
// Import React
import React = __React;
interface LinkContainerProps extends ReactRouter.LinkProps {
disabled?: boolean
}
interface LinkContainer extends React.ComponentClass<LinkContainerProps> {}
interface LinkContainerElement extends React.ReactElement<LinkContainerProps> {}
const LinkContainer: LinkContainer
const IndexLinkContainer: LinkContainer
}
declare module "react-router-bootstrap/lib/LinkContainer" {
export default ReactRouterBootstrap.LinkContainer
}
declare module "react-router-bootstrap/lib/IndexLinkContainer" {
export default ReactRouterBootstrap.IndexLinkContainer
}
declare module "react-router-bootstrap" {
import LinkContainer from "react-router-bootstrap/lib/LinkContainer"
import IndexLinkContainer from "react-router-bootstrap/lib/IndexLinkContainer"
export {
LinkContainer,
IndexLinkContainer
}
}

View File

@@ -1,48 +0,0 @@
// Type definitions for react-router-redux v2.1.0
// Project: https://github.com/rackt/react-router-redux
// Definitions by: Isman Usoh <http://github.com/isman-usoh>, Noah Shipley <https://github.com/noah79>, Dimitri Rosenberg <https://github.com/rosendi>
// Definitions: https://github.com/borisyankov/DefinitelyTyped
/// <reference path="../redux/redux.d.ts" />
/// <reference path="../react-router/react-router.d.ts"/>
declare namespace ReactRouterRedux {
import R = Redux;
import H = HistoryModule;
const TRANSITION: string;
const UPDATE_LOCATION: string;
const push: PushAction;
const replace: ReplaceAction;
const go: GoAction;
const goBack: GoForwardAction;
const goForward: GoBackAction;
const routeActions: RouteActions;
type LocationDescriptor = H.Location | H.Path;
type PushAction = (nextLocation: LocationDescriptor) => void;
type ReplaceAction = (nextLocation: LocationDescriptor) => void;
type GoAction = (n: number) => void;
type GoForwardAction = () => void;
type GoBackAction = () => void;
interface RouteActions {
push: PushAction;
replace: ReplaceAction;
go: GoAction;
goForward: GoForwardAction;
goBack: GoBackAction;
}
interface HistoryMiddleware extends R.Middleware {
listenForReplays(store: R.Store, selectLocationState?: Function): void;
unsubscribe(): void;
}
function routeReducer(state?: any, options?: any): R.Reducer;
function syncHistory(history: H.History): HistoryMiddleware;
}
declare module "react-router-redux" {
export = ReactRouterRedux;
}

View File

@@ -1,192 +0,0 @@
// Type definitions for history v1.13.1
// Project: https://github.com/rackt/history
// Definitions by: Sergey Buturlakin <http://github.com/sergey-buturlakin>
// Definitions: https://github.com/borisyankov/DefinitelyTyped
declare namespace HistoryModule {
// types based on https://github.com/rackt/history/blob/master/docs/Terms.md
type Action = string
type BeforeUnloadHook = () => string | boolean
type CreateHistory<T> = (options?: HistoryOptions) => T
type CreateHistoryEnhancer<T, E> = (createHistory: CreateHistory<T>) => CreateHistory<T & E>
interface History {
listenBefore(hook: TransitionHook): Function
listen(listener: LocationListener): Function
transitionTo(location: Location): void
pushState(state: LocationState, path: Path): void
replaceState(state: LocationState, path: Path): void
push(path: Path): void
replace(path: Path): void
go(n: number): void
goBack(): void
goForward(): void
createKey(): LocationKey
createPath(path: Path): Path
createHref(path: Path): Href
createLocation(path?: Path, state?: LocationState, action?: Action, key?: LocationKey): Location
/** @deprecated use location.key to save state instead */
setState(state: LocationState): void
/** @deprecated use listenBefore instead */
registerTransitionHook(hook: TransitionHook): void
/** @deprecated use the callback returned from listenBefore instead */
unregisterTransitionHook(hook: TransitionHook): void
}
type HistoryOptions = Object
type Href = string
type Location = {
pathname: Pathname
search: QueryString
query: Query
state: LocationState
action: Action
key: LocationKey
}
type LocationKey = string
type LocationListener = (location: Location) => void
type LocationState = Object
type Path = string // Pathname + QueryString
type Pathname = string
type Query = Object
type QueryString = string
type TransitionHook = (location: Location, callback: Function) => any
interface HistoryBeforeUnload {
listenBeforeUnload(hook: BeforeUnloadHook): Function
}
interface HistoryQueries {
pushState(state: LocationState, pathname: Pathname | Path, query?: Query): void
replaceState(state: LocationState, pathname: Pathname | Path, query?: Query): void
createPath(path: Path, query?: Query): Path
createHref(path: Path, query?: Query): Href
}
// Global usage, without modules, needs the small trick, because lib.d.ts
// already has `history` and `History` global definitions:
// var createHistory = ((window as any).History as HistoryModule.Module).createHistory;
interface Module {
createHistory: CreateHistory<History>
createHashHistory: CreateHistory<History>
createMemoryHistory: CreateHistory<History>
createLocation(path?: Path, state?: LocationState, action?: Action, key?: LocationKey): Location
useBasename<T>(createHistory: CreateHistory<T>): CreateHistory<T>
useBeforeUnload<T>(createHistory: CreateHistory<T>): CreateHistory<T & HistoryBeforeUnload>
useQueries<T>(createHistory: CreateHistory<T>): CreateHistory<T & HistoryQueries>
actions: {
PUSH: string
REPLACE: string
POP: string
}
}
}
declare module "history/lib/createBrowserHistory" {
export default function createBrowserHistory(options?: HistoryModule.HistoryOptions): HistoryModule.History
}
declare module "history/lib/createHashHistory" {
export default function createHashHistory(options?: HistoryModule.HistoryOptions): HistoryModule.History
}
declare module "history/lib/createMemoryHistory" {
export default function createMemoryHistory(options?: HistoryModule.HistoryOptions): HistoryModule.History
}
declare module "history/lib/createLocation" {
export default function createLocation(path?: HistoryModule.Path, state?: HistoryModule.LocationState, action?: HistoryModule.Action, key?: HistoryModule.LocationKey): HistoryModule.Location
}
declare module "history/lib/useBasename" {
export default function useBasename<T>(createHistory: HistoryModule.CreateHistory<T>): HistoryModule.CreateHistory<T>
}
declare module "history/lib/useBeforeUnload" {
export default function useBeforeUnload<T>(createHistory: HistoryModule.CreateHistory<T>): HistoryModule.CreateHistory<T & HistoryModule.HistoryBeforeUnload>
}
declare module "history/lib/useQueries" {
export default function useQueries<T>(createHistory: HistoryModule.CreateHistory<T>): HistoryModule.CreateHistory<T & HistoryModule.HistoryQueries>
}
declare module "history/lib/actions" {
export const PUSH: string
export const REPLACE: string
export const POP: string
export default {
PUSH,
REPLACE,
POP
}
}
declare module "history" {
export { default as createHistory } from "history/lib/createBrowserHistory"
export { default as createHashHistory } from "history/lib/createHashHistory"
export { default as createMemoryHistory } from "history/lib/createMemoryHistory"
export { default as createLocation } from "history/lib/createLocation"
export { default as useBasename } from "history/lib/useBasename"
export { default as useBeforeUnload } from "history/lib/useBeforeUnload"
export { default as useQueries } from "history/lib/useQueries"
import * as Actions from "history/lib/actions"
export { Actions }
}

View File

@@ -1,474 +0,0 @@
// Type definitions for react-router v2.0.0-rc5
// Project: https://github.com/rackt/react-router
// Definitions by: Sergey Buturlakin <http://github.com/sergey-buturlakin>, Yuichi Murata <https://github.com/mrk21>, Václav Ostrožlík <https://github.com/vasek17>
// Definitions: https://github.com/borisyankov/DefinitelyTyped
/// <reference path="../react/react.d.ts" />
/// <reference path="./history.d.ts"/>
declare namespace ReactRouter {
import React = __React
import H = HistoryModule
// types based on https://github.com/rackt/react-router/blob/master/docs/Glossary.md
type Component = React.ReactType
type EnterHook = (nextState: RouterState, replaceState: RedirectFunction, callback?: Function) => any
type LeaveHook = () => any
type Params = Object
type ParseQueryString = (queryString: H.QueryString) => H.Query
type RedirectFunction = (state: H.LocationState, pathname: H.Pathname | H.Path, query?: H.Query) => void
type RouteComponent = Component
// use the following interface in an app code to get access to route param values, history, location...
// interface MyComponentProps extends ReactRouter.RouteComponentProps<{}, { id: number }> {}
// somewhere in MyComponent
// ...
// let id = this.props.routeParams.id
// ...
// this.props.history. ...
// ...
interface RouteComponentProps<P, R> {
history?: History
location?: H.Location
params?: P
route?: PlainRoute
routeParams?: R
routes?: PlainRoute[]
children?: React.ReactElement<any>
}
type RouteComponents = { [key: string]: RouteComponent }
type RouteConfig = React.ReactNode | PlainRoute | PlainRoute[]
type RouteHook = (nextLocation?: H.Location) => any
type RoutePattern = string
type StringifyQuery = (queryObject: H.Query) => H.QueryString
type RouterListener = (error: Error, nextState: RouterState) => void
interface RouterState {
location: H.Location
routes: PlainRoute[]
params: Params
components: RouteComponent[]
}
interface HistoryBase extends H.History {
routes: PlainRoute[]
parseQueryString?: ParseQueryString
stringifyQuery?: StringifyQuery
}
type History = HistoryBase & H.HistoryQueries & HistoryRoutes
const browserHistory: History;
const hashHistory: History;
/* components */
interface RouterProps extends React.Props<Router> {
history?: H.History
routes?: RouteConfig // alias for children
createElement?: (component: RouteComponent, props: Object) => any
onError?: (error: any) => any
onUpdate?: () => any
parseQueryString?: ParseQueryString
stringifyQuery?: StringifyQuery
}
interface Router extends React.ComponentClass<RouterProps> {}
interface RouterElement extends React.ReactElement<RouterProps> {}
const Router: Router
interface LinkProps extends React.HTMLAttributes, React.Props<Link> {
activeStyle?: React.CSSProperties
activeClassName?: string
onlyActiveOnIndex?: boolean
to: RoutePattern
query?: H.Query
state?: H.LocationState
}
interface Link extends React.ComponentClass<LinkProps> {}
interface LinkElement extends React.ReactElement<LinkProps> {}
const Link: Link
const IndexLink: Link
interface RouterContextProps extends React.Props<RouterContext> {
history?: H.History
router: Router
createElement: (component: RouteComponent, props: Object) => any
location: H.Location
routes: RouteConfig
params: Params
components?: RouteComponent[]
}
interface RouterContext extends React.ComponentClass<RouterContextProps> {}
interface RouterContextElement extends React.ReactElement<RouterContextProps> {
history?: H.History
location: H.Location
router?: Router
}
const RouterContext: RouterContext
/* components (configuration) */
interface RouteProps extends React.Props<Route> {
path?: RoutePattern
component?: RouteComponent
components?: RouteComponents
getComponent?: (location: H.Location, cb: (error: any, component?: RouteComponent) => void) => void
getComponents?: (location: H.Location, cb: (error: any, components?: RouteComponents) => void) => void
onEnter?: EnterHook
onLeave?: LeaveHook
getIndexRoute?: (location: H.Location, cb: (error: any, indexRoute: RouteConfig) => void) => void
getChildRoutes?: (location: H.Location, cb: (error: any, childRoutes: RouteConfig) => void) => void
}
interface Route extends React.ComponentClass<RouteProps> {}
interface RouteElement extends React.ReactElement<RouteProps> {}
const Route: Route
interface PlainRoute {
path?: RoutePattern
component?: RouteComponent
components?: RouteComponents
getComponent?: (location: H.Location, cb: (error: any, component?: RouteComponent) => void) => void
getComponents?: (location: H.Location, cb: (error: any, components?: RouteComponents) => void) => void
onEnter?: EnterHook
onLeave?: LeaveHook
indexRoute?: PlainRoute
getIndexRoute?: (location: H.Location, cb: (error: any, indexRoute: RouteConfig) => void) => void
childRoutes?: PlainRoute[]
getChildRoutes?: (location: H.Location, cb: (error: any, childRoutes: RouteConfig) => void) => void
}
interface RedirectProps extends React.Props<Redirect> {
path?: RoutePattern
from?: RoutePattern // alias for path
to: RoutePattern
query?: H.Query
state?: H.LocationState
}
interface Redirect extends React.ComponentClass<RedirectProps> {}
interface RedirectElement extends React.ReactElement<RedirectProps> {}
const Redirect: Redirect
interface IndexRouteProps extends React.Props<IndexRoute> {
component?: RouteComponent
components?: RouteComponents
getComponent?: (location: H.Location, cb: (error: any, component?: RouteComponent) => void) => void
getComponents?: (location: H.Location, cb: (error: any, components?: RouteComponents) => void) => void
onEnter?: EnterHook
onLeave?: LeaveHook
}
interface IndexRoute extends React.ComponentClass<IndexRouteProps> {}
interface IndexRouteElement extends React.ReactElement<IndexRouteProps> {}
const IndexRoute: IndexRoute
interface IndexRedirectProps extends React.Props<IndexRedirect> {
to: RoutePattern
query?: H.Query
state?: H.LocationState
}
interface IndexRedirect extends React.ComponentClass<IndexRedirectProps> {}
interface IndexRedirectElement extends React.ReactElement<IndexRedirectProps> {}
const IndexRedirect: IndexRedirect
/* mixins */
interface HistoryMixin {
history: History
}
const History: React.Mixin<any, any>
interface LifecycleMixin {
routerWillLeave(nextLocation: H.Location): string | boolean
}
const Lifecycle: React.Mixin<any, any>
const RouteContext: React.Mixin<any, any>
/* utils */
interface HistoryRoutes {
listen(listener: RouterListener): Function
listenBeforeLeavingRoute(route: PlainRoute, hook: RouteHook): void
match(location: H.Location, callback: (error: any, nextState: RouterState, nextLocation: H.Location) => void): void
isActive(pathname: H.Pathname, query?: H.Query, indexOnly?: boolean): boolean
}
function useRoutes<T>(createHistory: HistoryModule.CreateHistory<T>): HistoryModule.CreateHistory<T & HistoryRoutes>
function createRoutes(routes: RouteConfig): PlainRoute[]
interface MatchArgs {
routes?: RouteConfig
history?: H.History
location?: H.Location
parseQueryString?: ParseQueryString
stringifyQuery?: StringifyQuery
}
interface MatchState extends RouterState {
history: History
}
function match(args: MatchArgs, cb: (error: any, nextLocation: H.Location, nextState: MatchState) => void): void
}
declare module "react-router/lib/Router" {
export default ReactRouter.Router
}
declare module "react-router/lib/Link" {
export default ReactRouter.Link
}
declare module "react-router/lib/IndexLink" {
export default ReactRouter.IndexLink
}
declare module "react-router/lib/IndexRedirect" {
export default ReactRouter.IndexRedirect
}
declare module "react-router/lib/IndexRoute" {
export default ReactRouter.IndexRoute
}
declare module "react-router/lib/Redirect" {
export default ReactRouter.Redirect
}
declare module "react-router/lib/Route" {
export default ReactRouter.Route
}
declare module "react-router/lib/History" {
export default ReactRouter.History
}
declare module "react-router/lib/Lifecycle" {
export default ReactRouter.Lifecycle
}
declare module "react-router/lib/RouteContext" {
export default ReactRouter.RouteContext
}
declare module "react-router/lib/useRoutes" {
export default ReactRouter.useRoutes
}
declare module "react-router/lib/PatternUtils" {
export function formatPattern(pattern: string, params: {}): string;
}
declare module "react-router/lib/RouteUtils" {
type E = __React.ReactElement<any>
export function isReactChildren(object: E | E[]): boolean
export function createRouteFromReactElement(element: E): ReactRouter.PlainRoute
export function createRoutesFromReactChildren(children: E | E[], parentRoute: ReactRouter.PlainRoute): ReactRouter.PlainRoute[]
export import createRoutes = ReactRouter.createRoutes
}
declare module "react-router/lib/RouterContext" {
export default ReactRouter.RouterContext
}
declare module "react-router/lib/PropTypes" {
import React = __React
export function falsy(props: any, propName: string, componentName: string): Error;
export const history: React.Requireable<any>
export const location: React.Requireable<any>
export const component: React.Requireable<any>
export const components: React.Requireable<any>
export const route: React.Requireable<any>
export const routes: React.Requireable<any>
export default {
falsy,
history,
location,
component,
components,
route
}
}
declare module "react-router/lib/browserHistory" {
export default ReactRouter.browserHistory;
}
declare module "react-router/lib/hashHistory" {
export default ReactRouter.hashHistory;
}
declare module "react-router/lib/match" {
export default ReactRouter.match
}
declare module "react-router" {
import Router from "react-router/lib/Router"
import Link from "react-router/lib/Link"
import IndexLink from "react-router/lib/IndexLink"
import IndexRedirect from "react-router/lib/IndexRedirect"
import IndexRoute from "react-router/lib/IndexRoute"
import Redirect from "react-router/lib/Redirect"
import Route from "react-router/lib/Route"
import History from "react-router/lib/History"
import Lifecycle from "react-router/lib/Lifecycle"
import RouteContext from "react-router/lib/RouteContext"
import browserHistory from "react-router/lib/browserHistory"
import hashHistory from "react-router/lib/hashHistory"
import useRoutes from "react-router/lib/useRoutes"
import { createRoutes } from "react-router/lib/RouteUtils"
import { formatPattern } from "react-router/lib/PatternUtils"
import RouterContext from "react-router/lib/RouterContext"
import PropTypes from "react-router/lib/PropTypes"
import match from "react-router/lib/match"
// PlainRoute is defined in the API documented at:
// https://github.com/rackt/react-router/blob/master/docs/API.md
// but not included in any of the .../lib modules above.
export type PlainRoute = ReactRouter.PlainRoute
// The following definitions are also very useful to export
// because by using these types lots of potential type errors
// can be exposed:
export type EnterHook = ReactRouter.EnterHook
export type LeaveHook = ReactRouter.LeaveHook
export type ParseQueryString = ReactRouter.ParseQueryString
export type RedirectFunction = ReactRouter.RedirectFunction
export type RouteComponentProps<P,R> = ReactRouter.RouteComponentProps<P,R>;
export type RouteHook = ReactRouter.RouteHook
export type StringifyQuery = ReactRouter.StringifyQuery
export type RouterListener = ReactRouter.RouterListener
export type RouterState = ReactRouter.RouterState
export type HistoryBase = ReactRouter.HistoryBase
export {
Router,
Link,
IndexLink,
IndexRedirect,
IndexRoute,
Redirect,
Route,
History,
browserHistory,
hashHistory,
Lifecycle,
RouteContext,
useRoutes,
createRoutes,
formatPattern,
RouterContext,
PropTypes,
match
}
export default Router
}

View File

@@ -1,66 +0,0 @@
// Type definitions for React v0.14 (react-dom)
// Project: http://facebook.github.io/react/
// Definitions by: Asana <https://asana.com>, AssureSign <http://www.assuresign.com>, Microsoft <https://microsoft.com>
// Definitions: https://github.com/borisyankov/DefinitelyTyped
/// <reference path="react.d.ts" />
declare namespace __React {
namespace __DOM {
function findDOMNode<E extends Element>(instance: ReactInstance): E;
function findDOMNode(instance: ReactInstance): Element;
function render<P>(
element: DOMElement<P>,
container: Element,
callback?: (element: Element) => any): Element;
function render<P, S>(
element: ClassicElement<P>,
container: Element,
callback?: (component: ClassicComponent<P, S>) => any): ClassicComponent<P, S>;
function render<P, S>(
element: ReactElement<P>,
container: Element,
callback?: (component: Component<P, S>) => any): Component<P, S>;
function unmountComponentAtNode(container: Element): boolean;
var version: string;
function unstable_batchedUpdates<A, B>(callback: (a: A, b: B) => any, a: A, b: B): void;
function unstable_batchedUpdates<A>(callback: (a: A) => any, a: A): void;
function unstable_batchedUpdates(callback: () => any): void;
function unstable_renderSubtreeIntoContainer<P>(
parentComponent: Component<any, any>,
nextElement: DOMElement<P>,
container: Element,
callback?: (element: Element) => any): Element;
function unstable_renderSubtreeIntoContainer<P, S>(
parentComponent: Component<any, any>,
nextElement: ClassicElement<P>,
container: Element,
callback?: (component: ClassicComponent<P, S>) => any): ClassicComponent<P, S>;
function unstable_renderSubtreeIntoContainer<P, S>(
parentComponent: Component<any, any>,
nextElement: ReactElement<P>,
container: Element,
callback?: (component: Component<P, S>) => any): Component<P, S>;
}
namespace __DOMServer {
function renderToString(element: ReactElement<any>): string;
function renderToStaticMarkup(element: ReactElement<any>): string;
var version: string;
}
}
declare module "react-dom" {
import DOM = __React.__DOM;
export = DOM;
}
declare module "react-dom/server" {
import DOMServer = __React.__DOMServer;
export = DOMServer;
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,18 +0,0 @@
// Type definitions for redux-thunk
// Project: https://github.com/gaearon/redux-thunk
// Definitions by: Qubo <https://github.com/tkqubo>
// Definitions: https://github.com/borisyankov/DefinitelyTyped
/// <reference path="../redux/redux.d.ts" />
declare module ReduxThunk {
export interface Thunk extends Redux.Middleware {}
export interface ThunkInterface {
<T>(dispatch: Redux.Dispatch, getState?: () => T): any;
}
}
declare module "redux-thunk" {
var thunk: ReduxThunk.Thunk;
export = thunk;
}

View File

@@ -1,52 +0,0 @@
// Type definitions for Redux v1.0.0
// Project: https://github.com/rackt/redux
// Definitions by: William Buchwalter <https://github.com/wbuchwalter/>, Vincent Prouillet <https://github.com/Keats/>
// Definitions: https://github.com/borisyankov/DefinitelyTyped
declare module Redux {
interface ActionCreator extends Function {
(...args: any[]): any;
}
interface Reducer extends Function {
(state: any, action: any): any;
}
interface Dispatch extends Function {
(action: any): any;
}
interface StoreMethods {
dispatch: Dispatch;
getState(): any;
}
interface MiddlewareArg {
dispatch: Dispatch;
getState: Function;
}
interface Middleware extends Function {
(obj: MiddlewareArg): Function;
}
class Store {
getReducer(): Reducer;
replaceReducer(nextReducer: Reducer): void;
dispatch(action: any): any;
getState(): any;
subscribe(listener: Function): Function;
}
function createStore(reducer: Reducer, initialState?: any): Store;
function bindActionCreators<T>(actionCreators: T, dispatch: Dispatch): T;
function combineReducers(reducers: any): Reducer;
function applyMiddleware(...middlewares: Middleware[]): Function;
function compose<T extends Function>(...functions: Function[]): T;
}
declare module "redux" {
export = Redux;
}

View File

@@ -1,12 +0,0 @@
/// <reference path="react-redux/react-redux.d.ts" />
/// <reference path="react/react-dom.d.ts" />
/// <reference path="react/react.d.ts" />
/// <reference path="redux/redux.d.ts" />
/// <reference path="webpack/webpack-env.d.ts" />
/// <reference path="react-bootstrap/react-bootstrap.d.ts" />
/// <reference path="react-router/history.d.ts" />
/// <reference path="react-router/react-router.d.ts" />
/// <reference path="react-router-bootstrap/react-router-bootstrap.d.ts" />
/// <reference path="react-router-redux/react-router-redux.d.ts" />
/// <reference path="redux-thunk/redux-thunk.d.ts" />
/// <reference path="whatwg-fetch/whatwg-fetch.d.ts" />

View File

@@ -1,232 +0,0 @@
// Type definitions for webpack 1.12.2 (module API)
// Project: https://github.com/webpack/webpack
// Definitions by: use-strict <https://github.com/use-strict>
// Definitions: https://github.com/borisyankov/DefinitelyTyped
/**
* Webpack module API - variables and global functions available inside modules
*/
declare namespace __WebpackModuleApi {
interface RequireContext {
keys(): string[];
<T>(id: string): T;
resolve(id: string): string;
}
interface RequireFunction {
/**
* Returns the exports from a dependency. The call is sync. No request to the server is fired. The compiler ensures that the dependency is available.
*/
<T>(path: string): T;
/**
* Behaves similar to require.ensure, but the callback is called with the exports of each dependency in the paths array. There is no option to provide a chunk name.
*/
(paths: string[], callback: (...modules: any[]) => void): void;
/**
* Download additional dependencies on demand. The paths array lists modules that should be available. When they are, callback is called. If the callback is a function expression, dependencies in that source part are extracted and also loaded on demand. A single request is fired to the server, except if all modules are already available.
*
* This creates a chunk. The chunk can be named. If a chunk with this name already exists, the dependencies are merged into that chunk and that chunk is used.
*/
ensure: (paths: string[], callback: (require: <T>(path: string) => T) => void, chunkName?: string) => void;
context: (path: string, deep?: boolean, filter?: RegExp) => RequireContext;
/**
* Returns the module id of a dependency. The call is sync. No request to the server is fired. The compiler ensures that the dependency is available.
*
* The module id is a number in webpack (in contrast to node.js where it is a string, the filename).
*/
resolve(path: string): number;
/**
* Like require.resolve, but doesnt include the module into the bundle. Its a weak dependency.
*/
resolveWeak(path: string): number;
/**
* Ensures that the dependency is available, but dont execute it. This can be use for optimizing the position of a module in the chunks.
*/
include(path: string): void;
/**
* Multiple requires to the same module result in only one module execution and only one export. Therefore a cache in the runtime exists. Removing values from this cache cause new module execution and a new export. This is only needed in rare cases (for compatibility!).
*/
cache: {
[id: string]: any;
}
}
interface Module {
exports: any;
require(id: string): any;
id: string;
filename: string;
loaded: boolean;
parent: any;
children: any[];
hot: Hot;
}
type ModuleId = string|number;
interface Hot {
/**
* Accept code updates for the specified dependencies. The callback is called when dependencies were replaced.
* @param dependencies
* @param callback
*/
accept(dependencies: string[], callback: (updatedDependencies: ModuleId[]) => void): void;
/**
* Accept code updates for the specified dependencies. The callback is called when dependencies were replaced.
* @param dependency
* @param callback
*/
accept(dependency: string, callback: () => void): void;
/**
* Accept code updates for this module without notification of parents.
* This should only be used if the module doesnt export anything.
* The errHandler can be used to handle errors that occur while loading the updated module.
* @param errHandler
*/
accept(errHandler?: (err: Error) => void): void;
/**
* Do not accept updates for the specified dependencies. If any dependencies is updated, the code update fails with code "decline".
*/
decline(dependencies: string[]): void;
/**
* Do not accept updates for the specified dependencies. If any dependencies is updated, the code update fails with code "decline".
*/
decline(dependency: string): void;
/**
* Flag the current module as not update-able. If updated the update code would fail with code "decline".
*/
decline(): void;
/**
* Add a one time handler, which is executed when the current module code is replaced.
* Here you should destroy/remove any persistent resource you have claimed/created.
* If you want to transfer state to the new module, add it to data object.
* The data will be available at module.hot.data on the new module.
* @param callback
*/
dispose<T>(callback: (data: T) => void): void;
/**
* Add a one time handler, which is executed when the current module code is replaced.
* Here you should destroy/remove any persistent resource you have claimed/created.
* If you want to transfer state to the new module, add it to data object.
* The data will be available at module.hot.data on the new module.
* @param callback
*/
addDisposeHandler<T>(callback: (data: T) => void): void;
/**
* Remove a handler.
* This can useful to add a temporary dispose handler. You could i. e. replace code while in the middle of a multi-step async function.
* @param callback
*/
removeDisposeHandler<T>(callback: (data: T) => void): void;
/**
* Throws an exceptions if status() is not idle.
* Check all currently loaded modules for updates and apply updates if found.
* If no update was found, the callback is called with null.
* If autoApply is truthy the callback will be called with all modules that were disposed.
* apply() is automatically called with autoApply as options parameter.
* If autoApply is not set the callback will be called with all modules that will be disposed on apply().
* @param autoApply
* @param callback
*/
check(autoApply: boolean, callback: (err: Error, outdatedModules: ModuleId[]) => void): void;
/**
* Throws an exceptions if status() is not idle.
* Check all currently loaded modules for updates and apply updates if found.
* If no update was found, the callback is called with null.
* The callback will be called with all modules that will be disposed on apply().
* @param callback
*/
check(callback: (err: Error, outdatedModules: ModuleId[]) => void): void;
/**
* If status() != "ready" it throws an error.
* Continue the update process.
* @param options
* @param callback
*/
apply(options: AcceptOptions, callback: (err: Error, outdatedModules: ModuleId[]) => void): void;
/**
* If status() != "ready" it throws an error.
* Continue the update process.
* @param callback
*/
apply(callback: (err: Error, outdatedModules: ModuleId[]) => void): void;
/**
* Return one of idle, check, watch, watch-delay, prepare, ready, dispose, apply, abort or fail.
*/
status(): string;
/** Register a callback on status change. */
status(callback: (status: string) => void): void;
/** Register a callback on status change. */
addStatusHandler(callback: (status: string) => void): void;
/**
* Remove a registered status change handler.
* @param callback
*/
removeStatusHandler(callback: (status: string) => void): void;
active: boolean;
data: {};
}
interface AcceptOptions {
/**
* If true the update process continues even if some modules are not accepted (and would bubble to the entry point).
*/
ignoreUnaccepted?: boolean;
/**
* Indicates that apply() is automatically called by check function
*/
autoApply?: boolean;
}
}
declare var require: __WebpackModuleApi.RequireFunction;
/**
* The resource query of the current module.
*
* e.g. __resourceQuery === "?test" // Inside "file.js?test"
*/
declare var __resourceQuery: string;
/**
* Equals the config options output.publicPath.
*/
declare var __webpack_public_path__: string;
/**
* The raw require function. This expression isnt parsed by the Parser for dependencies.
*/
declare var __webpack_require__: any;
/**
* The internal chunk loading function
*
* @param chunkId The id for the chunk to load.
* @param callback A callback function called once the chunk is loaded.
*/
declare var __webpack_chunk_load__: (chunkId: any, callback: (require: (id: string) => any) => void) => void;
/**
* Access to the internal object of all modules.
*/
declare var __webpack_modules__: any[];
/**
* Access to the hash of the compilation.
*
* Only available with the HotModuleReplacementPlugin or the ExtendedAPIPlugin
*/
declare var __webpack_hash__: any;
/**
* Generates a require function that is not parsed by webpack. Can be used to do cool stuff with a global require function if available.
*/
declare var __non_webpack_require__: any;
/**
* Equals the config option debug
*/
declare var DEBUG: boolean;
declare var module: __WebpackModuleApi.Module;

View File

@@ -1,85 +0,0 @@
// Type definitions for fetch API
// Project: https://github.com/github/fetch
// Definitions by: Ryan Graham <https://github.com/ryan-codingintrigue>
// Definitions: https://github.com/borisyankov/DefinitelyTyped
declare class Request extends Body {
constructor(input: string|Request, init?:RequestInit);
method: string;
url: string;
headers: Headers;
context: string|RequestContext;
referrer: string;
mode: string|RequestMode;
credentials: string|RequestCredentials;
cache: string|RequestCache;
}
interface RequestInit {
method?: string;
headers?: HeaderInit|{ [index: string]: string };
body?: BodyInit;
mode?: string|RequestMode;
credentials?: string|RequestCredentials;
cache?: string|RequestCache;
}
declare enum RequestContext {
"audio", "beacon", "cspreport", "download", "embed", "eventsource", "favicon", "fetch",
"font", "form", "frame", "hyperlink", "iframe", "image", "imageset", "import",
"internal", "location", "manifest", "object", "ping", "plugin", "prefetch", "script",
"serviceworker", "sharedworker", "subresource", "style", "track", "video", "worker",
"xmlhttprequest", "xslt"
}
declare enum RequestMode { "same-origin", "no-cors", "cors" }
declare enum RequestCredentials { "omit", "same-origin", "include" }
declare enum RequestCache { "default", "no-store", "reload", "no-cache", "force-cache", "only-if-cached" }
declare class Headers {
append(name: string, value: string): void;
delete(name: string):void;
get(name: string): string;
getAll(name: string): Array<string>;
has(name: string): boolean;
set(name: string, value: string): void;
}
declare class Body {
bodyUsed: boolean;
arrayBuffer(): Promise<ArrayBuffer>;
blob(): Promise<Blob>;
formData(): Promise<FormData>;
json(): Promise<any>;
json<T>(): Promise<T>;
text(): Promise<string>;
}
declare class Response extends Body {
constructor(body?: BodyInit, init?: ResponseInit);
error(): Response;
redirect(url: string, status: number): Response;
type: string|ResponseType;
url: string;
status: number;
ok: boolean;
statusText: string;
headers: Headers;
clone(): Response;
}
declare enum ResponseType { "basic", "cors", "default", "error", "opaque" }
interface ResponseInit {
status: number;
statusText?: string;
headers?: HeaderInit;
}
declare type HeaderInit = Headers|Array<string>;
declare type BodyInit = Blob|FormData|string;
declare type RequestInfo = Request|string;
interface Window {
fetch(url: string|Request, init?: RequestInit): Promise<Response>;
}
declare var fetch: typeof window.fetch;

View File

@@ -9,14 +9,31 @@ using Newtonsoft.Json;
namespace Microsoft.AspNetCore.AngularServices
{
/// <summary>
/// Helpers for prepopulating Angular 2's 'http' service with data.
/// </summary>
public static class PrimeCacheHelper
{
/// <summary>
/// Performs an HTTP GET request to the specified URL and adds the resulting JSON data
/// to the Angular 'http' service cache.
/// </summary>
/// <param name="html">The <see cref="IHtmlHelper"/>.</param>
/// <param name="url">The URL to be requested.</param>
/// <returns>A task representing the HTML content to be rendered into the document.</returns>
[Obsolete("Use PrimeCacheAsync instead")]
public static Task<IHtmlContent> PrimeCache(this IHtmlHelper html, string url)
{
return PrimeCacheAsync(html, url);
}
/// <summary>
/// Performs an HTTP GET request to the specified URL and adds the resulting JSON data
/// to the Angular 'http' service cache.
/// </summary>
/// <param name="html">The <see cref="IHtmlHelper"/>.</param>
/// <param name="url">The URL to be requested.</param>
/// <returns>A task representing the HTML content to be rendered into the document.</returns>
public static async Task<IHtmlContent> PrimeCacheAsync(this IHtmlHelper html, string url)
{
// TODO: Consider deduplicating the PrimeCacheAsync calls (that is, if there are multiple requests to precache

View File

@@ -0,0 +1,12 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
[assembly: AssemblyMetadata("Serviceable", "True")]
[assembly: NeutralResourcesLanguage("en-us")]
[assembly: AssemblyCompany("Microsoft Corporation.")]
[assembly: AssemblyCopyright("© Microsoft Corporation. All rights reserved.")]
[assembly: AssemblyProduct("Microsoft ASP.NET Core")]

View File

@@ -18,12 +18,12 @@
"url": "https://github.com/aspnet/JavaScriptServices.git"
},
"dependencies": {
"angular2": "^2.0.0-beta.13",
"angular2": "2.0.0-beta.13",
"reflect-metadata": "0.1.2",
"rxjs": "5.0.0-beta.2"
},
"devDependencies": {
"es6-shim": "^0.35.0",
"reflect-metadata": "^0.1.2",
"rimraf": "^2.5.4",
"systemjs-builder": "^0.14.11",
"typescript": "^2.0.0",

View File

@@ -1,26 +1,28 @@
{
"version": "1.0.0-*",
"description": "Helpers for building Angular 2 applications on ASP.NET Core.",
"compilationOptions": {
"keyFile": "../../tools/Key.snk"
"version": "1.0.0-*",
"packOptions": {
"repository": {
"type": "git",
"url": "git://github.com/aspnet/javascriptservices"
},
"tags": [
"aspnetcore",
"aspnetcoremvc",
"nodeservices"
]
},
"authors": [ "Microsoft" ],
"tooling": {
"defaultNamespace": "Microsoft.AspNetCore.AngularServices"
"buildOptions": {
"warningsAsErrors": true,
"keyFile": "../../tools/Key.snk",
"xmlDoc": true
},
"dependencies": {
"Microsoft.AspNetCore.Mvc.TagHelpers": "1.0.1",
"Microsoft.AspNetCore.SpaServices": "1.0.0-*"
},
"frameworks": {
"net451": {
},
"netstandard1.6": {
"imports": [
"dotnet5.6",
"dnxcore50",
"portable-net45+win8"
]
}
"net451": {},
"netstandard1.6": {}
}
}

View File

@@ -1,8 +1,18 @@
namespace Microsoft.AspNetCore.NodeServices
{
/// <summary>
/// Represents a way of creating and invoking code in a Node.js environment.
/// </summary>
public enum NodeHostingModel
{
/// <summary>
/// An out-of-process Node.js instance where RPC calls are made via HTTP.
/// </summary>
Http,
/// <summary>
/// An out-of-process Node.js instance where RPC calls are made over binary sockets.
/// </summary>
Socket,
}
}

View File

@@ -3,8 +3,16 @@ using Microsoft.AspNetCore.NodeServices.HostingModels;
namespace Microsoft.AspNetCore.NodeServices
{
/// <summary>
/// Supplies INodeServices instances.
/// </summary>
public static class NodeServicesFactory
{
/// <summary>
/// Create an <see cref="INodeServices"/> instance according to the supplied options.
/// </summary>
/// <param name="options">Options for creating the <see cref="INodeServices"/> instance.</param>
/// <returns>An <see cref="INodeServices"/> instance.</returns>
public static INodeServices CreateNodeServices(NodeServicesOptions options)
{
if (options == null)

View File

@@ -8,14 +8,25 @@ using Microsoft.Extensions.Logging.Console;
namespace Microsoft.AspNetCore.NodeServices
{
/// <summary>
/// Describes options used to configure an <see cref="INodeServices"/> instance.
/// </summary>
public class NodeServicesOptions
{
/// <summary>
/// Defines the default <see cref="NodeHostingModel"/>.
/// </summary>
public const NodeHostingModel DefaultNodeHostingModel = NodeHostingModel.Http;
internal const string TimeoutConfigPropertyName = nameof(InvocationTimeoutMilliseconds);
private const int DefaultInvocationTimeoutMilliseconds = 60 * 1000;
private const string LogCategoryName = "Microsoft.AspNetCore.NodeServices";
private static readonly string[] DefaultWatchFileExtensions = { ".js", ".jsx", ".ts", ".tsx", ".json", ".html" };
/// <summary>
/// Creates a new instance of <see cref="NodeServicesOptions"/>.
/// </summary>
/// <param name="serviceProvider">The <see cref="IServiceProvider"/>.</param>
public NodeServicesOptions(IServiceProvider serviceProvider)
{
if (serviceProvider == null)
@@ -44,14 +55,49 @@ namespace Microsoft.AspNetCore.NodeServices
: new ConsoleLogger(LogCategoryName, null, false);
}
/// <summary>
/// Specifies which <see cref="NodeHostingModel"/> should be used.
/// </summary>
public NodeHostingModel HostingModel { get; set; }
/// <summary>
/// If set, this callback function will be invoked to supply the <see cref="INodeServices"/> instance.
/// </summary>
public Func<INodeInstance> NodeInstanceFactory { get; set; }
/// <summary>
/// If set, overrides the path to the root of your application. This path is used when locating Node.js modules relative to your project.
/// </summary>
public string ProjectPath { get; set; }
/// <summary>
/// If set, the Node.js instance should restart when any matching file on disk within your project changes.
/// </summary>
public string[] WatchFileExtensions { get; set; }
/// <summary>
/// The Node.js instance's stdout/stderr will be redirected to this <see cref="ILogger"/>.
/// </summary>
public ILogger NodeInstanceOutputLogger { get; set; }
/// <summary>
/// If true, the Node.js instance will accept incoming V8 debugger connections (e.g., from node-inspector).
/// </summary>
public bool LaunchWithDebugging { get; set; }
public IDictionary<string, string> EnvironmentVariables { get; set; }
/// <summary>
/// If <see cref="LaunchWithDebugging"/> is true, the Node.js instance will listen for V8 debugger connections on this port.
/// </summary>
public int DebuggingPort { get; set; }
/// <summary>
/// If set, starts the Node.js instance with the specified environment variables.
/// </summary>
public IDictionary<string, string> EnvironmentVariables { get; set; }
/// <summary>
/// Specifies the maximum duration, in milliseconds, that your .NET code should wait for Node.js RPC calls to return.
/// </summary>
public int InvocationTimeoutMilliseconds { get; set; }
}
}

View File

@@ -8,9 +8,18 @@ namespace Microsoft.Extensions.DependencyInjection
/// </summary>
public static class NodeServicesServiceCollectionExtensions
{
/// <summary>
/// Adds NodeServices support to the <paramref name="serviceCollection"/>.
/// </summary>
/// <param name="serviceCollection">The <see cref="IServiceCollection"/>.</param>
public static void AddNodeServices(this IServiceCollection serviceCollection)
=> AddNodeServices(serviceCollection, _ => {});
/// <summary>
/// Adds NodeServices support to the <paramref name="serviceCollection"/>.
/// </summary>
/// <param name="serviceCollection">The <see cref="IServiceCollection"/>.</param>
/// <param name="options">Options for configuring the <see cref="INodeServices"/> instances.</param>
[Obsolete("Use the AddNodeServices(Action<NodeServicesOptions> setupAction) overload instead.")]
public static void AddNodeServices(this IServiceCollection serviceCollection, NodeServicesOptions options)
{
@@ -20,6 +29,11 @@ namespace Microsoft.Extensions.DependencyInjection
});
}
/// <summary>
/// Adds NodeServices support to the <paramref name="serviceCollection"/>.
/// </summary>
/// <param name="serviceCollection">The <see cref="IServiceCollection"/>.</param>
/// <param name="setupAction">A callback that will be invoked to populate the <see cref="NodeServicesOptions"/>.</param>
public static void AddNodeServices(this IServiceCollection serviceCollection, Action<NodeServicesOptions> setupAction)
{
if (setupAction == null)

View File

@@ -4,8 +4,20 @@ using System.Threading.Tasks;
namespace Microsoft.AspNetCore.NodeServices.HostingModels
{
/// <summary>
/// Represents an instance of Node.js to which Remote Procedure Calls (RPC) may be sent.
/// </summary>
public interface INodeInstance : IDisposable
{
/// <summary>
/// Asynchronously invokes code in the Node.js instance.
/// </summary>
/// <typeparam name="T">The JSON-serializable data type that the Node.js code will asynchronously return.</typeparam>
/// <param name="cancellationToken">A <see cref="CancellationToken"/> that can be used to cancel the invocation.</param>
/// <param name="moduleName">The path to the Node.js module (i.e., JavaScript file) relative to your project root that contains the code to be invoked.</param>
/// <param name="exportNameOrNull">If set, specifies the CommonJS export to be invoked. If not set, the module's default CommonJS export itself must be a function to be invoked.</param>
/// <param name="args">Any sequence of JSON-serializable arguments to be passed to the Node.js function.</param>
/// <returns>A <see cref="Task{TResult}"/> representing the completion of the RPC call.</returns>
Task<T> InvokeExportAsync<T>(CancellationToken cancellationToken, string moduleName, string exportNameOrNull, params object[] args);
}
}

View File

@@ -2,15 +2,33 @@ using System;
namespace Microsoft.AspNetCore.NodeServices.HostingModels
{
/// <summary>
/// Represents an exception caused by invoking Node.js code.
/// </summary>
public class NodeInvocationException : Exception
{
/// <summary>
/// If true, indicates that the invocation failed because the Node.js instance could not be reached. For example,
/// it might have already shut down or previously crashed.
/// </summary>
public bool NodeInstanceUnavailable { get; private set; }
/// <summary>
/// Creates a new instance of <see cref="NodeInvocationException"/>.
/// </summary>
/// <param name="message">A description of the exception.</param>
/// <param name="details">Additional information, such as a Node.js stack trace, representing the exception.</param>
public NodeInvocationException(string message, string details)
: base(message + Environment.NewLine + details)
{
}
/// <summary>
/// Creates a new instance of <see cref="NodeInvocationException"/>.
/// </summary>
/// <param name="message">A description of the exception.</param>
/// <param name="details">Additional information, such as a Node.js stack trace, representing the exception.</param>
/// <param name="nodeInstanceUnavailable">Specifies a value for the <see cref="NodeInstanceUnavailable"/> flag.</param>
public NodeInvocationException(string message, string details, bool nodeInstanceUnavailable)
: this(message, details)
{

View File

@@ -1,9 +1,24 @@
namespace Microsoft.AspNetCore.NodeServices.HostingModels
{
/// <summary>
/// Describes an RPC call sent from .NET code to Node.js code.
/// </summary>
public class NodeInvocationInfo
{
/// <summary>
/// Specifies the path to the Node.js module (i.e., .js file) relative to the project root.
/// </summary>
public string ModuleName { get; set; }
/// <summary>
/// If set, specifies the name of CommonJS function export to be invoked.
/// If not set, the Node.js module's default export must itself be a function to be invoked.
/// </summary>
public string ExportedFunctionName { get; set; }
/// <summary>
/// A sequence of JSON-serializable arguments to be passed to the Node.js function being invoked.
/// </summary>
public object[] Args { get; set; }
}
}

View File

@@ -21,7 +21,11 @@ namespace Microsoft.AspNetCore.NodeServices.HostingModels
/// <seealso cref="Microsoft.AspNetCore.NodeServices.HostingModels.INodeInstance" />
public abstract class OutOfProcessNodeInstance : INodeInstance
{
/// <summary>
/// The <see cref="ILogger"/> to which the Node.js instance's stdout/stderr is being redirected.
/// </summary>
protected readonly ILogger OutputLogger;
private const string ConnectionEstablishedMessage = "[Microsoft.AspNetCore.NodeServices:Listening]";
private const string DebuggingStartedMessageFormat = @"-----
*** Node.js debugging is enabled ***
@@ -43,6 +47,18 @@ If you haven't yet installed node-inspector, you can do so as follows:
private bool _nodeProcessNeedsRestart;
private readonly string[] _watchFileExtensions;
/// <summary>
/// Creates a new instance of <see cref="OutOfProcessNodeInstance"/>.
/// </summary>
/// <param name="entryPointScript">The path to the entry point script that the Node instance should load and execute.</param>
/// <param name="projectPath">The root path of the current project. This is used when resolving Node.js module paths relative to the project root.</param>
/// <param name="watchFileExtensions">The filename extensions that should be watched within the project root. The Node instance will automatically shut itself down if any matching file changes.</param>
/// <param name="commandLineArguments">Additional command-line arguments to be passed to the Node.js instance.</param>
/// <param name="nodeOutputLogger">The <see cref="ILogger"/> to which the Node.js instance's stdout/stderr (and other log information) should be written.</param>
/// <param name="environmentVars">Environment variables to be set on the Node.js process.</param>
/// <param name="invocationTimeoutMilliseconds">The maximum duration, in milliseconds, to wait for RPC calls to complete.</param>
/// <param name="launchWithDebugging">If true, passes a flag to the Node.js process telling it to accept V8 debugger connections.</param>
/// <param name="debuggingPort">If debugging is enabled, the Node.js process should listen for V8 debugger connections on this port.</param>
public OutOfProcessNodeInstance(
string entryPointScript,
string projectPath,
@@ -71,6 +87,15 @@ If you haven't yet installed node-inspector, you can do so as follows:
ConnectToInputOutputStreams();
}
/// <summary>
/// Asynchronously invokes code in the Node.js instance.
/// </summary>
/// <typeparam name="T">The JSON-serializable data type that the Node.js code will asynchronously return.</typeparam>
/// <param name="cancellationToken">A <see cref="CancellationToken"/> that can be used to cancel the invocation.</param>
/// <param name="moduleName">The path to the Node.js module (i.e., JavaScript file) relative to your project root that contains the code to be invoked.</param>
/// <param name="exportNameOrNull">If set, specifies the CommonJS export to be invoked. If not set, the module's default CommonJS export itself must be a function to be invoked.</param>
/// <param name="args">Any sequence of JSON-serializable arguments to be passed to the Node.js function.</param>
/// <returns>A <see cref="Task{TResult}"/> representing the completion of the RPC call.</returns>
public async Task<T> InvokeExportAsync<T>(
CancellationToken cancellationToken, string moduleName, string exportNameOrNull, params object[] args)
{
@@ -154,21 +179,41 @@ If you haven't yet installed node-inspector, you can do so as follows:
}
}
/// <summary>
/// Disposes this instance.
/// </summary>
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
/// <summary>
/// Asynchronously invokes code in the Node.js instance.
/// </summary>
/// <typeparam name="T">The JSON-serializable data type that the Node.js code will asynchronously return.</typeparam>
/// <param name="invocationInfo">Specifies the Node.js function to be invoked and arguments to be passed to it.</param>
/// <param name="cancellationToken">A <see cref="CancellationToken"/> that can be used to cancel the invocation.</param>
/// <returns>A <see cref="Task{TResult}"/> representing the completion of the RPC call.</returns>
protected abstract Task<T> InvokeExportAsync<T>(
NodeInvocationInfo invocationInfo,
CancellationToken cancellationToken);
// This method is virtual, as it provides a way to override the NODE_PATH or the path to node.exe
/// <summary>
/// Configures a <see cref="ProcessStartInfo"/> instance describing how to launch the Node.js process.
/// </summary>
/// <param name="entryPointFilename">The entrypoint JavaScript file that the Node.js process should execute.</param>
/// <param name="projectPath">The root path of the project. This is used when locating Node.js modules relative to the project root.</param>
/// <param name="commandLineArguments">Command-line arguments to be passed to the Node.js process.</param>
/// <param name="environmentVars">Environment variables to be set on the Node.js process.</param>
/// <param name="launchWithDebugging">If true, passes a flag to the Node.js process telling it to accept V8 debugger connections.</param>
/// <param name="debuggingPort">If debugging is enabled, the Node.js process should listen for V8 debugger connections on this port.</param>
/// <returns></returns>
protected virtual ProcessStartInfo PrepareNodeProcessStartInfo(
string entryPointFilename, string projectPath, string commandLineArguments,
IDictionary<string, string> environmentVars, bool launchWithDebugging, int debuggingPort)
{
// This method is virtual, as it provides a way to override the NODE_PATH or the path to node.exe
string debuggingArgs;
if (launchWithDebugging)
{
@@ -217,16 +262,28 @@ If you haven't yet installed node-inspector, you can do so as follows:
return startInfo;
}
/// <summary>
/// Virtual method invoked whenever the Node.js process emits a line to its stdout.
/// </summary>
/// <param name="outputData">The line emitted to the Node.js process's stdout.</param>
protected virtual void OnOutputDataReceived(string outputData)
{
OutputLogger.LogInformation(outputData);
}
/// <summary>
/// Virtual method invoked whenever the Node.js process emits a line to its stderr.
/// </summary>
/// <param name="errorData">The line emitted to the Node.js process's stderr.</param>
protected virtual void OnErrorDataReceived(string errorData)
{
OutputLogger.LogError(errorData);
}
/// <summary>
/// Disposes the instance.
/// </summary>
/// <param name="disposing">True if the object is disposing or false if it is finalizing.</param>
protected virtual void Dispose(bool disposing)
{
if (!_disposed)
@@ -403,6 +460,9 @@ If you haven't yet installed node-inspector, you can do so as follows:
EnsureFileSystemWatcherIsDisposed();
}
/// <summary>
/// Implements the finalization part of the IDisposable pattern by calling Dispose(false).
/// </summary>
~OutOfProcessNodeInstance()
{
Dispose(false);

View File

@@ -7,6 +7,10 @@ using System.Threading.Tasks;
namespace Microsoft.AspNetCore.NodeServices.HostingModels.VirtualConnections
{
/// <summary>
/// A callback that will be invoked if the <see cref="VirtualConnectionClient"/> encounters a read error.
/// </summary>
/// <param name="ex"></param>
public delegate void VirtualConnectionReadErrorHandler(Exception ex);
/// <summary>

View File

@@ -4,18 +4,71 @@ using System.Threading.Tasks;
namespace Microsoft.AspNetCore.NodeServices
{
/// <summary>
/// Represents the ability to invoke code in a Node.js environment. Although the underlying Node.js instance
/// might change over time (e.g., the process might be restarted), the <see cref="INodeServices"/> instance
/// will remain constant.
/// </summary>
public interface INodeServices : IDisposable
{
/// <summary>
/// Asynchronously invokes code in the Node.js instance.
/// </summary>
/// <typeparam name="T">The JSON-serializable data type that the Node.js code will asynchronously return.</typeparam>
/// <param name="moduleName">The path to the Node.js module (i.e., JavaScript file) relative to your project root whose default CommonJS export is the function to be invoked.</param>
/// <param name="args">Any sequence of JSON-serializable arguments to be passed to the Node.js function.</param>
/// <returns>A <see cref="Task{TResult}"/> representing the completion of the RPC call.</returns>
Task<T> InvokeAsync<T>(string moduleName, params object[] args);
/// <summary>
/// Asynchronously invokes code in the Node.js instance.
/// </summary>
/// <typeparam name="T">The JSON-serializable data type that the Node.js code will asynchronously return.</typeparam>
/// <param name="cancellationToken">A <see cref="CancellationToken"/> that can be used to cancel the invocation.</param>
/// <param name="moduleName">The path to the Node.js module (i.e., JavaScript file) relative to your project root whose default CommonJS export is the function to be invoked.</param>
/// <param name="args">Any sequence of JSON-serializable arguments to be passed to the Node.js function.</param>
/// <returns>A <see cref="Task{TResult}"/> representing the completion of the RPC call.</returns>
Task<T> InvokeAsync<T>(CancellationToken cancellationToken, string moduleName, params object[] args);
/// <summary>
/// Asynchronously invokes code in the Node.js instance.
/// </summary>
/// <typeparam name="T">The JSON-serializable data type that the Node.js code will asynchronously return.</typeparam>
/// <param name="moduleName">The path to the Node.js module (i.e., JavaScript file) relative to your project root that contains the code to be invoked.</param>
/// <param name="exportedFunctionName">Specifies the CommonJS export to be invoked.</param>
/// <param name="args">Any sequence of JSON-serializable arguments to be passed to the Node.js function.</param>
/// <returns>A <see cref="Task{TResult}"/> representing the completion of the RPC call.</returns>
Task<T> InvokeExportAsync<T>(string moduleName, string exportedFunctionName, params object[] args);
/// <summary>
/// Asynchronously invokes code in the Node.js instance.
/// </summary>
/// <typeparam name="T">The JSON-serializable data type that the Node.js code will asynchronously return.</typeparam>
/// <param name="cancellationToken">A <see cref="CancellationToken"/> that can be used to cancel the invocation.</param>
/// <param name="moduleName">The path to the Node.js module (i.e., JavaScript file) relative to your project root that contains the code to be invoked.</param>
/// <param name="exportedFunctionName">Specifies the CommonJS export to be invoked.</param>
/// <param name="args">Any sequence of JSON-serializable arguments to be passed to the Node.js function.</param>
/// <returns>A <see cref="Task{TResult}"/> representing the completion of the RPC call.</returns>
Task<T> InvokeExportAsync<T>(CancellationToken cancellationToken, string moduleName, string exportedFunctionName, params object[] args);
/// <summary>
/// Asynchronously invokes code in the Node.js instance.
/// </summary>
/// <typeparam name="T">The JSON-serializable data type that the Node.js code will asynchronously return.</typeparam>
/// <param name="moduleName">The path to the Node.js module (i.e., JavaScript file) relative to your project root whose default CommonJS export is the function to be invoked.</param>
/// <param name="args">Any sequence of JSON-serializable arguments to be passed to the Node.js function.</param>
/// <returns>A <see cref="Task{TResult}"/> representing the completion of the RPC call.</returns>
[Obsolete("Use InvokeAsync instead")]
Task<T> Invoke<T>(string moduleName, params object[] args);
/// <summary>
/// Asynchronously invokes code in the Node.js instance.
/// </summary>
/// <typeparam name="T">The JSON-serializable data type that the Node.js code will asynchronously return.</typeparam>
/// <param name="moduleName">The path to the Node.js module (i.e., JavaScript file) relative to your project root that contains the code to be invoked.</param>
/// <param name="exportedFunctionName">Specifies the CommonJS export to be invoked.</param>
/// <param name="args">Any sequence of JSON-serializable arguments to be passed to the Node.js function.</param>
/// <returns>A <see cref="Task{TResult}"/> representing the completion of the RPC call.</returns>
[Obsolete("Use InvokeExportAsync instead")]
Task<T> InvokeExport<T>(string moduleName, string exportedFunctionName, params object[] args);
}

View File

@@ -0,0 +1,12 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
[assembly: AssemblyMetadata("Serviceable", "True")]
[assembly: NeutralResourcesLanguage("en-us")]
[assembly: AssemblyCompany("Microsoft Corporation.")]
[assembly: AssemblyCopyright("© Microsoft Corporation. All rights reserved.")]
[assembly: AssemblyProduct("Microsoft ASP.NET Core")]

View File

@@ -4,8 +4,17 @@ using System.Reflection;
namespace Microsoft.AspNetCore.NodeServices
{
/// <summary>
/// Contains methods for reading embedded resources.
/// </summary>
public static class EmbeddedResourceReader
{
/// <summary>
/// Reads the specified embedded resource from a given assembly.
/// </summary>
/// <param name="assemblyContainingType">Any <see cref="Type"/> in the assembly whose resource is to be read.</param>
/// <param name="path">The path of the resource to be read.</param>
/// <returns>The contents of the resource.</returns>
public static string Read(Type assemblyContainingType, string path)
{
var asm = assemblyContainingType.GetTypeInfo().Assembly;

View File

@@ -3,19 +3,31 @@ using System.IO;
namespace Microsoft.AspNetCore.NodeServices
{
// Makes it easier to pass script files to Node in a way that's sure to clean up after the process exits
/// <summary>
/// Makes it easier to pass script files to Node in a way that's sure to clean up after the process exits.
/// </summary>
public sealed class StringAsTempFile : IDisposable
{
private bool _disposedValue;
/// <summary>
/// Create a new instance of <see cref="StringAsTempFile"/>.
/// </summary>
/// <param name="content">The contents of the temporary file to be created.</param>
public StringAsTempFile(string content)
{
FileName = Path.GetTempFileName();
File.WriteAllText(FileName, content);
}
/// <summary>
/// Specifies the filename of the temporary file.
/// </summary>
public string FileName { get; }
/// <summary>
/// Disposes the instance and deletes the associated temporary file.
/// </summary>
public void Dispose()
{
DisposeImpl(true);
@@ -37,6 +49,9 @@ namespace Microsoft.AspNetCore.NodeServices
}
}
/// <summary>
/// Implements the finalization part of the IDisposable pattern by calling Dispose(false).
/// </summary>
~StringAsTempFile()
{
DisposeImpl(false);

View File

@@ -1,17 +1,31 @@
{
"version": "1.0.0-*",
"description": "Invoke Node.js modules at runtime in ASP.NET Core applications.",
"compilationOptions": {
"keyFile": "../../tools/Key.snk"
"version": "1.0.0-*",
"packOptions": {
"repository": {
"type": "git",
"url": "git://github.com/aspnet/javascriptservices"
},
"tags": [
"aspnetcore",
"aspnetcoremvc",
"nodeservices"
]
},
"buildOptions": {
"warningsAsErrors": true,
"keyFile": "../../tools/Key.snk",
"embed": [
"Content/**/*"
],
"xmlDoc": true
},
"authors": [ "Microsoft" ],
"dependencies": {
"Microsoft.AspNetCore.Hosting.Abstractions": "1.0.0",
"Microsoft.Extensions.Configuration.Json": "1.0.0",
"Microsoft.Extensions.DependencyInjection.Abstractions": "1.0.0",
"Microsoft.Extensions.Logging.Console": "1.0.0",
"Microsoft.Extensions.PlatformAbstractions": "1.0.0",
"Newtonsoft.Json": "9.0.1"
"Newtonsoft.Json": "9.0.1",
"NETStandard.Library": "1.6.0"
},
"frameworks": {
"net451": {
@@ -22,27 +36,18 @@
"Microsoft.Tpl.Dataflow": "4.5.24"
}
},
"netstandard1.3": {
"imports": [
"dotnet5.6",
"dnxcore50",
"portable-net45+win8"
],
"netstandard1.6": {
"dependencies": {
"System.Console": "4.0.0",
"System.Diagnostics.Process": "4.1.0",
"System.IO.Pipes": "4.0.0",
"System.Net.Http": "4.1.0",
"System.Net.Sockets": "4.1.0",
"System.Runtime.InteropServices.RuntimeInformation": "4.0.0",
"System.Text.RegularExpressions": "4.1.0",
"System.Threading.Tasks.Dataflow": "4.5.25"
"System.Threading.Tasks.Dataflow": "4.6.0"
}
}
},
"buildOptions": {
"embed": [
"Content/**/*"
"scripts": {
"prepublish": [
"npm install",
"node node_modules/webpack/bin/webpack.js"
]
}
}

View File

@@ -0,0 +1,12 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
[assembly: AssemblyMetadata("Serviceable", "True")]
[assembly: NeutralResourcesLanguage("en-us")]
[assembly: AssemblyCompany("Microsoft Corporation.")]
[assembly: AssemblyCopyright("© Microsoft Corporation. All rights reserved.")]
[assembly: AssemblyProduct("Microsoft ASP.NET Core")]

View File

@@ -1,4 +1,3 @@
/typings/
/node_modules/
/*.js
/*.d.ts

View File

@@ -1,11 +1,11 @@
{
"name": "redux-typed",
"version": "1.0.2",
"version": "2.0.0",
"description": "Helpers for building React+Redux apps with strong TypeScript type checking everywhere",
"main": "main.js",
"typings": "main.d.ts",
"scripts": {
"prepublish": "rimraf *.d.ts && tsd update && tsc && echo 'Finished building NPM package \"redux-typed\"'",
"prepublish": "rimraf *.d.ts && tsc && echo 'Finished building NPM package \"redux-typed\"'",
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "Microsoft",
@@ -18,7 +18,10 @@
"url": "https://github.com/aspnet/JavaScriptServices.git"
},
"devDependencies": {
"@types/react": "^0.14.38",
"@types/react-redux": "^4.4.32",
"@types/redux": "^3.5.30",
"rimraf": "^2.5.4",
"typescript": "^1.8.10"
"typescript": "^2.0.0"
}
}

View File

@@ -4,8 +4,12 @@
"module": "commonjs",
"target": "es5",
"declaration": true,
"outDir": "."
"outDir": ".",
"lib": ["es2015", "dom"]
},
"files": [
"src/main.ts"
],
"exclude": [
"node_modules"
]

View File

@@ -1,18 +0,0 @@
{
"version": "v4",
"repo": "borisyankov/DefinitelyTyped",
"ref": "master",
"path": "typings",
"bundle": "typings/tsd.d.ts",
"installed": {
"react/react.d.ts": {
"commit": "f4b1797c1201b6c575668f5d7ea12d9b1ab21846"
},
"react-redux/react-redux.d.ts": {
"commit": "f4b1797c1201b6c575668f5d7ea12d9b1ab21846"
},
"redux/redux.d.ts": {
"commit": "f4b1797c1201b6c575668f5d7ea12d9b1ab21846"
}
}
}

View File

@@ -1,26 +1,28 @@
{
"version": "1.0.0-*",
"description": "Helpers for building React applications on ASP.NET Core.",
"compilationOptions": {
"keyFile": "../../tools/Key.snk"
"version": "1.0.0-*",
"packOptions": {
"repository": {
"type": "git",
"url": "git://github.com/aspnet/javascriptservices"
},
"tags": [
"aspnetcore",
"aspnetcoremvc",
"nodeservices"
]
},
"authors": [ "Microsoft" ],
"tooling": {
"defaultNamespace": "Microsoft.AspNetCore.ReactServices"
"buildOptions": {
"warningsAsErrors": true,
"keyFile": "../../tools/Key.snk",
"xmlDoc": true
},
"dependencies": {
"Microsoft.AspNetCore.Mvc.TagHelpers": "1.0.1",
"Microsoft.AspNetCore.SpaServices": "1.0.0-*"
},
"frameworks": {
"net451": {
},
"netstandard1.6": {
"imports": [
"dotnet5.6",
"dnxcore50",
"portable-net45+win8"
]
}
"net451": {},
"netstandard1.6": {}
}
}

View File

@@ -1 +1,2 @@
/bin/
/node_modules/

View File

@@ -1,20 +1,178 @@
// Pass through the invocation to the 'aspnet-prerendering' package, verifying that it can be loaded
module.exports.renderToString = function (callback) {
var aspNetPrerendering;
try {
aspNetPrerendering = require('aspnet-prerendering');
} catch (ex) {
// 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;
}
(function(e, a) { for(var i in a) e[i] = a[i]; }(exports, /******/ (function(modules) { // webpackBootstrap
/******/ // The module cache
/******/ var installedModules = {};
return aspNetPrerendering.renderToString.apply(this, arguments);
};
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/ // Check if module is in cache
/******/ if(installedModules[moduleId])
/******/ return installedModules[moduleId].exports;
/******/ // Create a new module (and put it into the cache)
/******/ var module = installedModules[moduleId] = {
/******/ exports: {},
/******/ id: moduleId,
/******/ loaded: false
/******/ };
/******/ // Execute the module function
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/ // Flag the module as loaded
/******/ module.loaded = true;
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/ // expose the modules object (__webpack_modules__)
/******/ __webpack_require__.m = modules;
/******/ // expose the module cache
/******/ __webpack_require__.c = installedModules;
/******/ // __webpack_public_path__
/******/ __webpack_require__.p = "";
/******/ // Load entry module and return exports
/******/ return __webpack_require__(0);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ function(module, exports, __webpack_require__) {
module.exports = __webpack_require__(1);
/***/ },
/* 1 */
/***/ function(module, exports, __webpack_require__) {
"use strict";
var path = __webpack_require__(2);
// Separate declaration and export just to add type checking on function signature
exports.renderToString = renderToStringImpl;
// This function is invoked by .NET code (via NodeServices). Its job is to hand off execution to the application's
// prerendering boot function. It can operate in two modes:
// [1] Legacy mode
// This is for backward compatibility with projects created with templates older than the generator version 0.6.0.
// In this mode, we don't really do anything here - we just load the 'aspnet-prerendering' NPM module (which must
// exist in node_modules, and must be v1.x (not v2+)), and pass through all the parameters to it. Code in
// 'aspnet-prerendering' v1.x will locate the boot function and invoke it.
// The drawback to this mode is that, for it to work, you have to deploy node_modules to production.
// [2] Current mode
// This is for projects created with the Yeoman generator 0.6.0+ (or projects manually updated). In this mode,
// we don't invoke 'require' at runtime at all. All our dependencies are bundled into the NuGet package, so you
// don't have to deploy node_modules to production.
// To determine whether we're in mode [1] or [2], the code locates your prerendering boot function, and checks whether
// a certain flag is attached to the function instance.
function renderToStringImpl(callback, applicationBasePath, bootModule, absoluteRequestUrl, requestPathAndQuery, customDataParameter, overrideTimeoutMilliseconds) {
try {
var forceLegacy = isLegacyAspNetPrerendering();
var renderToStringFunc = !forceLegacy && findRenderToStringFunc(applicationBasePath, bootModule);
var isNotLegacyMode = renderToStringFunc && renderToStringFunc['isServerRenderer'];
if (isNotLegacyMode) {
// Current (non-legacy) mode - we invoke the exported function directly (instead of going through aspnet-prerendering)
// It's type-safe to just apply the incoming args to this function, because we already type-checked that it's a RenderToStringFunc,
// just like renderToStringImpl itself is.
renderToStringFunc.apply(null, arguments);
}
else {
// Legacy mode - just hand off execution to 'aspnet-prerendering' v1.x, which must exist in node_modules at runtime
var aspNetPrerenderingV1RenderToString = __webpack_require__(3).renderToString;
if (aspNetPrerenderingV1RenderToString) {
aspNetPrerenderingV1RenderToString(callback, applicationBasePath, bootModule, absoluteRequestUrl, requestPathAndQuery, customDataParameter, overrideTimeoutMilliseconds);
}
else {
callback('If you use aspnet-prerendering >= 2.0.0, you must update your server-side boot module to call createServerRenderer. '
+ 'Either update your boot module code, or revert to aspnet-prerendering version 1.x');
}
}
}
catch (ex) {
// Make sure loading errors are reported back to the .NET part of the app
callback('Prerendering failed because of error: '
+ ex.stack
+ '\nCurrent directory is: '
+ process.cwd());
}
}
;
function findBootModule(applicationBasePath, bootModule) {
var bootModuleNameFullPath = path.resolve(applicationBasePath, bootModule.moduleName);
if (bootModule.webpackConfig) {
// If you're using asp-prerender-webpack-config, you're definitely in legacy mode
return null;
}
else {
return require(bootModuleNameFullPath);
}
}
function findRenderToStringFunc(applicationBasePath, bootModule) {
// First try to load the module
var foundBootModule = findBootModule(applicationBasePath, bootModule);
if (foundBootModule === null) {
return null; // Must be legacy mode
}
// Now try to pick out the function they want us to invoke
var renderToStringFunc;
if (bootModule.exportName) {
// Explicitly-named export
renderToStringFunc = foundBootModule[bootModule.exportName];
}
else if (typeof foundBootModule !== 'function') {
// TypeScript-style default export
renderToStringFunc = foundBootModule.default;
}
else {
// Native default export
renderToStringFunc = foundBootModule;
}
// Validate the result
if (typeof renderToStringFunc !== 'function') {
if (bootModule.exportName) {
throw new Error("The module at " + bootModule.moduleName + " has no function export named " + bootModule.exportName + ".");
}
else {
throw new Error("The module at " + bootModule.moduleName + " does not export a default function, and you have not specified which export to invoke.");
}
}
return renderToStringFunc;
}
function isLegacyAspNetPrerendering() {
var version = getAspNetPrerenderingPackageVersion();
return version && /^1\./.test(version);
}
function getAspNetPrerenderingPackageVersion() {
try {
var packageEntryPoint = require.resolve('aspnet-prerendering');
var packageDir = path.dirname(packageEntryPoint);
var packageJsonPath = path.join(packageDir, 'package.json');
var packageJson = require(packageJsonPath);
return packageJson.version.toString();
}
catch (ex) {
// Implies aspnet-prerendering isn't in node_modules at all (or node_modules itself doesn't exist,
// which will be the case in production based on latest templates).
return null;
}
}
/***/ },
/* 2 */
/***/ function(module, exports) {
module.exports = require("path");
/***/ },
/* 3 */
/***/ function(module, exports) {
module.exports = require("aspnet-prerendering");
/***/ }
/******/ ])));

View File

@@ -1,20 +1,86 @@
// Pass through the invocation to the 'aspnet-webpack' package, verifying that it can be loaded
module.exports.createWebpackDevServer = function (callback) {
var aspNetWebpack;
try {
aspNetWebpack = require('aspnet-webpack');
} catch (ex) {
// 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;
}
(function(e, a) { for(var i in a) e[i] = a[i]; }(exports, /******/ (function(modules) { // webpackBootstrap
/******/ // The module cache
/******/ var installedModules = {};
return aspNetWebpack.createWebpackDevServer.apply(this, arguments);
};
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/ // Check if module is in cache
/******/ if(installedModules[moduleId])
/******/ return installedModules[moduleId].exports;
/******/ // Create a new module (and put it into the cache)
/******/ var module = installedModules[moduleId] = {
/******/ exports: {},
/******/ id: moduleId,
/******/ loaded: false
/******/ };
/******/ // Execute the module function
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/ // Flag the module as loaded
/******/ module.loaded = true;
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/ // expose the modules object (__webpack_modules__)
/******/ __webpack_require__.m = modules;
/******/ // expose the module cache
/******/ __webpack_require__.c = installedModules;
/******/ // __webpack_public_path__
/******/ __webpack_require__.p = "";
/******/ // Load entry module and return exports
/******/ return __webpack_require__(0);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ function(module, exports, __webpack_require__) {
module.exports = __webpack_require__(4);
/***/ },
/* 1 */,
/* 2 */,
/* 3 */,
/* 4 */
/***/ function(module, exports, __webpack_require__) {
"use strict";
// Pass through the invocation to the 'aspnet-webpack' package, verifying that it can be loaded
function createWebpackDevServer(callback) {
var aspNetWebpack;
try {
aspNetWebpack = __webpack_require__(5);
}
catch (ex) {
// 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 aspNetWebpack.createWebpackDevServer.apply(this, arguments);
}
exports.createWebpackDevServer = createWebpackDevServer;
/***/ },
/* 5 */
/***/ function(module, exports) {
module.exports = require("aspnet-webpack");
/***/ }
/******/ ])));

View File

@@ -1,14 +1,36 @@
using System;
namespace Microsoft.AspNetCore.SpaServices.Prerendering
{
/// <summary>
/// Describes how to find the JavaScript code that performs prerendering.
/// </summary>
public class JavaScriptModuleExport
{
/// <summary>
/// Creates a new instance of <see cref="JavaScriptModuleExport"/>.
/// </summary>
/// <param name="moduleName">The path to the JavaScript module containing prerendering code.</param>
public JavaScriptModuleExport(string moduleName)
{
ModuleName = moduleName;
}
/// <summary>
/// Specifies the path to the JavaScript module containing prerendering code.
/// </summary>
public string ModuleName { get; private set; }
/// <summary>
/// If set, specifies the name of the CommonJS export that is the prerendering function to execute.
/// If not set, the JavaScript module's default CommonJS export must itself be the prerendering function.
/// </summary>
public string ExportName { get; set; }
/// <summary>
/// Obsolete. Do not use. Instead, configure Webpack to build a Node.js-compatible bundle and reference that directly.
/// </summary>
[Obsolete("Do not use. This feature will be removed. Instead, configure Webpack to build a Node.js-compatible bundle and reference that directly.")]
public string WebpackConfig { get; set; }
}
}

View File

@@ -11,6 +11,9 @@ using Newtonsoft.Json;
namespace Microsoft.AspNetCore.SpaServices.Prerendering
{
/// <summary>
/// A tag helper for prerendering JavaScript applications on the server.
/// </summary>
[HtmlTargetElement(Attributes = PrerenderModuleAttributeName)]
public class PrerenderTagHelper : TagHelper
{
@@ -24,6 +27,10 @@ namespace Microsoft.AspNetCore.SpaServices.Prerendering
private readonly string _applicationBasePath;
private readonly INodeServices _nodeServices;
/// <summary>
/// Creates a new instance of <see cref="PrerenderTagHelper"/>.
/// </summary>
/// <param name="serviceProvider">The <see cref="IServiceProvider"/>.</param>
public PrerenderTagHelper(IServiceProvider serviceProvider)
{
var hostEnv = (IHostingEnvironment) serviceProvider.GetService(typeof(IHostingEnvironment));
@@ -39,25 +46,51 @@ namespace Microsoft.AspNetCore.SpaServices.Prerendering
}
}
/// <summary>
/// Specifies the path to the JavaScript module containing prerendering code.
/// </summary>
[HtmlAttributeName(PrerenderModuleAttributeName)]
public string ModuleName { get; set; }
/// <summary>
/// If set, specifies the name of the CommonJS export that is the prerendering function to execute.
/// If not set, the JavaScript module's default CommonJS export must itself be the prerendering function.
/// </summary>
[HtmlAttributeName(PrerenderExportAttributeName)]
public string ExportName { get; set; }
/// <summary>
/// Obsolete. Do not use. Instead, configure Webpack to build a Node.js-compatible bundle and reference that directly.
/// </summary>
[Obsolete("Do not use. This feature will be removed. Instead, configure Webpack to build a Node.js-compatible bundle and reference that directly.")]
[HtmlAttributeName(PrerenderWebpackConfigAttributeName)]
public string WebpackConfigPath { get; set; }
/// <summary>
/// An optional JSON-serializable parameter to be supplied to the prerendering code.
/// </summary>
[HtmlAttributeName(PrerenderDataAttributeName)]
public object CustomDataParameter { get; set; }
/// <summary>
/// The maximum duration to wait for prerendering to complete.
/// </summary>
[HtmlAttributeName(PrerenderTimeoutAttributeName)]
public int TimeoutMillisecondsParameter { get; set; }
/// <summary>
/// The <see cref="ViewContext"/>.
/// </summary>
[HtmlAttributeNotBound]
[ViewContext]
public ViewContext ViewContext { get; set; }
/// <summary>
/// Executes the tag helper to perform server-side prerendering.
/// </summary>
/// <param name="context">The <see cref="TagHelperContext"/>.</param>
/// <param name="output">The <see cref="TagHelperOutput"/>.</param>
/// <returns>A <see cref="Task"/> representing the operation.</returns>
public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
{
// We want to pass the original, unencoded incoming URL data through to Node, so that
@@ -79,7 +112,9 @@ namespace Microsoft.AspNetCore.SpaServices.Prerendering
new JavaScriptModuleExport(ModuleName)
{
ExportName = ExportName,
#pragma warning disable CS0618 // Type or member is obsolete
WebpackConfig = WebpackConfigPath
#pragma warning restore CS0618 // Type or member is obsolete
},
unencodedAbsoluteUrl,
unencodedPathAndQuery,

View File

@@ -4,6 +4,9 @@ using Microsoft.AspNetCore.NodeServices;
namespace Microsoft.AspNetCore.SpaServices.Prerendering
{
/// <summary>
/// Performs server-side prerendering by invoking code in Node.js.
/// </summary>
public static class Prerenderer
{
private static readonly Lazy<StringAsTempFile> NodeScript;
@@ -17,6 +20,17 @@ namespace Microsoft.AspNetCore.SpaServices.Prerendering
});
}
/// <summary>
/// Performs server-side prerendering by invoking code in Node.js.
/// </summary>
/// <param name="applicationBasePath">The root path to your application. This is used when resolving project-relative paths.</param>
/// <param name="nodeServices">The instance of <see cref="INodeServices"/> that will be used to invoke JavaScript code.</param>
/// <param name="bootModule">The path to the JavaScript file containing the prerendering logic.</param>
/// <param name="requestAbsoluteUrl">The URL of the currently-executing HTTP request. This is supplied to the prerendering code.</param>
/// <param name="requestPathAndQuery">The path and query part of the URL of the currently-executing HTTP request. This is supplied to the prerendering code.</param>
/// <param name="customDataParameter">An optional JSON-serializable parameter to be supplied to the prerendering code.</param>
/// <param name="timeoutMilliseconds">The maximum duration to wait for prerendering to complete.</param>
/// <returns></returns>
public static Task<RenderToStringResult> RenderToString(
string applicationBasePath,
INodeServices nodeServices,

View File

@@ -2,10 +2,28 @@ using Newtonsoft.Json.Linq;
namespace Microsoft.AspNetCore.SpaServices.Prerendering
{
/// <summary>
/// Describes the prerendering result returned by JavaScript code.
/// </summary>
public class RenderToStringResult
{
/// <summary>
/// If set, specifies JSON-serializable data that should be added as a set of global JavaScript variables in the document.
/// This can be used to transfer arbitrary data from server-side prerendering code to client-side code (for example, to
/// transfer the state of a Redux store).
/// </summary>
public JObject Globals { get; set; }
/// <summary>
/// The HTML generated by the prerendering logic.
/// </summary>
public string Html { get; set; }
/// <summary>
/// If set, specifies that instead of rendering HTML, the response should be an HTTP redirection to this URL.
/// This can be used if the prerendering code determines that the requested URL would lead to a redirection according
/// to the SPA's routing configuration.
/// </summary>
public string RedirectUrl { get; set; }
}
}

View File

@@ -0,0 +1,12 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
[assembly: AssemblyMetadata("Serviceable", "True")]
[assembly: NeutralResourcesLanguage("en-us")]
[assembly: AssemblyCompany("Microsoft Corporation.")]
[assembly: AssemblyCopyright("© Microsoft Corporation. All rights reserved.")]
[assembly: AssemblyProduct("Microsoft ASP.NET Core")]

View File

@@ -38,6 +38,8 @@ If you're starting from scratch, you might prefer to use the `aspnetcore-spa` Ye
See: [Getting started with the aspnetcore-spa generator](http://blog.stevensanderson.com/2016/05/02/angular2-react-knockout-apps-on-aspnet-core/)
Also, if you want to debug projects created with the aspnetcore-spa generator, see [Debugging your projects](#debugging-your-projects)
## Server-side prerendering
The `SpaServices` package isn't tied to any particular client-side framework, and it doesn't force you to set up your client-side application in any one particular style. So, `SpaServices` doesn't contain hard-coded logic for rendering Angular 2 / React / etc. components.
@@ -50,7 +52,7 @@ Make sure you've installed the `Microsoft.AspNetCore.SpaServices` NuGet package
Now go to your `Views/_ViewImports.cshtml` file, and add the following line:
@addTagHelper "*, Microsoft.AspNetCore.SpaServices"
@addTagHelper *, Microsoft.AspNetCore.SpaServices
### 2. Use asp-prerender-* in a view
@@ -129,45 +131,54 @@ This can be useful if, for example, you want to avoid loading the same data twic
### 4. Enabling webpack build tooling
Of course, rather than writing your `boot-server` module and your entire SPA in plain ES5 JavaScript, it's quite likely that you'll want to write your client-side code in TypeScript or at least ES2015 code. To enable this, you can either:
Of course, rather than writing your `boot-server` module and your entire SPA in plain ES5 JavaScript, it's quite likely that you'll want to write your client-side code in TypeScript or at least ES2015 code. To enable this, you need to set up a build system.
* Set up some build tool such as Babel to transpile to ES5, and always remember to run this to generate plain ES5 `.js` files before you run your application
* Or, more conveniently, use [webpack](https://webpack.github.io/) along with the `asp-prerender-webpack-config` attribute so that `Microsoft.AspNetCore.SpaServices` can automatically build your boot module and the SPA code that it references. Then there's no need for `.js` files even to be written to disk - the build process is all dynamic and in memory.
#### Example: Configuring Webpack to build TypeScript
To enable webpack builds for your server-side prerendering, amend your MVC view to specify the location of your webpack configuration file using an `asp-prerender-webpack-config` attribute, e.g.:
Let's say you want to write your boot module and SPA code in TypeScript, and build it using Webpack. First ensure that `webpack` is installed, along with the libraries needed for TypeScript compilation:
<div id="my-spa" asp-prerender-module="ClientApp/boot-server"
asp-prerender-webpack-config="webpack.config.js"></div>
You'll also need to install the NPM module `aspnet-webpack` if you don't have it already, e.g.:
npm install --save aspnet-webpack
This includes webpack as well as the server-side code needed to invoke it from ASP.NET Core at runtime.
Now, assuming you have a working webpack configuration at `webpack.config.js`, your boot module and SPA code will dynamically be built using webpack.
#### Example: Configuring webpack to build TypeScript
Let's say you want to write your boot module and SPA code in TypeScript. First ensure that `aspnet-webpack` is installed, along with the libraries needed for TypeScript compilation:
npm install --save aspnet-webpack ts-loader typescript
npm install -g webpack
npm install --save ts-loader typescript
Next, create a file `webpack.config.js` at the root of your project, containing:
```javascript
var path = require('path');
module.exports = {
entry: { 'main-server': './ClientApp/boot-server.ts' },
resolve: { extensions: [ '', '.js', '.ts' ] },
output: {
path: path.join(__dirname, './ClientApp/dist'),
filename: '[name].js',
libraryTarget: 'commonjs'
},
module: {
loaders: [
{ test: /\.ts$/, loader: 'ts-loader' }
]
}
},
target: 'node',
devtool: 'inline-source-map'
};
```
This tells webpack that it should compile `.ts` files using TypeScript, and that when looking for modules by name (e.g., `boot-server`), it should also find files with `.js` and `.ts` extensions.
If you don't already have a `tsconfig.json` file at the root of your project, add one now. Make sure your `tsconfig.json` includes `"es6"` in its `"lib"` array so that TypeScript knows about intrinsics such as `Promise`. Here's an example `tsconfig.json`:
```json
{
"compilerOptions": {
"moduleResolution": "node",
"target": "es5",
"sourceMap": true,
"lib": [ "es6", "dom" ]
},
"exclude": [ "bin", "node_modules" ]
}
```
Now you can delete `ClientApp/boot-server.js`, and in its place, create `ClientApp/boot-server.ts`, containing the TypeScript equivalent of what you had before:
```javascript
@@ -184,12 +195,9 @@ export default function (params: any): Promise<{ html: string}> {
}
```
Finally, you can tell `SpaServices` to use the Webpack environment you've just set up. In your MVC view where you use `aspnet-prerender-module`, also specify `aspnet-prerender-webpack-config`:
Finally, run `webpack` on the command line to build `ClientApp/dist/main-server.js`. Then you can tell `SpaServices` to use that file for server-side prerendering. In your MVC view where you use `aspnet-prerender-module`, update the attribute value:
<div id="my-spa" asp-prerender-module="ClientApp/boot-server"
asp-prerender-webpack-config="webpack.config.js"></div>
Now your `boot-server.ts` code should get executed when your ASP.NET Core page is rendered, and since it's TypeScript, it can of course reference any other TypeScript modules, which means your entire SPA can be written in TypeScript and executed on the server.
<div id="my-spa" asp-prerender-module="ClientApp/dist/main-server"></div>
Webpack is a broad and powerful tool and can do far more than just invoke the TypeScript compiler. To learn more, see the [webpack website](https://webpack.github.io/).
@@ -276,30 +284,7 @@ You can now run your React code on the client by adding the following to one of
<div id="my-spa"></div>
<script src="/dist/main.js"></script>
#### Running React code on the server
Now you have React code being built using Webpack, you can enable server-side prerendering using the `aspnet-prerender-*` tag helpers as follows:
<div id="my-spa" asp-prerender-module="ClientApp/boot-server"
asp-prerender-webpack-config="webpack.config.js"></div>
... along with the following boot module at `ClientApp/boot-server.jsx`:
```javascript
import * as React from 'react';
import { renderToString } from 'react-dom/server';
import { HelloMessage } from './react-app';
export default function (params) {
return new Promise((resolve, reject) => {
resolve({
html: renderToString(<HelloMessage message="from the server" />)
});
});
}
```
Now you should find that your React app is rendered in the page even before any JavaScript is loaded in the browser (or even if JavaScript is disabled in the browser).
If you want to enable server-side prerendering too, follow the same process as described under [server-side prerendering](#server-side-prerendering).
#### Realistic React apps and Redux
@@ -406,7 +391,7 @@ To make this work, the template has Webpack configured to inject the contents of
```javascript
// This goes into webpack.config.js, in the module loaders array:
{ test: /\.css/, include: /ClientApp/, loader: 'raw' }
{ test: /\.css/, include: /ClientApp/, loader: 'raw-loader' }
```
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:
@@ -418,10 +403,10 @@ 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' }
{ test: /\.less/, include: /ClientApp/, loader: 'raw-loader!less-loader' }
```
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:
Notice how this chains together with `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({
@@ -462,7 +447,7 @@ npm install --save less-loader less
Finally, tell Webpack to use this whenever it encounters a `.less` file. In `webpack.config.js`, add to the `loaders` array:
```
{ test: /\.less/, loader: 'style!css!less' }
{ test: /\.less/, loader: 'style-loader!css-loader!less-loader' }
```
This means that when you `import` or `require` a `.less` file, it should pass it first to the LESS compiler to produce CSS, then the output goes to the CSS and Style loaders that know how to attach it dynamically to the page at runtime.
@@ -504,7 +489,7 @@ var extractStyles = new (require('extract-text-webpack-plugin'))('mystyles.css')
This creates a plugin instance that will output text to a file called `mystyles.css`. You can now compile `.less` files and emit the resulting CSS text into that file. To do so, add the following to the `loaders` array in your Webpack configuration:
```javascript
{ test: /\.less$/, loader: extractStyles.extract('css!less') }
{ test: /\.less$/, loader: extractStyles.extract('css-loader!less-loader') }
```
This tells Webpack that, whenever it finds a `.less` file, it should use the LESS loader to produce CSS, and then feed that CSS into the `extractStyles` object which you've already configured to write a file on disk called `mystyles.css`. Finally, for this to actually work, you need to include `extractStyles` in the list of active plugins. Just add that object to the `plugins` array in your Webpack config, e.g.:
@@ -533,7 +518,7 @@ if (env.IsDevelopment()) {
app.UseWebpackDevMiddleware();
}
// You call to app.UseStaticFiles(); should be here
// Your call to app.UseStaticFiles(); should be here
```
Also check your webpack configuration at `webpack.config.js`. Since `UseWebpackDevMiddleware` needs to know which incoming requests to intercept, make sure you've specified a `publicPath` value on your `output`, for example:
@@ -604,6 +589,14 @@ Now when you load your application in a browser, you should see a message like t
If you edit any of your source files that get built by webpack, the result will automatically be pushed into the browser. As for what the browser does with these updates - that's a matter of how you configure it - see below.
**Note for TypeScript + Visual Studio users**
If you want HMR to work correctly with TypeScript, and you use Visual Studio on Windows as an IDE (but not VS Code), then you will need to make a further configuration change. In your `.csproj` file, in one of the `<PropertyGroup>` elements, add this:
<TypeScriptCompileBlocked>true</TypeScriptCompileBlocked>
This is necessary because otherwise, Visual Studio will try to auto-compile TypeScript files as you save changes to them. That default auto-compilation behavior is unhelpful in projects where you have a proper build system (e.g., Webpack), because VS doesn't know about your build system and would emit `.js` files in the wrong locations, which would in turn cause problems with your real build or deployment mechanisms.
#### Enabling hot replacement for React components
Webpack has built-in support for updating React components in place. To enable this, amend your `UseWebpackDevMiddleware` call further as follows:
@@ -664,3 +657,141 @@ Then, since `MapSpaFallbackRoute` is last, any other requests **that don't appea
Any requests that do appear to be for static files (i.e., those that end with filename extensions), will *not* be handled by `MapSpaFallbackRoute`, and so will end up as 404s.
This is not a perfect solution to the problem of identifying 404s, because for example `MapSpaFallbackRoute` will not match requests for `/users/albert.einstein`, because it appears to contain a filename extension (`.einstein`). If you need your SPA to handle routes like that, then don't use `MapSpaFallbackRoute` - just use a regular MVC catch-all route. But then beware that requests for unknown static files will result in your client-side app being rendered.
## Debugging your projects
How to attach and use a debugger depends on what code you want to debug. For details, see:
* [How to debug your C# code that runs on the server](#debugging-your-c-code-that-runs-on-the-server)
* How to debug your JavaScript/TypeScript code:
* ... [when it's running in a browser](#debugging-your-javascripttypescript-code-when-its-running-in-a-browser)
* ... [when it's running on the server](#debugging-your-javascripttypescript-code-when-it-runs-on-the-server) (i.e., via `asp-prerender` or NodeSevices)
### Debugging your C# code that runs on the server
You can use any .NET debugger, for example Visual Studio's C# debugger or [Visual Studio Code's C# debugger](https://code.visualstudio.com/Docs/editor/debugging).
### Debugging your JavaScript/TypeScript code when it's running in a browser
**The absolute most reliable way of debugging your client-side code is to use your browser's built-in debugger.** This is much easier to make work than debugging via an IDE, plus it offers much richer insight into what's going on than your IDE will do (for example, you'll be able to inspect the DOM and capture performance profiles as well as just set breakpoints and step through code).
If you're unfamiliar with your browser's debugging tools, then take the time to get familiar with them. You will become more productive.
#### Using your browser's built-in debugging tools
##### Using Chrome's developer tools for debugging
In Chrome, with your application running in the browser, [open the developer tools](https://developer.chrome.com/devtools#access). You can now find your code:
* In the developer tools *Sources* tab, expand folders in the hierarchy pane on the left to find the file you want
* Or, press `ctrl`+`o` (on Windows) or `cmd`+`o` on Mac, then start to type name name of the file you want to open (e.g., `counter.component.ts`)
With source maps enabled (which is the case in the project templates in this repo), you'll be able to see your original TypeScript source code, set breakpoints on it, etc.
##### Using Internet Explorer/Edge's developer tools (F12) for debugging
In Internet Explorer or Edge, with your application running in the browser, open the F12 developer tools by pressing `F12`. You can now find your code:
* In the F12 tools *Debugger* tab, expand folders in the hierarchy pane on the left to find the file you want
* Or, press `ctrl`+`o`, then start to type name name of the file you want to open (e.g., `counter.component.ts`)
With source maps enabled (which is the case in the project templates in this repo), you'll be able to see your original TypeScript source code, set breakpoints on it, etc.
##### Using Firefox's developer tools for debugging
In Firefox, with your application running in the browser, open the developer tools by pressing `F12`. You can now find your code:
* In the developer tools *Debugger* tab, expand folders in the hierarchy pane titled *Sources* towards the bottom to find the file you want
* Or, press `ctrl`+`o` (on Windows) or `cmd`+`o` on Mac, then start to type name name of the file you want to open (e.g., `counter.component.ts`)
With source maps enabled (which is the case in the project templates in this repo), you'll be able to see your original TypeScript source code, set breakpoints on it, etc.
##### How browser-based debugging interacts with Hot Module Replacement (HMR)
If you're using HMR, then each time you modify a file, the Webpack dev middleware restarts your client-side application, adding a new version of each affected module, without reloading the page. This can be confusing during debugging, because any breakpoints set on the old version of the code will still be there, but they will no longer get hit, because the old version of the module is no longer in use.
You have two options to get breakpoints that will be hit as expected:
* **Reload the page** (e.g., by pressing `F5`). Then your existing breakpoints will be applied to the new version of the module. This is obviously the easiest solution.
* Or, if you don't want to reload the page, you can **set new breakpoints on the new version of the module**. To do this, look in your browser's debug tools' list of source files, and identify the newly-injected copy of the module you want to debug. It will typically have a suffix on its URL such as `?4a2c`, and may appear in a new top-level hierarchy entry called `webpack://`. Set a breakpoint in the newly-injected module, and it will be hit as expected as your application runs.
#### Using Visual Studio Code's "Debugger for Chrome" extension
If you're using Visual Studio Code and Chrome, you can set breakpoints directly on your TypeScript source code in the IDE. To do this:
1. Install VS Code's [*Debugger for Chrome* extension](https://marketplace.visualstudio.com/items?itemName=msjsdiag.debugger-for-chrome)
2. Ensure your application server has started and can be reached with a browser (for example, run `dotnet watch run`)
3. In VS Code, open its *Debug* view (on Windows/Linux, press `ctrl`+`shift`+`d`; on Mac, press `cmd`+`shift`+`d`).
4. Press the cog icon and when prompted to *Select environment*, choose `Chrome`. VS Code will create a `launch.json` file for you. This describes how the debugger and browser should be launched.
5. Edit your new `.vscode/launch.json` file to specify the correct `url` and `webRoot` for your application. If you're using the project templates in this repo, then the values you probably want are:
* For `url`, put `"http://localhost:5000"` (but of course, change this if you're using a different port)
* For `port`, put `5000` (or your custom port number if applicable)
* For `workspace` in **both** configurations, put `"${workspaceRoot}/wwwroot"`
* This tells the debugger how URLs within your application correspond to files in your VS Code workspace. By default, ASP.NET Core projects treat `wwwroot` as the root directory for publicly-served files, so `http://localhost:5000/dist/myfile.js` corresponds to `<yourprojectroot>/wwwroot/dist/myfile.js`. VS Code doesn't know about `wwwroot` unless you tell it.
* **Important:** If your VS Code window's workspace root is not the same as your ASP.NET Core project root (for example, if VS Code is opened at a higher-level directory to show both your ASP.NET Core project plus other peer-level directories), then you will need to amend `workspace` correspondingly (e.g., to `"${workspaceRoot}/SomeDir/MyAspNetProject/wwwroot"`).
6. Start the debugger:
* While still on the *Debug* view, from the dropdown near the top-left, choose "*Launch Chrome against localhost, with sourcemaps*".
* Press the *Play* icon. Your application will launch in Chrome.
* If it does nothing for a while, then eventually gives the error *Cannot connect to runtime process*, that's because you already have an instance of Chrome running. Close it first, then try again.
7. Finally, you can now set and hit breakpoints in your TypeScript code in VS Code.
For more information about VS Code's built-in debugging facilities, [see its documentation](https://code.visualstudio.com/Docs/editor/debugging).
Caveats:
* The debugging interface between VS Code and Chrome occasionally has issues. If you're unable to set or hit breakpoints, or if you try to set a breakpoint but it appears in the wrong place, you may need to stop and restart the debugger (and often, the whole Chrome process).
* If you're using Hot Module Replacement (HMR), then whenever you edit a file, the breakpoints in it will no longer hit. This is because HMR loads a new version of the module into the browser, so the old code no longer runs. To fix this, you must:
* Reload the page in Chrome (e.g., by pressing `F5`)
* **Then** (and only then), remove and re-add the breakpoint in VS Code. It will now be attached to the current version of your module. Alternatively, stop and restart debugging altogether.
* If you prefer, you can use "*Attach to Chrome, with sourcemaps*" instead of launching a new Chrome instance, but this is a bit trickier: you must first start Chrome using the command-line option `--remote-debugging-port=9222`, and you must ensure there are no other tabs opened (otherwise, it might try to connect to the wrong one).
#### Using Visual Studio's built-in debugger for Internet Explorer
If you're using Visual Studio on Windows, and are running your app in Internet Explorer 11 (not Edge!), then you can use VS's built-in debugger rather than Interner Explorer's F12 tools if you prefer. To do this:
1. In Internet Explorer, [enable script debugging](https://msdn.microsoft.com/en-us/library/ms241741\(v=vs.100\).aspx)
2. In Visual Studio, [set the default "*Browse with*" option](http://stackoverflow.com/a/31959053) to Internet Explorer
3. In Visual Studio, press F5 to launch your application with the debugger in Internet Explorer.
* When the page has loaded in the browser, you'll be able to set and hit breakpoints in your TypeScript source files in Visual Studio.
Caveats:
* If you're using Hot Module Replacement, you'll need to stop and restart the debugger any time you change a source file. VS's IE debugger does not recognise that source files might change while the debugging session is in progress.
* Realistically, you are not going to be as productive using this approach to debugging as you would be if you used your browser's built-in debugging tools. The browser's built-in debugging tools are far more effective: they are always available (you don't have to have launched your application in a special way), they better handle HMR, and they don't make your application very slow to launch.
## Debugging your JavaScript/TypeScript code when it runs on the server
When you're using NodeServices or the server-side prerendering feature included in the project templates in this repo, your JavaScript/TypeScript code will execute on the server in a background instance of Node.js. You can enable debugging on that Node.js instance. Here's how to do it.
First, in your `Startup.cs` file, in the `ConfigureServices` method, add the following:
```
services.AddNodeServices(options => {
options.LaunchWithDebugging = true;
options.DebuggingPort = 5858;
});
```
Now, run your application from that command line (e.g., `dotnet run`). Then in a browser visit one of your pages that causes server-side JS to execute.
In the console, you should see all the normal trace messages appear, plus among them will be:
-----
*** Node.js debugging is enabled ***
Debugger listening on port 5858
To debug, run:
node-inspector
If you haven't yet installed node-inspector, you can do so as follows:
npm install -g node-inspector
-----
In some other command line window, follow those instructions (i.e., install `node-inspector` as it describes, then run `node-inspector`). Then you can open a browser at `http://127.0.0.1:8080/?port=5858` and you'll see the debugger UI.
By expanding the `webpack://` entry in the sidebar, you'll be able to find your original TypeScript code (it's using source maps), and then set breakpoints in it. When you re-run your app in another browser window, your breakpoints will be hit, then you can debug the server-side execution just like you'd debug client-side execution. It looks like this:
![screen shot 2016-07-26 at 18 56 12](https://cloud.githubusercontent.com/assets/1101362/17149317/a6f7d00c-5362-11e6-969c-4c3a9bbc33f7.png)
(Note: although this looks like Chrome's native debugger for client-side code, it is actually a JavaScript-powered debugger UI that's connected to the server-side runtime)

View File

@@ -7,10 +7,22 @@ using Microsoft.AspNetCore.SpaServices;
namespace Microsoft.AspNetCore.Builder
{
/// <summary>
/// Extension methods useful for configuring routing in a single-page application (SPA).
/// </summary>
public static class SpaRouteExtensions
{
private const string ClientRouteTokenName = "clientRoute";
/// <summary>
/// Configures a route that is automatically bypassed if the requested URL appears to be for a static file
/// (e.g., if it has a filename extension).
/// </summary>
/// <param name="routeBuilder">The <see cref="IRouteBuilder"/>.</param>
/// <param name="name">The route name.</param>
/// <param name="defaults">Default route parameters.</param>
/// <param name="constraints">Route constraints.</param>
/// <param name="dataTokens">Route data tokens.</param>
public static void MapSpaFallbackRoute(
this IRouteBuilder routeBuilder,
string name,
@@ -27,6 +39,16 @@ namespace Microsoft.AspNetCore.Builder
dataTokens);
}
/// <summary>
/// Configures a route that is automatically bypassed if the requested URL appears to be for a static file
/// (e.g., if it has a filename extension).
/// </summary>
/// <param name="routeBuilder">The <see cref="IRouteBuilder"/>.</param>
/// <param name="name">The route name.</param>
/// <param name="templatePrefix">The template prefix.</param>
/// <param name="defaults">Default route parameters.</param>
/// <param name="constraints">Route constraints.</param>
/// <param name="dataTokens">Route data tokens.</param>
public static void MapSpaFallbackRoute(
this IRouteBuilder routeBuilder,
string name,

View File

@@ -0,0 +1,115 @@
/// <reference path="../npm/aspnet-prerendering/src/PrerenderingInterfaces.d.ts" />
import * as url from 'url';
import * as path from 'path';
import * as fs from 'fs';
declare var __non_webpack_require__;
// Separate declaration and export just to add type checking on function signature
export const renderToString: RenderToStringFunc = renderToStringImpl;
// This function is invoked by .NET code (via NodeServices). Its job is to hand off execution to the application's
// prerendering boot function. It can operate in two modes:
// [1] Legacy mode
// This is for backward compatibility with projects created with templates older than the generator version 0.6.0.
// In this mode, we don't really do anything here - we just load the 'aspnet-prerendering' NPM module (which must
// exist in node_modules, and must be v1.x (not v2+)), and pass through all the parameters to it. Code in
// 'aspnet-prerendering' v1.x will locate the boot function and invoke it.
// The drawback to this mode is that, for it to work, you have to deploy node_modules to production.
// [2] Current mode
// This is for projects created with the Yeoman generator 0.6.0+ (or projects manually updated). In this mode,
// we don't invoke 'require' at runtime at all. All our dependencies are bundled into the NuGet package, so you
// don't have to deploy node_modules to production.
// To determine whether we're in mode [1] or [2], the code locates your prerendering boot function, and checks whether
// a certain flag is attached to the function instance.
function renderToStringImpl(callback: RenderToStringCallback, applicationBasePath: string, bootModule: BootModuleInfo, absoluteRequestUrl: string, requestPathAndQuery: string, customDataParameter: any, overrideTimeoutMilliseconds: number) {
try {
const forceLegacy = isLegacyAspNetPrerendering();
const renderToStringFunc = !forceLegacy && findRenderToStringFunc(applicationBasePath, bootModule);
const isNotLegacyMode = renderToStringFunc && renderToStringFunc['isServerRenderer'];
if (isNotLegacyMode) {
// Current (non-legacy) mode - we invoke the exported function directly (instead of going through aspnet-prerendering)
// It's type-safe to just apply the incoming args to this function, because we already type-checked that it's a RenderToStringFunc,
// just like renderToStringImpl itself is.
renderToStringFunc.apply(null, arguments);
} else {
// Legacy mode - just hand off execution to 'aspnet-prerendering' v1.x, which must exist in node_modules at runtime
const aspNetPrerenderingV1RenderToString = require('aspnet-prerendering').renderToString;
if (aspNetPrerenderingV1RenderToString) {
aspNetPrerenderingV1RenderToString(callback, applicationBasePath, bootModule, absoluteRequestUrl, requestPathAndQuery, customDataParameter, overrideTimeoutMilliseconds);
} else {
callback('If you use aspnet-prerendering >= 2.0.0, you must update your server-side boot module to call createServerRenderer. '
+ 'Either update your boot module code, or revert to aspnet-prerendering version 1.x');
}
}
} catch (ex) {
// Make sure loading errors are reported back to the .NET part of the app
callback(
'Prerendering failed because of error: '
+ ex.stack
+ '\nCurrent directory is: '
+ process.cwd()
);
}
};
function findBootModule(applicationBasePath: string, bootModule: BootModuleInfo): any {
const bootModuleNameFullPath = path.resolve(applicationBasePath, bootModule.moduleName);
if (bootModule.webpackConfig) {
// If you're using asp-prerender-webpack-config, you're definitely in legacy mode
return null;
} else {
return __non_webpack_require__(bootModuleNameFullPath);
}
}
function findRenderToStringFunc(applicationBasePath: string, bootModule: BootModuleInfo): RenderToStringFunc {
// First try to load the module
const foundBootModule = findBootModule(applicationBasePath, bootModule);
if (foundBootModule === null) {
return null; // Must be legacy mode
}
// Now try to pick out the function they want us to invoke
let renderToStringFunc: RenderToStringFunc;
if (bootModule.exportName) {
// Explicitly-named export
renderToStringFunc = foundBootModule[bootModule.exportName];
} else if (typeof foundBootModule !== 'function') {
// TypeScript-style default export
renderToStringFunc = foundBootModule.default;
} else {
// Native default export
renderToStringFunc = foundBootModule;
}
// Validate the result
if (typeof renderToStringFunc !== 'function') {
if (bootModule.exportName) {
throw new Error(`The module at ${ bootModule.moduleName } has no function export named ${ bootModule.exportName }.`);
} else {
throw new Error(`The module at ${ bootModule.moduleName } does not export a default function, and you have not specified which export to invoke.`);
}
}
return renderToStringFunc;
}
function isLegacyAspNetPrerendering() {
const version = getAspNetPrerenderingPackageVersion();
return version && /^1\./.test(version);
}
function getAspNetPrerenderingPackageVersion() {
try {
const packageEntryPoint = __non_webpack_require__.resolve('aspnet-prerendering');
const packageDir = path.dirname(packageEntryPoint);
const packageJsonPath = path.join(packageDir, 'package.json');
const packageJson = __non_webpack_require__(packageJsonPath);
return packageJson.version.toString();
} catch(ex) {
// Implies aspnet-prerendering isn't in node_modules at all (or node_modules itself doesn't exist,
// which will be the case in production based on latest templates).
return null;
}
}

View File

@@ -0,0 +1,20 @@
// Pass through the invocation to the 'aspnet-webpack' package, verifying that it can be loaded
export function createWebpackDevServer(callback) {
let aspNetWebpack;
try {
aspNetWebpack = require('aspnet-webpack');
} catch (ex) {
// 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 aspNetWebpack.createWebpackDevServer.apply(this, arguments);
}

View File

@@ -0,0 +1,12 @@
{
"compilerOptions": {
"target": "es3",
"module": "commonjs",
"moduleResolution": "node",
"types": ["node"],
"lib": ["es2015"]
},
"exclude": [
"node_modules"
]
}

View File

@@ -8,16 +8,29 @@ using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.PlatformAbstractions;
using Newtonsoft.Json;
// Putting in this namespace so it's always available whenever MapRoute is
namespace Microsoft.AspNetCore.Builder
{
/// <summary>
/// Extension methods that can be used to enable Webpack dev middleware support.
/// </summary>
public static class WebpackDevMiddleware
{
private const string WebpackDevMiddlewareScheme = "http";
private const string WebpackHotMiddlewareEndpoint = "/__webpack_hmr";
private const string DefaultConfigFile = "webpack.config.js";
/// <summary>
/// Enables Webpack dev middleware support. This hosts an instance of the Webpack compiler in memory
/// in your application so that you can always serve up-to-date Webpack-built resources without having
/// to run the compiler manually. Since the Webpack compiler instance is retained in memory, incremental
/// compilation is vastly faster that re-running the compiler from scratch.
///
/// Incoming requests that match Webpack-built files will be handled by returning the Webpack compiler
/// output directly, regardless of files on disk. If compilation is in progress when the request arrives,
/// the response will pause until updated compiler output is ready.
/// </summary>
/// <param name="appBuilder">The <see cref="IApplicationBuilder"/>.</param>
/// <param name="options">Options for configuring the Webpack compiler instance.</param>
public static void UseWebpackDevMiddleware(
this IApplicationBuilder appBuilder,
WebpackDevMiddlewareOptions options = null)
@@ -47,6 +60,14 @@ namespace Microsoft.AspNetCore.Builder
nodeServicesOptions.ProjectPath = options.ProjectPath;
}
if (options.EnvironmentVariables != null)
{
foreach (var kvp in options.EnvironmentVariables)
{
nodeServicesOptions.EnvironmentVariables[kvp.Key] = kvp.Value;
}
}
var nodeServices = NodeServicesFactory.CreateNodeServices(nodeServicesOptions);
// Get a filename matching the middleware Node script

View File

@@ -1,11 +1,43 @@
using System.Collections.Generic;
namespace Microsoft.AspNetCore.SpaServices.Webpack
{
/// <summary>
/// Options for configuring a Webpack dev middleware compiler.
/// </summary>
public class WebpackDevMiddlewareOptions
{
/// <summary>
/// If true, hot module replacement (HMR) will be enabled. This automatically updates Webpack-built
/// resources (such as JavaScript, CSS, or images) in your web browser whenever source files are changed.
/// </summary>
public bool HotModuleReplacement { get; set; }
/// <summary>
/// Overrides the internal port number that client-side HMR code will connect to.
/// </summary>
public int HotModuleReplacementServerPort { get; set; }
/// <summary>
/// If true, enables React-specific extensions to Webpack's hot module replacement (HMR) feature.
/// This enables React components to be updated without losing their in-memory state.
/// </summary>
public bool ReactHotModuleReplacement { get; set; }
/// <summary>
/// Specifies the Webpack configuration file to be used. If not set, defaults to 'webpack.config.js'.
/// </summary>
public string ConfigFile { get; set; }
/// <summary>
/// The root path of your project. Webpack runs in this context.
/// </summary>
public string ProjectPath { get; set; }
/// <summary>
/// Specifies additional environment variables to be passed to the Node instance hosting
/// the webpack compiler.
/// </summary>
public IDictionary<string, string> EnvironmentVariables { get; set; }
}
}

View File

@@ -1,4 +1,6 @@
/typings/
/node_modules/
/*.js
/*.d.ts
/**/*.js
/**/.d.ts
!/src/**/*.d.ts

View File

@@ -1,6 +1,6 @@
{
"name": "aspnet-prerendering",
"version": "1.0.7",
"version": "2.0.0",
"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",
"scripts": {
@@ -17,8 +17,7 @@
"url": "https://github.com/aspnet/JavaScriptServices.git"
},
"dependencies": {
"domain-task": "^2.0.1",
"es6-promise": "^3.1.2"
"domain-task": "^2.0.1"
},
"devDependencies": {
"@types/node": "^6.0.42",

View File

@@ -1,4 +1,4 @@
import 'es6-promise';
/// <reference path="./PrerenderingInterfaces.d.ts" />
import * as url from 'url';
import * as path from 'path';
import * as domain from 'domain';
@@ -7,41 +7,8 @@ import { baseUrl } from 'domain-task/fetch';
const defaultTimeoutMilliseconds = 30 * 1000;
export interface RenderToStringCallback {
(error: any, result: RenderToStringResult): void;
}
export interface RenderToStringResult {
html: string;
globals: { [key: string]: any };
}
export interface BootFunc {
(params: BootFuncParams): Promise<RenderToStringResult>;
}
export interface BootFuncParams {
location: url.Url; // e.g., Location object containing information '/some/path'
origin: string; // e.g., 'https://example.com:1234'
url: string; // e.g., '/some/path'
absoluteUrl: string; // e.g., 'https://example.com:1234/some/path'
domainTasks: Promise<any>;
data: any; // any custom object passed through from .NET
}
export interface BootModuleInfo {
moduleName: string;
exportName?: string;
webpackConfig?: string;
}
export function renderToString(callback: RenderToStringCallback, applicationBasePath: string, bootModule: BootModuleInfo, absoluteRequestUrl: string, requestPathAndQuery: string, customDataParameter: any, overrideTimeoutMilliseconds: number) {
findBootFunc(applicationBasePath, bootModule, (findBootFuncError, bootFunc) => {
if (findBootFuncError) {
callback(findBootFuncError, null);
return;
}
export function createServerRenderer(bootFunc: BootFunc): RenderToStringFunc {
const resultFunc = (callback: RenderToStringCallback, applicationBasePath: string, bootModule: BootModuleInfo, absoluteRequestUrl: string, requestPathAndQuery: string, customDataParameter: any, overrideTimeoutMilliseconds: number) => {
// Prepare a promise that will represent the completion of all domain tasks in this execution context.
// The boot code will wait for this before performing its final render.
let domainTaskCompletionPromiseResolve;
@@ -76,7 +43,7 @@ export function renderToString(callback: RenderToStringCallback, applicationBase
}
const timeoutMilliseconds = overrideTimeoutMilliseconds || defaultTimeoutMilliseconds; // e.g., pass -1 to override as 'never time out'
const bootFuncPromiseWithTimeout = timeoutMilliseconds > 0
? wrapWithTimeout(bootFuncPromise, timeoutMilliseconds,
? wrapWithTimeout(bootFuncPromise, timeoutMilliseconds,
`Prerendering timed out after ${timeoutMilliseconds}ms because the boot function in '${bootModule.moduleName}' `
+ 'returned a promise that did not resolve or reject. Make sure that your boot function always resolves or '
+ 'rejects its promise. You can change the timeout value using the \'asp-prerender-timeout\' tag helper.')
@@ -97,7 +64,14 @@ export function renderToString(callback: RenderToStringCallback, applicationBase
domainTaskCompletionPromiseResolve();
}
});
});
};
// Indicate to the prerendering code bundled into Microsoft.AspNetCore.SpaServices that this is a serverside rendering
// function, so it can be invoked directly. This flag exists only so that, in its absence, we can run some different
// backward-compatibility logic.
resultFunc['isServerRenderer'] = true;
return resultFunc;
}
function wrapWithTimeout<T>(promise: Promise<T>, timeoutMilliseconds: number, timeoutRejectionValue: any): Promise<T> {
@@ -119,59 +93,6 @@ function wrapWithTimeout<T>(promise: Promise<T>, timeoutMilliseconds: number, ti
});
}
function findBootModule<T>(applicationBasePath: string, bootModule: BootModuleInfo, callback: (error: any, foundModule: T) => void) {
const bootModuleNameFullPath = path.resolve(applicationBasePath, bootModule.moduleName);
if (bootModule.webpackConfig) {
const webpackConfigFullPath = path.resolve(applicationBasePath, bootModule.webpackConfig);
let aspNetWebpackModule: any;
try {
aspNetWebpackModule = require('aspnet-webpack');
} 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. Error encountered while loading \'aspnet-webpack\': ' + ex.stack, null);
return;
}
aspNetWebpackModule.loadViaWebpack(webpackConfigFullPath, bootModuleNameFullPath, callback);
} else {
callback(null, require(bootModuleNameFullPath));
}
}
function findBootFunc(applicationBasePath: string, bootModule: BootModuleInfo, callback: (error: any, bootFunc: BootFunc) => void) {
// First try to load the module (possibly via Webpack)
findBootModule<any>(applicationBasePath, bootModule, (findBootModuleError, foundBootModule) => {
if (findBootModuleError) {
callback(findBootModuleError, null);
return;
}
// Now try to pick out the function they want us to invoke
let bootFunc: BootFunc;
if (bootModule.exportName) {
// Explicitly-named export
bootFunc = foundBootModule[bootModule.exportName];
} else if (typeof foundBootModule !== 'function') {
// TypeScript-style default export
bootFunc = foundBootModule.default;
} else {
// Native default export
bootFunc = foundBootModule;
}
// Validate the result
if (typeof bootFunc !== 'function') {
if (bootModule.exportName) {
callback(`The module at ${ bootModule.moduleName } has no function export named ${ bootModule.exportName }.`, null);
} else {
callback(`The module at ${ bootModule.moduleName } does not export a default function, and you have not specified which export to invoke.`, null);
}
} else {
callback(null, bootFunc);
}
});
}
function bindPromiseContinuationsToDomain(promise: Promise<any>, domainInstance: domain.Domain) {
const originalThen = promise.then;
promise.then = (function then(resolve, reject) {

View File

@@ -0,0 +1,35 @@
interface RenderToStringFunc {
(callback: RenderToStringCallback, applicationBasePath: string, bootModule: BootModuleInfo, absoluteRequestUrl: string, requestPathAndQuery: string, customDataParameter: any, overrideTimeoutMilliseconds: number): void;
}
interface RenderToStringCallback {
(error: any, result?: RenderToStringResult): void;
}
interface RenderToStringResult {
html: string;
globals?: { [key: string]: any };
}
interface RedirectResult {
redirectUrl: string;
}
interface BootFunc {
(params: BootFuncParams): Promise<RenderToStringResult>;
}
interface BootFuncParams {
location: any; // e.g., Location object containing information '/some/path'
origin: string; // e.g., 'https://example.com:1234'
url: string; // e.g., '/some/path'
absoluteUrl: string; // e.g., 'https://example.com:1234/some/path'
domainTasks: Promise<any>;
data: any; // any custom object passed through from .NET
}
interface BootModuleInfo {
moduleName: string;
exportName?: string;
webpackConfig?: string;
}

View File

@@ -1 +1,5 @@
/// <reference path="./PrerenderingInterfaces.d.ts" />
export * from './Prerendering';
export type RenderResult = RenderToStringResult | RedirectResult;

View File

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

View File

@@ -1,7 +1,11 @@
import * as webpack from 'webpack';
export function addReactHotModuleReplacementBabelTransform(webpackConfig: webpack.Configuration) {
webpackConfig.module.loaders.forEach(loaderConfig => {
const moduleRules: webpack.Loader[] =
(webpackConfig.module as any).rules // Webpack < 2.1.0 beta 23
|| webpackConfig.module.loaders; // Webpack >= 2.1.0 beta 23
moduleRules.forEach(loaderConfig => {
if (loaderConfig.loader && loaderConfig.loader.match(/\bbabel-loader\b/)) {
// Ensure the babel-loader options includes a 'query'
const query = loaderConfig.query = loaderConfig.query || {};

View File

@@ -1,10 +1,10 @@
{
"name": "aspnet-webpack",
"version": "1.0.21",
"version": "1.0.24",
"description": "Helpers for using Webpack in ASP.NET Core projects. Works in conjunction with the Microsoft.AspNetCore.SpaServices NuGet package.",
"main": "index.js",
"scripts": {
"prepublish": "rimraf *.d.ts && tsd update && tsc && echo 'Finished building NPM package \"aspnet-webpack\"'",
"prepublish": "rimraf *.d.ts && tsc && echo 'Finished building NPM package \"aspnet-webpack\"'",
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "Microsoft",
@@ -21,7 +21,7 @@
"es6-promise": "^3.1.2",
"memory-fs": "^0.3.0",
"require-from-string": "^1.1.0",
"webpack-dev-middleware": "^1.6.1",
"webpack-dev-middleware": "^1.8.4",
"webpack-node-externals": "^1.4.3"
},
"devDependencies": {
@@ -33,6 +33,6 @@
"webpack": "^1.13.2"
},
"peerDependencies": {
"webpack": "^1.13.2"
"webpack": "^1.13.2 || ^2.1.0-beta"
}
}

View File

@@ -93,7 +93,6 @@ function attachWebpackDevMiddleware(app: any, webpackConfig: webpack.Configurati
// Attach Webpack dev middleware and optional 'hot' middleware
const compiler = webpack(webpackConfig);
const originalFileSystem = compiler.outputFileSystem;
app.use(require('webpack-dev-middleware')(compiler, {
noInfo: true,
publicPath: webpackConfig.output.publicPath
@@ -108,7 +107,7 @@ function attachWebpackDevMiddleware(app: any, webpackConfig: webpack.Configurati
// file on disk wouldn't match the file served to the browser, and the source map line numbers wouldn't
// match up. Breakpoints would either not be hit, or would hit the wrong lines.
(compiler as any).plugin('done', stats => {
copyRecursiveSync(compiler.outputFileSystem, originalFileSystem, '/', [/\.hot-update\.(js|json)$/]);
copyRecursiveToRealFsSync(compiler.outputFileSystem, '/', [/\.hot-update\.(js|json)$/]);
});
if (enableHotModuleReplacement) {
@@ -122,7 +121,7 @@ function attachWebpackDevMiddleware(app: any, webpackConfig: webpack.Configurati
}
}
function copyRecursiveSync(from: typeof fs, to: typeof fs, rootDir: string, exclude: RegExp[]) {
function copyRecursiveToRealFsSync(from: typeof fs, rootDir: string, exclude: RegExp[]) {
from.readdirSync(rootDir).forEach(filename => {
const fullPath = pathJoinSafe(rootDir, filename);
const shouldExclude = exclude.filter(re => re.test(fullPath)).length > 0;
@@ -130,9 +129,12 @@ function copyRecursiveSync(from: typeof fs, to: typeof fs, rootDir: string, excl
const fileStat = from.statSync(fullPath);
if (fileStat.isFile()) {
const fileBuf = from.readFileSync(fullPath);
to.writeFile(fullPath, fileBuf);
fs.writeFileSync(fullPath, fileBuf);
} else if (fileStat.isDirectory()) {
copyRecursiveSync(from, to, fullPath, exclude);
if (!fs.existsSync(fullPath)) {
fs.mkdirSync(fullPath);
}
copyRecursiveToRealFsSync(from, fullPath, exclude);
}
}
});

View File

@@ -2,7 +2,7 @@ import * as url from 'url';
import * as domain from 'domain';
import * as domainContext from 'domain-context';
const isomorphicFetch = require('isomorphic-fetch');
const isBrowser: boolean = (new Function('try { return this === window; } catch (e) { return false; }'))();
const isNode = typeof process === 'object' && process.versions && !!process.versions.node;
// Not using a symbol, because this may need to run in a version of Node.js that doesn't support them
const domainTaskStateKey = '__DOMAIN_TASK_INTERNAL_FETCH_BASEURL__DO_NOT_REFERENCE_THIS__';
@@ -17,7 +17,7 @@ function issueRequest(baseUrl: string, req: string | Request, init?: RequestInit
} else {
req = url.resolve(baseUrl, req as string);
}
} else if (!isBrowser) {
} else if (isNode) {
// TODO: Consider only throwing if it's a relative URL, since absolute ones would work fine
throw new Error(`
When running outside the browser (e.g., in Node.js), you must specify a base URL

View File

@@ -0,0 +1,18 @@
{
"name": "spaservices",
"version": "1.0.0",
"description": "This is not really an NPM package and will not be published. This file exists only to reference compilation tools.",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "./node_modules/.bin/webpack"
},
"author": "Microsoft",
"license": "Apache-2.0",
"devDependencies": {
"@types/node": "^6.0.42",
"ts-loader": "^0.8.2",
"typescript": "^2.0.0",
"webpack": "^1.13.1"
}
}

View File

@@ -1,30 +1,37 @@
{
"version": "1.0.0-*",
"description": "Helpers for building single-page applications on ASP.NET MVC Core",
"compilationOptions": {
"keyFile": "../../tools/Key.snk"
"version": "1.0.0-*",
"packOptions": {
"repository": {
"type": "git",
"url": "git://github.com/aspnet/javascriptservices"
},
"tags": [
"aspnetcore",
"aspnetcoremvc",
"nodeservices"
]
},
"buildOptions": {
"warningsAsErrors": true,
"keyFile": "../../tools/Key.snk",
"embed": [
"Content/**/*"
],
"xmlDoc": true
},
"authors": [
"Microsoft"
],
"dependencies": {
"Microsoft.AspNetCore.Mvc": "1.0.1",
"Microsoft.AspNetCore.NodeServices": "1.0.0-*"
},
"frameworks": {
"net451": {
},
"netstandard1.6": {
"imports": [
"dotnet5.6",
"dnxcore50",
"portable-net45+win8"
]
}
"net451": {},
"netstandard1.6": {}
},
"buildOptions": {
"embed": [
"Content/**/*"
"scripts": {
"prepublish": [
"npm install",
"node node_modules/webpack/bin/webpack.js"
]
}
}

View File

@@ -0,0 +1,26 @@
module.exports = {
target: 'node',
externals: [
// These NPM modules are loaded dynamically at runtime, rather than being bundled into the Content/Node/*.js files
// So, at runtime, they have to either be in node_modules or be built-in Node modules (e.g., 'fs')
'aspnet-prerendering',
'aspnet-webpack'
],
resolve: {
extensions: [ '.ts' ]
},
module: {
loaders: [
{ test: /\.ts$/, loader: 'ts-loader' },
]
},
entry: {
'prerenderer': ['./TypeScript/Prerenderer'],
'webpack-dev-middleware': ['./TypeScript/WebpackDevMiddleware'],
},
output: {
libraryTarget: 'commonjs',
path: './Content/Node',
filename: '[name].js'
}
};

View File

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

View File

@@ -0,0 +1,29 @@
/// <reference path="../../../../node_modules/@types/jasmine/index.d.ts" />
import { assert } from 'chai';
import { CounterComponent } from './counter.component';
import { TestBed, async, ComponentFixture } from '@angular/core/testing';
let fixture: ComponentFixture<CounterComponent>;
describe('Counter component', () => {
beforeEach(() => {
TestBed.configureTestingModule({ declarations: [CounterComponent] });
fixture = TestBed.createComponent(CounterComponent);
fixture.detectChanges();
});
it('should display a title', async(() => {
const titleText = fixture.nativeElement.querySelector('h2').textContent;
expect(titleText).toEqual('Counter');
}));
it('should start with count 0, then increments by 1 when clicked', async(() => {
const countElement = fixture.nativeElement.querySelector('strong');
expect(countElement.textContent).toEqual('0');
const incrementButton = fixture.nativeElement.querySelector('button');
incrementButton.click();
fixture.detectChanges();
expect(countElement.textContent).toEqual('1');
}));
});

View File

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

View File

@@ -3,14 +3,14 @@ import { Http } from '@angular/http';
@Component({
selector: 'fetchdata',
template: require('./fetchdata.component.html')
templateUrl: './fetchdata.component.html'
})
export class FetchDataComponent {
public forecasts: WeatherForecast[];
constructor(http: Http) {
http.get('/api/SampleData/WeatherForecasts').subscribe(result => {
this.forecasts = result.json();
this.forecasts = result.json() as WeatherForecast[];
});
}
}

View File

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

View File

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

View File

@@ -1,5 +1,6 @@
import 'angular2-universal-polyfills';
import 'zone.js';
import { createServerRenderer, RenderResult } from 'aspnet-prerendering';
import { enableProdMode } from '@angular/core';
import { platformNodeDynamic } from 'angular2-universal';
import { AppModule } from './app/app.module';
@@ -7,8 +8,8 @@ import { AppModule } from './app/app.module';
enableProdMode();
const platform = platformNodeDynamic();
export default function (params: any) : Promise<{ html: string, globals?: any }> {
return new Promise((resolve, reject) => {
export default createServerRenderer(params => {
return new Promise<RenderResult>((resolve, reject) => {
const requestZone = Zone.current.fork({
name: 'angular-universal request',
properties: {
@@ -16,9 +17,7 @@ export default function (params: any) : Promise<{ html: string, globals?: any }>
requestUrl: params.url,
originUrl: params.origin,
preboot: false,
// TODO: Render just the <app> component instead of wrapping it inside an extra HTML document
// Waiting on https://github.com/angular/universal/issues/347
document: '<!DOCTYPE html><html><head></head><body><app></app></body></html>'
document: '<app></app>'
},
onHandleError: (parentZone, currentZone, targetZone, error) => {
// If any error occurs while rendering the module, reject the whole operation
@@ -31,4 +30,4 @@ export default function (params: any) : Promise<{ html: string, globals?: any }>
resolve({ html: html });
}, reject);
});
}
});

View File

@@ -0,0 +1,32 @@
// Load required polyfills and testing libraries
import 'angular2-universal-polyfills';
import 'zone.js/dist/long-stack-trace-zone';
import 'zone.js/dist/proxy.js';
import 'zone.js/dist/sync-test';
import 'zone.js/dist/jasmine-patch';
import 'zone.js/dist/async-test';
import 'zone.js/dist/fake-async-test';
import * as testing from '@angular/core/testing';
import * as testingBrowser from '@angular/platform-browser-dynamic/testing';
// There's no typing for the `__karma__` variable. Just declare it as any
declare var __karma__: any;
declare var require: any;
// Prevent Karma from running prematurely
__karma__.loaded = function () {};
// First, initialize the Angular testing environment
testing.getTestBed().initTestEnvironment(
testingBrowser.BrowserDynamicTestingModule,
testingBrowser.platformBrowserDynamicTesting()
);
// Then we find all the tests
const context = require.context('../', true, /\.spec\.ts$/);
// And load the modules
context.keys().map(context);
// Finally, start Karma to run the tests
__karma__.start();

View File

@@ -0,0 +1,25 @@
// Karma configuration file, see link for more information
// https://karma-runner.github.io/0.13/config/configuration-file.html
module.exports = function (config) {
config.set({
basePath: '.',
frameworks: ['jasmine'],
files: [
'../../wwwroot/dist/vendor.js',
'./boot-tests.ts'
],
preprocessors: {
'./boot-tests.ts': ['webpack']
},
reporters: ['progress'],
port: 9876,
colors: true,
logLevel: config.LOG_INFO,
autoWatch: true,
browsers: ['Chrome'],
singleRun: false,
webpack: require('../../webpack.config.js').filter(config => config.target !== 'node'), // Test against client bundle, because tests run in a browser
webpackMiddleware: { stats: 'errors-only' }
});
};

View File

@@ -1,39 +0,0 @@
# Welcome to ASP.NET Core
We've made some big updates in this release, so its **important** that you spend a few minutes to learn whats new.
You've created a new ASP.NET Core project. [Learn what's new](https://go.microsoft.com/fwlink/?LinkId=518016)
## This application consists of:
* Sample pages using ASP.NET Core MVC
* [Gulp](https://go.microsoft.com/fwlink/?LinkId=518007) and [Bower](https://go.microsoft.com/fwlink/?LinkId=518004) for managing client-side libraries
* Theming using [Bootstrap](https://go.microsoft.com/fwlink/?LinkID=398939)
## How to
* [Add a Controller and View](https://go.microsoft.com/fwlink/?LinkID=398600)
* [Add an appsetting in config and access it in app.](https://go.microsoft.com/fwlink/?LinkID=699562)
* [Manage User Secrets using Secret Manager.](https://go.microsoft.com/fwlink/?LinkId=699315)
* [Use logging to log a message.](https://go.microsoft.com/fwlink/?LinkId=699316)
* [Add packages using NuGet.](https://go.microsoft.com/fwlink/?LinkId=699317)
* [Add client packages using Bower.](https://go.microsoft.com/fwlink/?LinkId=699318)
* [Target development, staging or production environment.](https://go.microsoft.com/fwlink/?LinkId=699319)
## Overview
* [Conceptual overview of what is ASP.NET Core](https://go.microsoft.com/fwlink/?LinkId=518008)
* [Fundamentals of ASP.NET Core such as Startup and middleware.](https://go.microsoft.com/fwlink/?LinkId=699320)
* [Working with Data](https://go.microsoft.com/fwlink/?LinkId=398602)
* [Security](https://go.microsoft.com/fwlink/?LinkId=398603)
* [Client side development](https://go.microsoft.com/fwlink/?LinkID=699321)
* [Develop on different platforms](https://go.microsoft.com/fwlink/?LinkID=699322)
* [Read more on the documentation site](https://go.microsoft.com/fwlink/?LinkID=699323)
## Run & Deploy
* [Run your app](https://go.microsoft.com/fwlink/?LinkID=517851)
* [Run tools such as EF migrations and more](https://go.microsoft.com/fwlink/?LinkID=517853)
* [Publish to Microsoft Azure Web Apps](https://go.microsoft.com/fwlink/?LinkID=398609)
We would love to hear your [feedback](https://go.microsoft.com/fwlink/?LinkId=518015)

View File

@@ -0,0 +1,3 @@
{
"sdk": { "version": "1.0.0-preview2-003121" }
}

View File

@@ -1,6 +1,9 @@
{
"name": "Angular2Spa",
"version": "0.0.0",
"scripts": {
"test": "karma start ClientApp/test/karma.conf.js"
},
"dependencies": {
"@angular/common": "2.0.2",
"@angular/compiler": "2.0.2",
@@ -13,9 +16,10 @@
"@angular/router": "3.0.2",
"@types/node": "^6.0.42",
"angular2-platform-node": "~2.0.11",
"angular2-template-loader": "^0.6.0",
"angular2-universal": "~2.0.11",
"angular2-universal-polyfills": "~2.0.11",
"aspnet-prerendering": "^1.0.7",
"aspnet-prerendering": "^2.0.0",
"aspnet-webpack": "^1.0.17",
"bootstrap": "^3.3.7",
"css": "^2.2.1",
@@ -25,8 +29,11 @@
"expose-loader": "^0.7.1",
"extract-text-webpack-plugin": "^1.0.1",
"file-loader": "^0.9.0",
"html-loader": "^0.4.4",
"isomorphic-fetch": "^2.2.1",
"jquery": "^2.2.1",
"json-loader": "^0.5.4",
"node-noop": "^1.0.0",
"preboot": "^4.5.2",
"raw-loader": "^0.5.1",
"rxjs": "5.0.0-beta.12",
@@ -37,8 +44,19 @@
"url-loader": "^0.5.7",
"webpack": "^1.13.2",
"webpack-hot-middleware": "^2.12.2",
"webpack-node-externals": "^1.4.3",
"webpack-merge": "^0.14.1",
"zone.js": "^0.6.25"
},
"devDependencies": {
"@types/chai": "^3.4.34",
"@types/jasmine": "^2.5.37",
"chai": "^3.5.0",
"jasmine-core": "^2.5.2",
"karma": "^1.3.0",
"karma-chai": "^0.1.0",
"karma-chrome-launcher": "^2.0.0",
"karma-cli": "^1.0.1",
"karma-jasmine": "^1.0.2",
"karma-webpack": "^1.8.0"
}
}

View File

@@ -56,7 +56,6 @@
"include": [
"appsettings.json",
"ClientApp/dist",
"node_modules",
"Views",
"web.config",
"wwwroot"

View File

@@ -196,6 +196,8 @@ orleans.codegen.cs
/node_modules/**
!/node_modules/_placeholder.txt
/yarn.lock
# RIA/Silverlight projects
Generated_Code/

View File

@@ -1,12 +1,11 @@
var isDevBuild = process.argv.indexOf('--env.prod') < 0;
var path = require('path');
var webpack = require('webpack');
var nodeExternals = require('webpack-node-externals');
var merge = require('webpack-merge');
var allFilenamesExceptJavaScript = /\.(?!js(\?|$))([^.]+(\?|$))/;
// Configuration in common to both client-side and server-side bundles
var sharedConfig = {
context: __dirname,
resolve: { extensions: [ '', '.js', '.ts' ] },
output: {
filename: '[name].js',
@@ -14,10 +13,10 @@ var sharedConfig = {
},
module: {
loaders: [
{ test: /\.ts$/, include: /ClientApp/, loader: 'ts', query: { silent: true } },
{ test: /\.html$/, loader: 'raw' },
{ test: /\.css$/, loader: 'to-string!css' },
{ test: /\.(png|jpg|jpeg|gif|svg)$/, loader: 'url', query: { limit: 25000 } }
{ test: /\.ts$/, include: /ClientApp/, loaders: ['ts-loader?silent=true', 'angular2-template-loader'] },
{ test: /\.html$/, loader: 'html-loader?minimize=false' },
{ test: /\.css$/, loader: 'to-string-loader!css-loader' },
{ test: /\.(png|jpg|jpeg|gif|svg)$/, loader: 'url-loader', query: { limit: 25000 } }
]
}
};
@@ -35,7 +34,7 @@ var clientBundleConfig = merge(sharedConfig, {
].concat(isDevBuild ? [
// Plugins that apply in development builds only
new webpack.SourceMapDevToolPlugin({
filename: '[name].js.map', // Remove this line if you prefer inline source maps
filename: '[file].map', // Remove this line if you prefer inline source maps
moduleFilenameTemplate: path.relative(clientBundleOutputDir, '[resourcePath]') // Point sourcemap entries to the original file locations on disk
})
] : [
@@ -47,14 +46,22 @@ var clientBundleConfig = merge(sharedConfig, {
// Configuration for server-side (prerendering) bundle suitable for running in Node
var serverBundleConfig = merge(sharedConfig, {
resolve: { packageMains: ['main'] },
entry: { 'main-server': './ClientApp/boot-server.ts' },
plugins: [
new webpack.DllReferencePlugin({
context: __dirname,
manifest: require('./ClientApp/dist/vendor-manifest.json'),
sourceType: 'commonjs2',
name: './vendor'
})
],
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
devtool: 'inline-source-map'
});
module.exports = [clientBundleConfig, serverBundleConfig];

View File

@@ -2,16 +2,15 @@ var isDevBuild = process.argv.indexOf('--env.prod') < 0;
var path = require('path');
var webpack = require('webpack');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var merge = require('webpack-merge');
var extractCSS = new ExtractTextPlugin('vendor.css');
module.exports = {
resolve: {
extensions: [ '', '.js' ]
},
var sharedConfig = {
resolve: { extensions: [ '', '.js' ] },
module: {
loaders: [
{ test: /\.(png|woff|woff2|eot|ttf|svg)(\?|$)/, loader: 'url-loader?limit=100000' },
{ test: /\.css(\?|$)/, loader: extractCSS.extract(['css']) }
{ test: /\.json$/, loader: require.resolve('json-loader') },
{ test: /\.(png|woff|woff2|eot|ttf|svg)(\?|$)/, loader: 'url-loader?limit=100000' }
]
},
entry: {
@@ -36,19 +35,54 @@ module.exports = {
]
},
output: {
path: path.join(__dirname, 'wwwroot', 'dist'),
publicPath: '/dist/',
filename: '[name].js',
library: '[name]_[hash]',
library: '[name]_[hash]'
},
plugins: [
new webpack.ProvidePlugin({ $: 'jquery', jQuery: 'jquery' }), // Maps these identifiers to the jQuery package (because Bootstrap expects it to be a global variable)
new webpack.ContextReplacementPlugin(/\@angular\b.*\b(bundles|linker)/, path.join(__dirname, './ClientApp')), // Workaround for https://github.com/angular/angular/issues/11580
new webpack.IgnorePlugin(/^vertx$/), // Workaround for https://github.com/stefanpenner/es6-promise/issues/100
new webpack.NormalModuleReplacementPlugin(/\/iconv-loader$/, require.resolve('node-noop')), // Workaround for https://github.com/andris9/encoding/issues/16
]
};
var clientBundleConfig = merge(sharedConfig, {
output: { path: path.join(__dirname, 'wwwroot', 'dist') },
module: {
loaders: [
{ test: /\.css(\?|$)/, loader: extractCSS.extract(['css-loader']) }
]
},
plugins: [
extractCSS,
new webpack.ProvidePlugin({ $: 'jquery', jQuery: 'jquery' }), // Maps these identifiers to the jQuery package (because Bootstrap expects it to be a global variable)
new webpack.optimize.OccurenceOrderPlugin(),
new webpack.DllPlugin({
path: path.join(__dirname, 'wwwroot', 'dist', '[name]-manifest.json'),
name: '[name]_[hash]'
})
].concat(isDevBuild ? [] : [
new webpack.optimize.OccurenceOrderPlugin(),
new webpack.optimize.UglifyJsPlugin({ compress: { warnings: false } })
])
};
});
var serverBundleConfig = merge(sharedConfig, {
target: 'node',
resolve: { packageMains: ['main'] },
output: {
path: path.join(__dirname, 'ClientApp', 'dist'),
libraryTarget: 'commonjs2',
},
module: {
loaders: [ { test: /\.css(\?|$)/, loader: 'to-string-loader!css-loader' } ]
},
entry: { vendor: ['aspnet-prerendering'] },
plugins: [
new webpack.DllPlugin({
path: path.join(__dirname, 'ClientApp', 'dist', '[name]-manifest.json'),
name: '[name]_[hash]'
})
]
});
module.exports = [clientBundleConfig, serverBundleConfig];

View File

@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
<TypeScriptCompileBlocked>true</TypeScriptCompileBlocked>
</PropertyGroup>
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.Props" Condition="'$(VSToolsPath)' != ''" />
<PropertyGroup Label="Globals">
<ProjectGuid>33d8dad9-74f9-471d-8bad-55f828faa736</ProjectGuid>
<RootNamespace>AureliaSpa</RootNamespace>
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">.\obj</BaseIntermediateOutputPath>
<OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath>
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
</PropertyGroup>
<PropertyGroup>
<SchemaVersion>2.0</SchemaVersion>
</PropertyGroup>
<Import Project="$(VSToolsPath)\DotNet.Web\Microsoft.DotNet.Web.targets" Condition="'$(VSToolsPath)' != ''" />
</Project>

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,14 @@
<template>
<require from="../navmenu/navmenu.html"></require>
<require from="./app.css"></require>
<div class="container-fluid">
<div class="row">
<div class="col-sm-3">
<navmenu router.bind="router"></navmenu>
</div>
<div class="col-sm-9 body-content">
<router-view></router-view>
</div>
</div>
</div>
</template>

View File

@@ -0,0 +1,34 @@
import { Aurelia } from 'aurelia-framework';
import { Router, RouterConfiguration } from 'aurelia-router';
export class App {
router: Router;
configureRouter(config: RouterConfiguration, router: Router) {
config.title = 'Aurelia';
config.map([{
route: [ '', 'home' ],
name: 'home',
settings: { icon: 'home' },
moduleId: '../home/home',
nav: true,
title: 'Home'
}, {
route: 'counter',
name: 'counter',
settings: { icon: 'education' },
moduleId: '../counter/counter',
nav: true,
title: 'Counter'
}, {
route: 'fetch-data',
name: 'fetchdata',
settings: { icon: 'th-list' },
moduleId: '../fetchdata/fetchdata',
nav: true,
title: 'Fetch data'
}]);
this.router = router;
}
}

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