From 8acba881602e0d8cf94bca04d353e5040ffa1506 Mon Sep 17 00:00:00 2001 From: Steve Sanderson Date: Tue, 11 Jul 2017 16:23:15 +0100 Subject: [PATCH 1/5] Update aspnet-webpack to 2.0.0, now supporting HMR when apps are running in virtual directories --- .../npm/aspnet-webpack/package.json | 2 +- .../src/WebpackDevMiddleware.ts | 48 ++++++++++++++----- 2 files changed, 38 insertions(+), 12 deletions(-) diff --git a/src/Microsoft.AspNetCore.SpaServices/npm/aspnet-webpack/package.json b/src/Microsoft.AspNetCore.SpaServices/npm/aspnet-webpack/package.json index 010d226..47b3381 100644 --- a/src/Microsoft.AspNetCore.SpaServices/npm/aspnet-webpack/package.json +++ b/src/Microsoft.AspNetCore.SpaServices/npm/aspnet-webpack/package.json @@ -1,6 +1,6 @@ { "name": "aspnet-webpack", - "version": "1.0.29", + "version": "2.0.0", "description": "Helpers for using Webpack in ASP.NET Core projects. Works in conjunction with the Microsoft.AspNetCore.SpaServices NuGet package.", "main": "index.js", "scripts": { diff --git a/src/Microsoft.AspNetCore.SpaServices/npm/aspnet-webpack/src/WebpackDevMiddleware.ts b/src/Microsoft.AspNetCore.SpaServices/npm/aspnet-webpack/src/WebpackDevMiddleware.ts index bf31d82..7fba9de 100644 --- a/src/Microsoft.AspNetCore.SpaServices/npm/aspnet-webpack/src/WebpackDevMiddleware.ts +++ b/src/Microsoft.AspNetCore.SpaServices/npm/aspnet-webpack/src/WebpackDevMiddleware.ts @@ -108,7 +108,7 @@ function attachWebpackDevMiddleware(app: any, webpackConfig: webpack.Configurati const compiler = webpack(webpackConfig); app.use(require('webpack-dev-middleware')(compiler, { noInfo: true, - publicPath: webpackConfig.output.publicPath, + publicPath: ensureLeadingSlash(webpackConfig.output.publicPath), watchOptions: webpackConfig.watchOptions })); @@ -195,6 +195,14 @@ function copyRecursiveToRealFsSync(from: typeof fs, rootDir: string, exclude: Re }); } +function ensureLeadingSlash(value: string) { + if (value !== null && value.substring(0, 1) !== '/') { + value = '/' + value; + } + + return value; +} + function pathJoinSafe(rootPath: string, filePath: string) { // On Windows, MemoryFileSystem's readdirSync output produces directory entries like 'C:' // which then trigger errors if you call statSync for them. Avoid this by detecting drive @@ -257,22 +265,32 @@ export function createWebpackDevServer(callback: CreateDevServerCallback, option if (!publicPath) { throw new Error('To use the Webpack dev server, you must specify a value for \'publicPath\' on the \'output\' section of your webpack config (for any configuration that targets browsers)'); } - normalizedPublicPaths.push(removeTrailingSlash(publicPath)); + const publicPathNoTrailingSlash = removeTrailingSlash(publicPath); + normalizedPublicPaths.push(publicPathNoTrailingSlash); - // Newer versions of Microsoft.AspNetCore.SpaServices will explicitly pass an HMR endpoint URL - // (because it's relative to the app's URL space root, which the client doesn't otherwise know). - // For back-compatibility, fall back on connecting directly to the underlying HMR server (though - // that won't work if the app is hosted on HTTPS because of the mixed-content rule, and we can't - // run the HMR server itself on HTTPS because in general it has no valid cert). - const hmrClientEndpoint = options.hotModuleReplacementEndpointUrl // The URL that we'll proxy (e.g., /__asp_webpack_hmr) - || `http://localhost:${listener.address().port}/__webpack_hmr`; // Fall back on absolute URL to bypass proxying - const hmrServerEndpoint = options.hotModuleReplacementEndpointUrl - || '/__webpack_hmr'; // URL is relative to webpack dev server root + // This is the URL the client will connect to, except that since it's a relative URL + // (no leading slash), Webpack will resolve it against the runtime URL + // plus it also adds the publicPath + const hmrClientEndpoint = removeLeadingSlash(options.hotModuleReplacementEndpointUrl); + + // This is the URL inside the Webpack middleware Node server that we'll proxy to. + // We have to prefix with the public path because Webpack will add the publicPath + // when it resolves hmrClientEndpoint as a relative URL. + const hmrServerEndpoint = ensureLeadingSlash(publicPathNoTrailingSlash + options.hotModuleReplacementEndpointUrl); // We always overwrite the 'path' option as it needs to match what the .NET side is expecting const hmrClientOptions = options.suppliedOptions.HotModuleReplacementClientOptions || >{}; hmrClientOptions['path'] = hmrClientEndpoint; + const dynamicPublicPathKey = 'dynamicPublicPath'; + if (!(dynamicPublicPathKey in hmrClientOptions)) { + // dynamicPublicPath default to true, so we can work with nonempty pathbases (virtual directories) + hmrClientOptions[dynamicPublicPathKey] = true; + } else { + // ... but you can set it to any other value explicitly if you want (e.g., false) + hmrClientOptions[dynamicPublicPathKey] = JSON.parse(hmrClientOptions[dynamicPublicPathKey]); + } + attachWebpackDevMiddleware(app, webpackConfig, enableHotModuleReplacement, enableReactHotModuleReplacement, hmrClientOptions, hmrServerEndpoint); } }); @@ -292,6 +310,14 @@ export function createWebpackDevServer(callback: CreateDevServerCallback, option }); } +function removeLeadingSlash(str: string) { + if (str.indexOf('/') === 0) { + str = str.substring(1); + } + + return str; +} + function removeTrailingSlash(str: string) { if (str.lastIndexOf('/') === str.length - 1) { str = str.substring(0, str.length - 1); From 56c806b34e6c9ebc90b725741556a01fe93c6501 Mon Sep 17 00:00:00 2001 From: Steve Sanderson Date: Tue, 11 Jul 2017 22:37:09 +0100 Subject: [PATCH 2/5] Update aspnet-prerendering to 3.0.1, fixing the default "fetch" base URL to match the real application root URL --- .../npm/aspnet-prerendering/package.json | 4 ++-- .../npm/aspnet-prerendering/src/Prerendering.ts | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/Microsoft.AspNetCore.SpaServices/npm/aspnet-prerendering/package.json b/src/Microsoft.AspNetCore.SpaServices/npm/aspnet-prerendering/package.json index b2813a4..e239460 100644 --- a/src/Microsoft.AspNetCore.SpaServices/npm/aspnet-prerendering/package.json +++ b/src/Microsoft.AspNetCore.SpaServices/npm/aspnet-prerendering/package.json @@ -1,6 +1,6 @@ { "name": "aspnet-prerendering", - "version": "2.0.6", + "version": "3.0.1", "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,7 +17,7 @@ "url": "https://github.com/aspnet/JavaScriptServices.git" }, "dependencies": { - "domain-task": "^2.0.2" + "domain-task": "^3.0.0" }, "devDependencies": { "@types/node": "^6.0.42", diff --git a/src/Microsoft.AspNetCore.SpaServices/npm/aspnet-prerendering/src/Prerendering.ts b/src/Microsoft.AspNetCore.SpaServices/npm/aspnet-prerendering/src/Prerendering.ts index 80a0259..a313cba 100644 --- a/src/Microsoft.AspNetCore.SpaServices/npm/aspnet-prerendering/src/Prerendering.ts +++ b/src/Microsoft.AspNetCore.SpaServices/npm/aspnet-prerendering/src/Prerendering.ts @@ -26,6 +26,7 @@ export function createServerRenderer(bootFunc: BootFunc): RenderToStringFunc { domainTasks: domainTaskCompletionPromise, data: customDataParameter }; + const absoluteBaseUrl = params.origin + params.baseUrl; // Should be same value as page's // Open a new domain that can track all the async tasks involved in the app's execution domainTaskRun(/* code to run */ () => { @@ -35,7 +36,7 @@ export function createServerRenderer(bootFunc: BootFunc): RenderToStringFunc { bindPromiseContinuationsToDomain(domainTaskCompletionPromise, domain['active']); // Make the base URL available to the 'domain-tasks/fetch' helper within this execution context - domainTaskBaseUrl(absoluteRequestUrl); + domainTaskBaseUrl(absoluteBaseUrl); // Begin rendering, and apply a timeout const bootFuncPromise = bootFunc(params); From 4903e123731cca060b32f7d141a487393985ed7e Mon Sep 17 00:00:00 2001 From: Steve Sanderson Date: Tue, 11 Jul 2017 22:38:08 +0100 Subject: [PATCH 3/5] Publish aspnet-webpack-react as 3.0.0 since it's no longer beta --- .../npm/aspnet-webpack-react/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.AspNetCore.SpaServices/npm/aspnet-webpack-react/package.json b/src/Microsoft.AspNetCore.SpaServices/npm/aspnet-webpack-react/package.json index a6f0b0f..19a2a1b 100644 --- a/src/Microsoft.AspNetCore.SpaServices/npm/aspnet-webpack-react/package.json +++ b/src/Microsoft.AspNetCore.SpaServices/npm/aspnet-webpack-react/package.json @@ -1,6 +1,6 @@ { "name": "aspnet-webpack-react", - "version": "3.0.0-beta.1", + "version": "3.0.0", "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": { From bb0727c34c201c4b8e08c65470023577f44b9f6a Mon Sep 17 00:00:00 2001 From: Steve Sanderson Date: Tue, 11 Jul 2017 16:47:57 +0100 Subject: [PATCH 4/5] Update templates to newer aspnet NPM dependencies --- templates/AngularSpa/npm-shrinkwrap.json | 18 +++++++-------- templates/AngularSpa/package.json | 4 ++-- templates/AureliaSpa/npm-shrinkwrap.json | 6 ++--- templates/AureliaSpa/package.json | 2 +- templates/KnockoutSpa/npm-shrinkwrap.json | 6 ++--- templates/KnockoutSpa/package.json | 2 +- templates/ReactReduxSpa/npm-shrinkwrap.json | 25 ++++++++------------- templates/ReactReduxSpa/package.json | 6 ++--- templates/ReactSpa/npm-shrinkwrap.json | 12 +++++----- templates/ReactSpa/package.json | 4 ++-- templates/VueSpa/npm-shrinkwrap.json | 6 ++--- templates/VueSpa/package.json | 2 +- 12 files changed, 43 insertions(+), 50 deletions(-) diff --git a/templates/AngularSpa/npm-shrinkwrap.json b/templates/AngularSpa/npm-shrinkwrap.json index f4f3ada..e87dcf5 100644 --- a/templates/AngularSpa/npm-shrinkwrap.json +++ b/templates/AngularSpa/npm-shrinkwrap.json @@ -274,14 +274,14 @@ "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.9.1.tgz" }, "aspnet-prerendering": { - "version": "2.0.6", - "from": "aspnet-prerendering@>=2.0.5 <3.0.0", - "resolved": "https://registry.npmjs.org/aspnet-prerendering/-/aspnet-prerendering-2.0.6.tgz" + "version": "3.0.1", + "from": "aspnet-prerendering@3.0.1", + "resolved": "https://registry.npmjs.org/aspnet-prerendering/-/aspnet-prerendering-3.0.1.tgz" }, "aspnet-webpack": { - "version": "1.0.29", - "from": "aspnet-webpack@>=1.0.29 <2.0.0", - "resolved": "https://registry.npmjs.org/aspnet-webpack/-/aspnet-webpack-1.0.29.tgz" + "version": "2.0.0", + "from": "aspnet-webpack@2.0.0", + "resolved": "https://registry.npmjs.org/aspnet-webpack/-/aspnet-webpack-2.0.0.tgz" }, "assert": { "version": "1.4.1", @@ -932,9 +932,9 @@ "resolved": "https://registry.npmjs.org/domain-context/-/domain-context-0.5.1.tgz" }, "domain-task": { - "version": "2.0.3", - "from": "domain-task@>=2.0.2 <3.0.0", - "resolved": "https://registry.npmjs.org/domain-task/-/domain-task-2.0.3.tgz" + "version": "3.0.3", + "from": "domain-task@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/domain-task/-/domain-task-3.0.3.tgz" }, "ee-first": { "version": "1.1.1", diff --git a/templates/AngularSpa/package.json b/templates/AngularSpa/package.json index 58494ec..65f753f 100644 --- a/templates/AngularSpa/package.json +++ b/templates/AngularSpa/package.json @@ -20,8 +20,8 @@ "@ngtools/webpack": "1.5.0", "@types/node": "8.0.8", "angular2-template-loader": "0.6.2", - "aspnet-prerendering": "^2.0.5", - "aspnet-webpack": "^1.0.29", + "aspnet-prerendering": "^3.0.1", + "aspnet-webpack": "^2.0.0", "awesome-typescript-loader": "3.2.1", "bootstrap": "3.3.7", "css": "2.2.1", diff --git a/templates/AureliaSpa/npm-shrinkwrap.json b/templates/AureliaSpa/npm-shrinkwrap.json index 611e8b6..5a52826 100644 --- a/templates/AureliaSpa/npm-shrinkwrap.json +++ b/templates/AureliaSpa/npm-shrinkwrap.json @@ -113,9 +113,9 @@ "dev": true }, "aspnet-webpack": { - "version": "1.0.29", - "from": "aspnet-webpack@>=1.0.28 <2.0.0", - "resolved": "https://registry.npmjs.org/aspnet-webpack/-/aspnet-webpack-1.0.29.tgz", + "version": "2.0.0", + "from": "aspnet-webpack@2.0.0", + "resolved": "https://registry.npmjs.org/aspnet-webpack/-/aspnet-webpack-2.0.0.tgz", "dev": true }, "assert": { diff --git a/templates/AureliaSpa/package.json b/templates/AureliaSpa/package.json index 99bc02b..7e92b5a 100644 --- a/templates/AureliaSpa/package.json +++ b/templates/AureliaSpa/package.json @@ -15,7 +15,7 @@ }, "devDependencies": { "@types/node": "^7.0.12", - "aspnet-webpack": "^1.0.28", + "aspnet-webpack": "^2.0.0", "aurelia-webpack-plugin": "^2.0.0-rc.2", "css-loader": "^0.28.0", "extract-text-webpack-plugin": "^2.1.0", diff --git a/templates/KnockoutSpa/npm-shrinkwrap.json b/templates/KnockoutSpa/npm-shrinkwrap.json index 665c0a7..75ccbab 100644 --- a/templates/KnockoutSpa/npm-shrinkwrap.json +++ b/templates/KnockoutSpa/npm-shrinkwrap.json @@ -167,9 +167,9 @@ "dev": true }, "aspnet-webpack": { - "version": "1.0.29", - "from": "aspnet-webpack@>=1.0.27 <2.0.0", - "resolved": "https://registry.npmjs.org/aspnet-webpack/-/aspnet-webpack-1.0.29.tgz", + "version": "2.0.0", + "from": "aspnet-webpack@2.0.0", + "resolved": "https://registry.npmjs.org/aspnet-webpack/-/aspnet-webpack-2.0.0.tgz", "dev": true }, "assert": { diff --git a/templates/KnockoutSpa/package.json b/templates/KnockoutSpa/package.json index c4c42fc..385775a 100644 --- a/templates/KnockoutSpa/package.json +++ b/templates/KnockoutSpa/package.json @@ -12,7 +12,7 @@ "@types/react-router": "^2.0.37", "@types/requirejs": "^2.1.26", "@types/signals": "0.0.16", - "aspnet-webpack": "^1.0.27", + "aspnet-webpack": "^2.0.0", "awesome-typescript-loader": "^3.0.0", "bootstrap": "^3.3.6", "bundle-loader": "^0.5.4", diff --git a/templates/ReactReduxSpa/npm-shrinkwrap.json b/templates/ReactReduxSpa/npm-shrinkwrap.json index 9dc18a0..5e4df91 100644 --- a/templates/ReactReduxSpa/npm-shrinkwrap.json +++ b/templates/ReactReduxSpa/npm-shrinkwrap.json @@ -170,26 +170,19 @@ "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.9.1.tgz" }, "aspnet-prerendering": { - "version": "2.0.6", - "from": "aspnet-prerendering@>=2.0.5 <3.0.0", - "resolved": "https://registry.npmjs.org/aspnet-prerendering/-/aspnet-prerendering-2.0.6.tgz", - "dependencies": { - "domain-task": { - "version": "2.0.3", - "from": "domain-task@>=2.0.2 <3.0.0", - "resolved": "https://registry.npmjs.org/domain-task/-/domain-task-2.0.3.tgz" - } - } + "version": "3.0.1", + "from": "aspnet-prerendering@3.0.1", + "resolved": "https://registry.npmjs.org/aspnet-prerendering/-/aspnet-prerendering-3.0.1.tgz" }, "aspnet-webpack": { - "version": "1.0.29", - "from": "aspnet-webpack@>=1.0.29 <2.0.0", - "resolved": "https://registry.npmjs.org/aspnet-webpack/-/aspnet-webpack-1.0.29.tgz" + "version": "2.0.0", + "from": "aspnet-webpack@2.0.0", + "resolved": "https://registry.npmjs.org/aspnet-webpack/-/aspnet-webpack-2.0.0.tgz" }, "aspnet-webpack-react": { - "version": "3.0.0-beta.1", - "from": "aspnet-webpack-react@>=3.0.0-beta <4.0.0", - "resolved": "https://registry.npmjs.org/aspnet-webpack-react/-/aspnet-webpack-react-3.0.0-beta.1.tgz" + "version": "3.0.0", + "from": "aspnet-webpack-react@3.0.0", + "resolved": "https://registry.npmjs.org/aspnet-webpack-react/-/aspnet-webpack-react-3.0.0.tgz" }, "assert": { "version": "1.4.1", diff --git a/templates/ReactReduxSpa/package.json b/templates/ReactReduxSpa/package.json index 9d3ab76..b8c308a 100644 --- a/templates/ReactReduxSpa/package.json +++ b/templates/ReactReduxSpa/package.json @@ -12,9 +12,9 @@ "@types/react-router-redux": "5.0.3", "@types/webpack": "2.2.15", "@types/webpack-env": "1.13.0", - "aspnet-prerendering": "^2.0.5", - "aspnet-webpack": "^1.0.29", - "aspnet-webpack-react": "^3.0.0-beta", + "aspnet-prerendering": "^3.0.1", + "aspnet-webpack": "^2.0.0", + "aspnet-webpack-react": "^3.0.0", "awesome-typescript-loader": "3.2.1", "bootstrap": "3.3.7", "css-loader": "0.28.4", diff --git a/templates/ReactSpa/npm-shrinkwrap.json b/templates/ReactSpa/npm-shrinkwrap.json index 694cbc9..4069cea 100644 --- a/templates/ReactSpa/npm-shrinkwrap.json +++ b/templates/ReactSpa/npm-shrinkwrap.json @@ -155,15 +155,15 @@ "dev": true }, "aspnet-webpack": { - "version": "1.0.29", - "from": "aspnet-webpack@>=1.0.29 <2.0.0", - "resolved": "https://registry.npmjs.org/aspnet-webpack/-/aspnet-webpack-1.0.29.tgz", + "version": "2.0.0", + "from": "aspnet-webpack@2.0.0", + "resolved": "https://registry.npmjs.org/aspnet-webpack/-/aspnet-webpack-2.0.0.tgz", "dev": true }, "aspnet-webpack-react": { - "version": "3.0.0-beta.1", - "from": "aspnet-webpack-react@>=3.0.0-beta <4.0.0", - "resolved": "https://registry.npmjs.org/aspnet-webpack-react/-/aspnet-webpack-react-3.0.0-beta.1.tgz", + "version": "3.0.0", + "from": "aspnet-webpack-react@3.0.0", + "resolved": "https://registry.npmjs.org/aspnet-webpack-react/-/aspnet-webpack-react-3.0.0.tgz", "dev": true }, "assert": { diff --git a/templates/ReactSpa/package.json b/templates/ReactSpa/package.json index 980d979..913de25 100644 --- a/templates/ReactSpa/package.json +++ b/templates/ReactSpa/package.json @@ -8,8 +8,8 @@ "@types/react-dom": "15.5.1", "@types/react-router": "4.0.12", "@types/webpack-env": "1.13.0", - "aspnet-webpack": "^1.0.29", - "aspnet-webpack-react": "^3.0.0-beta", + "aspnet-webpack": "^2.0.0", + "aspnet-webpack-react": "^3.0.0", "awesome-typescript-loader": "3.2.1", "bootstrap": "3.3.7", "css-loader": "0.28.4", diff --git a/templates/VueSpa/npm-shrinkwrap.json b/templates/VueSpa/npm-shrinkwrap.json index 55b7451..ab6bf01 100644 --- a/templates/VueSpa/npm-shrinkwrap.json +++ b/templates/VueSpa/npm-shrinkwrap.json @@ -119,9 +119,9 @@ "dev": true }, "aspnet-webpack": { - "version": "1.0.29", - "from": "aspnet-webpack@>=1.0.27 <2.0.0", - "resolved": "https://registry.npmjs.org/aspnet-webpack/-/aspnet-webpack-1.0.29.tgz", + "version": "2.0.0", + "from": "aspnet-webpack@2.0.0", + "resolved": "https://registry.npmjs.org/aspnet-webpack/-/aspnet-webpack-2.0.0.tgz", "dev": true }, "assert": { diff --git a/templates/VueSpa/package.json b/templates/VueSpa/package.json index d7b4334..eac756d 100644 --- a/templates/VueSpa/package.json +++ b/templates/VueSpa/package.json @@ -4,7 +4,7 @@ "version": "0.0.0", "devDependencies": { "@types/requirejs": "^2.1.28", - "aspnet-webpack": "^1.0.27", + "aspnet-webpack": "^2.0.0", "awesome-typescript-loader": "^3.0.0", "bootstrap": "^3.3.6", "css-loader": "^0.25.0", From e65ecebac6f3c3c9abd815d25fd3b898a54e4453 Mon Sep 17 00:00:00 2001 From: Steve Sanderson Date: Tue, 11 Jul 2017 23:45:25 +0100 Subject: [PATCH 5/5] Make templates work with nonempty baseUrls (e.g., IIS virtual directories) --- .../AngularSpa/ClientApp/app/app.module.browser.ts | 6 +++--- .../app/components/fetchdata/fetchdata.component.ts | 4 ++-- templates/AngularSpa/ClientApp/boot.server.ts | 4 +++- templates/AngularSpa/webpack.config.js | 2 +- templates/AngularSpa/webpack.config.vendor.js | 2 +- .../ClientApp/app/components/fetchdata/fetchdata.ts | 2 +- templates/AureliaSpa/ClientApp/boot.ts | 6 ++++++ templates/AureliaSpa/webpack.config.js | 2 +- templates/AureliaSpa/webpack.config.vendor.js | 2 +- templates/KnockoutSpa/ClientApp/boot.ts | 4 +++- .../ClientApp/components/app-root/app-root.html | 2 +- .../ClientApp/components/app-root/app-root.ts | 10 +++++----- .../ClientApp/components/fetch-data/fetch-data.ts | 2 +- .../ClientApp/components/nav-menu/nav-menu.html | 6 +++--- .../ClientApp/components/nav-menu/nav-menu.ts | 8 +++++--- templates/KnockoutSpa/ClientApp/router.ts | 11 ++++++++--- templates/KnockoutSpa/Views/Home/Index.cshtml | 2 +- templates/KnockoutSpa/webpack.config.js | 2 +- templates/KnockoutSpa/webpack.config.vendor.js | 2 +- templates/ReactReduxSpa/ClientApp/boot-client.tsx | 3 ++- templates/ReactReduxSpa/ClientApp/boot-server.tsx | 6 ++++-- .../ReactReduxSpa/ClientApp/store/WeatherForecasts.ts | 2 +- templates/ReactReduxSpa/webpack.config.js | 2 +- templates/ReactReduxSpa/webpack.config.vendor.js | 2 +- templates/ReactSpa/ClientApp/boot.tsx | 3 ++- templates/ReactSpa/ClientApp/components/FetchData.tsx | 2 +- templates/ReactSpa/webpack.config.js | 2 +- templates/ReactSpa/webpack.config.vendor.js | 2 +- .../ClientApp/components/fetchdata/fetchdata.ts | 2 +- templates/VueSpa/webpack.config.js | 2 +- templates/VueSpa/webpack.config.vendor.js | 2 +- 31 files changed, 65 insertions(+), 44 deletions(-) diff --git a/templates/AngularSpa/ClientApp/app/app.module.browser.ts b/templates/AngularSpa/ClientApp/app/app.module.browser.ts index 7e71ca9..03104b4 100644 --- a/templates/AngularSpa/ClientApp/app/app.module.browser.ts +++ b/templates/AngularSpa/ClientApp/app/app.module.browser.ts @@ -10,12 +10,12 @@ import { AppComponent } from './components/app/app.component'; AppModuleShared ], providers: [ - { provide: 'ORIGIN_URL', useFactory: getOriginUrl } + { provide: 'BASE_URL', useFactory: getBaseUrl } ] }) export class AppModule { } -export function getOriginUrl() { - return location.origin; +export function getBaseUrl() { + return document.getElementsByTagName('base')[0].href; } diff --git a/templates/AngularSpa/ClientApp/app/components/fetchdata/fetchdata.component.ts b/templates/AngularSpa/ClientApp/app/components/fetchdata/fetchdata.component.ts index 6296925..a4c06f4 100644 --- a/templates/AngularSpa/ClientApp/app/components/fetchdata/fetchdata.component.ts +++ b/templates/AngularSpa/ClientApp/app/components/fetchdata/fetchdata.component.ts @@ -8,8 +8,8 @@ import { Http } from '@angular/http'; export class FetchDataComponent { public forecasts: WeatherForecast[]; - constructor(http: Http, @Inject('ORIGIN_URL') originUrl: string) { - http.get(originUrl + '/api/SampleData/WeatherForecasts').subscribe(result => { + constructor(http: Http, @Inject('BASE_URL') baseUrl: string) { + http.get(baseUrl + 'api/SampleData/WeatherForecasts').subscribe(result => { this.forecasts = result.json() as WeatherForecast[]; }, error => console.error(error)); } diff --git a/templates/AngularSpa/ClientApp/boot.server.ts b/templates/AngularSpa/ClientApp/boot.server.ts index 08474cf..851e137 100644 --- a/templates/AngularSpa/ClientApp/boot.server.ts +++ b/templates/AngularSpa/ClientApp/boot.server.ts @@ -1,6 +1,7 @@ import 'reflect-metadata'; import 'zone.js'; import 'rxjs/add/operator/first'; +import { APP_BASE_HREF } from '@angular/common'; import { enableProdMode, ApplicationRef, NgZone, ValueProvider } from '@angular/core'; import { platformDynamicServer, PlatformState, INITIAL_CONFIG } from '@angular/platform-server'; import { createServerRenderer, RenderResult } from 'aspnet-prerendering'; @@ -11,7 +12,8 @@ enableProdMode(); export default createServerRenderer(params => { const providers = [ { provide: INITIAL_CONFIG, useValue: { document: '', url: params.url } }, - { provide: 'ORIGIN_URL', useValue: params.origin } + { provide: APP_BASE_HREF, useValue: params.baseUrl }, + { provide: 'BASE_URL', useValue: params.origin + params.baseUrl }, ]; return platformDynamicServer(providers).bootstrapModule(AppModule).then(moduleRef => { diff --git a/templates/AngularSpa/webpack.config.js b/templates/AngularSpa/webpack.config.js index fd1ff6e..85e238d 100644 --- a/templates/AngularSpa/webpack.config.js +++ b/templates/AngularSpa/webpack.config.js @@ -13,7 +13,7 @@ module.exports = (env) => { resolve: { extensions: [ '.js', '.ts' ] }, output: { filename: '[name].js', - publicPath: '/dist/' // Webpack dev middleware, if enabled, handles requests for this URL prefix + publicPath: 'dist/' // Webpack dev middleware, if enabled, handles requests for this URL prefix }, module: { rules: [ diff --git a/templates/AngularSpa/webpack.config.vendor.js b/templates/AngularSpa/webpack.config.vendor.js index ed7fa93..36e4386 100644 --- a/templates/AngularSpa/webpack.config.vendor.js +++ b/templates/AngularSpa/webpack.config.vendor.js @@ -36,7 +36,7 @@ module.exports = (env) => { ] }, output: { - publicPath: '/dist/', + publicPath: 'dist/', filename: '[name].js', library: '[name]_[hash]' }, diff --git a/templates/AureliaSpa/ClientApp/app/components/fetchdata/fetchdata.ts b/templates/AureliaSpa/ClientApp/app/components/fetchdata/fetchdata.ts index ff86025..6cd72ac 100644 --- a/templates/AureliaSpa/ClientApp/app/components/fetchdata/fetchdata.ts +++ b/templates/AureliaSpa/ClientApp/app/components/fetchdata/fetchdata.ts @@ -6,7 +6,7 @@ export class Fetchdata { public forecasts: WeatherForecast[]; constructor(http: HttpClient) { - http.fetch('/api/SampleData/WeatherForecasts') + http.fetch('api/SampleData/WeatherForecasts') .then(result => result.json() as Promise) .then(data => { this.forecasts = data; diff --git a/templates/AureliaSpa/ClientApp/boot.ts b/templates/AureliaSpa/ClientApp/boot.ts index 5c9e2fd..053b9c3 100644 --- a/templates/AureliaSpa/ClientApp/boot.ts +++ b/templates/AureliaSpa/ClientApp/boot.ts @@ -1,5 +1,6 @@ import 'isomorphic-fetch'; import { Aurelia, PLATFORM } from 'aurelia-framework'; +import { HttpClient } from 'aurelia-fetch-client'; import 'bootstrap/dist/css/bootstrap.css'; import 'bootstrap'; declare const IS_DEV_BUILD: boolean; // The value is supplied by Webpack during the build @@ -11,5 +12,10 @@ export function configure(aurelia: Aurelia) { aurelia.use.developmentLogging(); } + new HttpClient().configure(config => { + const baseUrl = document.getElementsByTagName('base')[0].href; + config.withBaseUrl(baseUrl); + }); + aurelia.start().then(() => aurelia.setRoot(PLATFORM.moduleName('app/components/app/app'))); } diff --git a/templates/AureliaSpa/webpack.config.js b/templates/AureliaSpa/webpack.config.js index 4ddc35c..5ff94d0 100644 --- a/templates/AureliaSpa/webpack.config.js +++ b/templates/AureliaSpa/webpack.config.js @@ -14,7 +14,7 @@ module.exports = (env) => { }, output: { path: path.resolve(bundleOutputDir), - publicPath: '/dist/', + publicPath: 'dist/', filename: '[name].js' }, module: { diff --git a/templates/AureliaSpa/webpack.config.vendor.js b/templates/AureliaSpa/webpack.config.vendor.js index 9625a31..1dc579c 100644 --- a/templates/AureliaSpa/webpack.config.vendor.js +++ b/templates/AureliaSpa/webpack.config.vendor.js @@ -38,7 +38,7 @@ module.exports = ({ prod } = {}) => { }, output: { path: path.join(__dirname, 'wwwroot', 'dist'), - publicPath: '/dist/', + publicPath: 'dist/', filename: '[name].js', library: '[name]_[hash]', }, diff --git a/templates/KnockoutSpa/ClientApp/boot.ts b/templates/KnockoutSpa/ClientApp/boot.ts index 143e8e5..b8da1dd 100644 --- a/templates/KnockoutSpa/ClientApp/boot.ts +++ b/templates/KnockoutSpa/ClientApp/boot.ts @@ -4,12 +4,14 @@ import * as ko from 'knockout'; import './webpack-component-loader'; import AppRootComponent from './components/app-root/app-root'; const createHistory = require('history').createBrowserHistory; +const baseUrl = document.getElementsByTagName('base')[0].getAttribute('href'); +const basename = baseUrl.substring(0, baseUrl.length - 1); // History component needs no trailing slash // Load and register the component ko.components.register('app-root', AppRootComponent); // Tell Knockout to start up an instance of your application -ko.applyBindings({ history: createHistory() }); +ko.applyBindings({ history: createHistory({ basename }), basename }); // Basic hot reloading support. Automatically reloads and restarts the Knockout app each time // you modify source files. This will not preserve any application state other than the URL. diff --git a/templates/KnockoutSpa/ClientApp/components/app-root/app-root.html b/templates/KnockoutSpa/ClientApp/components/app-root/app-root.html index f1f11b4..88e345b 100644 --- a/templates/KnockoutSpa/ClientApp/components/app-root/app-root.html +++ b/templates/KnockoutSpa/ClientApp/components/app-root/app-root.html @@ -1,7 +1,7 @@
- +
diff --git a/templates/KnockoutSpa/ClientApp/components/app-root/app-root.ts b/templates/KnockoutSpa/ClientApp/components/app-root/app-root.ts index af9062c..2ca1bfe 100644 --- a/templates/KnockoutSpa/ClientApp/components/app-root/app-root.ts +++ b/templates/KnockoutSpa/ClientApp/components/app-root/app-root.ts @@ -12,12 +12,12 @@ const routes: Route[] = [ class AppRootViewModel { public route: KnockoutObservable; - private _router: Router; + public router: Router; - constructor(params: { history: History.History }) { + constructor(params: { history: History.History, basename: string }) { // Activate the client-side router - this._router = new Router(params.history, routes) - this.route = this._router.currentRoute; + this.router = new Router(params.history, routes, params.basename); + this.route = this.router.currentRoute; // Load and register all the KO components needed to handle the routes // The optional 'bundle-loader?lazy!' prefix is a Webpack feature that causes the referenced modules @@ -32,7 +32,7 @@ class AppRootViewModel { // To support hot module replacement, this method unregisters the router and KO components. // In production scenarios where hot module replacement is disabled, this would not be invoked. public dispose() { - this._router.dispose(); + this.router.dispose(); // TODO: Need a better API for this Object.getOwnPropertyNames((ko).components._allRegisteredComponents).forEach(componentName => { diff --git a/templates/KnockoutSpa/ClientApp/components/fetch-data/fetch-data.ts b/templates/KnockoutSpa/ClientApp/components/fetch-data/fetch-data.ts index 9576d66..b053890 100644 --- a/templates/KnockoutSpa/ClientApp/components/fetch-data/fetch-data.ts +++ b/templates/KnockoutSpa/ClientApp/components/fetch-data/fetch-data.ts @@ -12,7 +12,7 @@ class FetchDataViewModel { public forecasts = ko.observableArray(); constructor() { - fetch('/api/SampleData/WeatherForecasts') + fetch('api/SampleData/WeatherForecasts') .then(response => response.json() as Promise) .then(data => { this.forecasts(data); diff --git a/templates/KnockoutSpa/ClientApp/components/nav-menu/nav-menu.html b/templates/KnockoutSpa/ClientApp/components/nav-menu/nav-menu.html index 0bfd32c..f053cef 100644 --- a/templates/KnockoutSpa/ClientApp/components/nav-menu/nav-menu.html +++ b/templates/KnockoutSpa/ClientApp/components/nav-menu/nav-menu.html @@ -13,17 +13,17 @@