Permalink
Browse files

use code splitting to dynamically load javascript based on route

  • Loading branch information...
dstaley committed Feb 13, 2017
1 parent 470b55e commit 4776bf964a35c9b2b87b54db066ad8558b9727e2
Showing with 55 additions and 70 deletions.
  1. +55 −70 assets/js/app.js
View
@@ -1,73 +1,56 @@
import 'babel-polyfill';
import $ from 'jquery';
import async from 'async';
import account from './theme/account';
import auth from './theme/auth';
import blog from './theme/blog';
import brand from './theme/brand';
import cart from './theme/cart';
import category from './theme/category';
import contactUs from './theme/contact-us';
import compare from './theme/compare';
import errors from './theme/errors';
import errors404 from './theme/404-error';
import giftCertificate from './theme/gift-certificate';
import global from './theme/global';
import home from './theme/home';
import orderComplete from './theme/order-complete';
import rss from './theme/rss';
import page from './theme/page';
import product from './theme/product';
import search from './theme/search';
import sitemap from './theme/sitemap';
import subscribe from './theme/subscribe';
import wishlist from './theme/wishlist';

This comment has been minimized.

Show comment
Hide comment
@dstaley

dstaley Feb 13, 2017

Owner

Since these are all now loaded dynamically, we don't need to import them (or else they'd get added to our main bundle).

@dstaley

dstaley Feb 13, 2017

Owner

Since these are all now loaded dynamically, we don't need to import them (or else they'd get added to our main bundle).

const scriptURL = document.currentScript.src;
// eslint-disable-next-line camelcase, no-undef
__webpack_public_path__ = scriptURL.slice(0, scriptURL.lastIndexOf('/') + 1);

This comment has been minimized.

Show comment
Hide comment
@dstaley

dstaley Feb 13, 2017

Owner

By default, Webpack expects bundles to be located at the root of the current page. We could manually specify a directory, but Stencil's path is dynamic. So, instead we use a little known feature to find out the path of the entry point bundle, and then set that as our path to load modules from.

@dstaley

dstaley Feb 13, 2017

Owner

By default, Webpack expects bundles to be located at the root of the current page. We could manually specify a directory, but Stencil's path is dynamic. So, instead we use a little known feature to find out the path of the entry point bundle, and then set that as our path to load modules from.

