diff --git a/templates/KnockoutSpa/ClientApp/boot.ts b/templates/KnockoutSpa/ClientApp/boot.ts index e0346aa..66740eb 100644 --- a/templates/KnockoutSpa/ClientApp/boot.ts +++ b/templates/KnockoutSpa/ClientApp/boot.ts @@ -3,6 +3,7 @@ import 'bootstrap/dist/css/bootstrap.css'; import './css/site.css'; import * as ko from 'knockout'; import { createHistory } from 'history'; +import './webpack-component-loader'; // Load and register the component ko.components.register('app-root', require('./components/app-root/app-root').default); diff --git a/templates/KnockoutSpa/ClientApp/components/app-root/app-root.ts b/templates/KnockoutSpa/ClientApp/components/app-root/app-root.ts index bf8cd8f..2d05cb1 100644 --- a/templates/KnockoutSpa/ClientApp/components/app-root/app-root.ts +++ b/templates/KnockoutSpa/ClientApp/components/app-root/app-root.ts @@ -1,5 +1,6 @@ import * as ko from 'knockout'; import { Route, Router } from '../../router'; +import navMenu from '../nav-menu/nav-menu'; // Declare the client-side routing configuration const routes: Route[] = [ @@ -18,10 +19,13 @@ class AppRootViewModel { this.route = this._router.currentRoute; // Load and register all the KO components needed to handle the routes - ko.components.register('nav-menu', require('../nav-menu/nav-menu').default); - ko.components.register('home-page', require('../home-page/home-page').default); - ko.components.register('counter-example', require('../counter-example/counter-example').default); - ko.components.register('fetch-data', require('../fetch-data/fetch-data').default); + // The optional 'bundle?lazy!' prefix is a Webpack feature that causes the referenced modules + // to be split into separate files that are then loaded on demand. + // For docs, see https://github.com/webpack/bundle-loader + ko.components.register('nav-menu', navMenu); + ko.components.register('home-page', require('bundle?lazy!../home-page/home-page')); + ko.components.register('counter-example', require('bundle?lazy!../counter-example/counter-example')); + ko.components.register('fetch-data', require('bundle?lazy!../fetch-data/fetch-data')); } // To support hot module replacement, this method unregisters the router and KO components. diff --git a/templates/KnockoutSpa/ClientApp/components/home-page/home-page.html b/templates/KnockoutSpa/ClientApp/components/home-page/home-page.html index 6aad35c..4624268 100644 --- a/templates/KnockoutSpa/ClientApp/components/home-page/home-page.html +++ b/templates/KnockoutSpa/ClientApp/components/home-page/home-page.html @@ -11,5 +11,6 @@
  • Client-side navigation. For example, click Counter then Back to return here.
  • Webpack dev middleware. In development mode, there's no need to run the webpack build tool. Your client-side resources are dynamically built on demand. Updates are available as soon as you modify any file.
  • Hot module replacement. In development mode, you don't even need to reload the page after making most changes. Within seconds of saving changes to files, your Knockout app will be rebuilt and a new instance injected is into the page.
  • +
  • Code splitting and lazy loading. KO components may optionally be bundled individually and loaded on demand. For example, the code and template for 'Counter' is not loaded until you navigate to it..
  • Efficient production builds. In production mode, development-time features are disabled, and the webpack build tool produces minified static CSS and JavaScript files.
  • diff --git a/templates/KnockoutSpa/ClientApp/webpack-component-loader.ts b/templates/KnockoutSpa/ClientApp/webpack-component-loader.ts new file mode 100644 index 0000000..d46ec82 --- /dev/null +++ b/templates/KnockoutSpa/ClientApp/webpack-component-loader.ts @@ -0,0 +1,25 @@ +import * as ko from 'knockout'; + +// This Knockout component loader integrates with Webpack's lazy-loaded bundle feature. +// Having this means you can optionally declare components as follows: +// ko.components.register('my-component', require('bundle?lazy!../some-path-to-a-js-or-ts-module')); +// ... and then it will be loaded on demand instead of being loaded up front. +ko.components.loaders.unshift({ + loadComponent: (name, componentConfig, callback) => { + if (typeof componentConfig === 'function') { + // It's a lazy-loaded Webpack bundle + (componentConfig as any)(loadedModule => { + // Handle TypeScript-style default exports + if (loadedModule.__esModule && loadedModule.default) { + loadedModule = loadedModule.default; + } + + // Pass the loaded module to KO's default loader + ko.components.defaultLoader.loadComponent(name, loadedModule, callback); + }); + } else { + // It's something else - let another component loader handle it + callback(null); + } + } +}); diff --git a/templates/KnockoutSpa/package.json b/templates/KnockoutSpa/package.json index a9a16a9..39f6bff 100644 --- a/templates/KnockoutSpa/package.json +++ b/templates/KnockoutSpa/package.json @@ -19,6 +19,7 @@ "webpack-hot-middleware": "^2.7.1" }, "dependencies": { + "bundle-loader": "^0.5.4", "crossroads": "^0.12.2", "domain-task": "^1.0.0", "es6-promise": "^3.1.2",