const PageClasses = {
mapping: {
'pages/account/orders/all': account,
'pages/account/orders/details': account,
'pages/account/addresses': account,
'pages/account/add-address': account,
'pages/account/add-return': account,
'pages/account/add-wishlist': wishlist,
'pages/account/recent-items': account,
'pages/account/download-item': account,
'pages/account/edit': account,
'pages/account/inbox': account,
'pages/account/return-saved': account,
'pages/account/returns': account,
'pages/auth/login': auth,
'pages/auth/account-created': auth,
'pages/auth/create-account': auth,
'pages/auth/new-password': auth,
'pages/auth/forgot-password': auth,
'pages/blog': blog,
'pages/blog-post': blog,
'pages/brand': brand,
'pages/brands': brand,
'pages/cart': cart,
'pages/category': category,
'pages/compare': compare,
'pages/contact-us': contactUs,
'pages/errors': errors,
'pages/errors/404': errors404,
'pages/gift-certificate/purchase': giftCertificate,
'pages/gift-certificate/balance': giftCertificate,
'pages/gift-certificate/redeem': giftCertificate,
'pages/account/orders/all': () => System.import('./theme/account'),
'pages/account/orders/details': () => System.import('./theme/account'),
'pages/account/addresses': () => System.import('./theme/account'),
'pages/account/add-address': () => System.import('./theme/account'),
'pages/account/add-return': () => System.import('./theme/account'),
'pages/account/add-wishlist': () => System.import('./theme/wishlist'),
'pages/account/recent-items': () => System.import('./theme/account'),
'pages/account/download-item': () => System.import('./theme/account'),
'pages/account/edit': () => System.import('./theme/account'),
'pages/account/inbox': () => System.import('./theme/account'),
'pages/account/return-saved': () => System.import('./theme/account'),
'pages/account/returns': () => System.import('./theme/account'),
'pages/auth/login': () => System.import('./theme/auth'),
'pages/auth/account-created': () => System.import('./theme/auth'),
'pages/auth/create-account': () => System.import('./theme/auth'),
'pages/auth/new-password': () => System.import('./theme/auth'),
'pages/auth/forgot-password': () => System.import('./theme/auth'),
'pages/blog': () => System.import('./theme/blog'),
'pages/blog-post': () => System.import('./theme/blog'),
'pages/brand': () => System.import('./theme/brand'),
'pages/brands': () => System.import('./theme/brand'),
'pages/cart': () => System.import('./theme/cart'),
'pages/category': () => System.import('./theme/category'),
'pages/compare': () => System.import('./theme/compare'),
'pages/contact-us': () => System.import('./theme/contact-us'),
'pages/errors': () => System.import('./theme/errors'),
'pages/errors/404': () => System.import('./theme/404-error'),
'pages/gift-certificate/purchase': () => System.import('./theme/gift-certificate'),
'pages/gift-certificate/balance': () => System.import('./theme/gift-certificate'),
'pages/gift-certificate/redeem': () => System.import('./theme/gift-certificate'),

This comment has been minimized.

Show comment
Hide comment
@dstaley

dstaley Feb 13, 2017

Owner

Instead of a reference to the page's module, we set the page keys to functions that return the System.import promise. Those promises resolve to the page's module.

@dstaley

dstaley Feb 13, 2017

Owner

Instead of a reference to the page's module, we set the page keys to functions that return the System.import promise. Those promises resolve to the page's module.

// eslint-disable-next-line
'global': global,

This comment has been minimized.

Show comment
Hide comment
@dstaley

dstaley Feb 13, 2017

Owner

Because global is used for every page, we don't want to request it dynamically. By including it here, it gets bundled into the main bundle.

@dstaley

dstaley Feb 13, 2017

Owner

Because global is used for every page, we don't want to request it dynamically. By including it here, it gets bundled into the main bundle.

'pages/home': home,
'pages/order-complete': orderComplete,
'pages/page': page,
'pages/product': product,
'pages/search': search,
'pages/rss': rss,
'pages/sitemap': sitemap,
'pages/subscribed': subscribe,
'pages/account/wishlist-details': wishlist,
'pages/account/wishlists': wishlist,
'pages/home': () => System.import('./theme/home'),
'pages/order-complete': () => System.import('./theme/order-complete'),
'pages/page': () => System.import('./theme/page'),
'pages/product': () => System.import('./theme/product'),
'pages/search': () => System.import('./theme/search'),
'pages/rss': () => System.import('./theme/rss'),
'pages/sitemap': () => System.import('./theme/sitemap'),
'pages/subscribed': () => System.import('./theme/subscribe'),
'pages/account/wishlist-details': () => System.import('./theme/wishlist'),
'pages/account/wishlists': () => System.import('./theme/wishlist'),
},
/**
* Getter method to ensure a good page type is accessed.
@@ -140,18 +123,20 @@ window.stencilBootstrap = function stencilBootstrap(templateFile, contextJSON =
return {
load() {
$(() => {
const PageTypeFn = pages.get(templateFile); // Finds the appropriate module from the pageType object and store the result as a function.
if (PageTypeFn) {
const pageType = new PageTypeFn(context);
document.addEventListener('DOMContentLoaded', () => {
const pageTypePromise = pages.get(templateFile);
if (pageTypePromise !== false) {
pageTypePromise().then(PageTypeFn => {
// eslint-disable-next-line new-cap
const pageType = new PageTypeFn.default(context);

This comment has been minimized.

Show comment
Hide comment
@dstaley

dstaley Feb 13, 2017

Owner

Because Jquery is only being used in this file to add a ready handler, we instead replace it with a DOMContentLoaded listener. We then load the function for the specific page type. We then call the function and await the resolution of the promise. Once the promise resolves with the page's module, we call the module's default export with the context of the page.

@dstaley

dstaley Feb 13, 2017

Owner

Because Jquery is only being used in this file to add a ready handler, we instead replace it with a DOMContentLoaded listener. We then load the function for the specific page type. We then call the function and await the resolution of the promise. Once the promise resolves with the page's module, we call the module's default export with the context of the page.

pageType.context = context;
pageType.context = context;
return loader(pageType, pages);
return loader(pageType, pages);
});
} else {
throw new Error(`${templateFile} Module not found`);
}
throw new Error(`${templateFile} Module not found`);
});
},
};

0 comments on commit 4776bf9

Please sign in to comment.