Skip to content

Commit

Permalink
Drop support for route.bundle (#464)
Browse files Browse the repository at this point in the history
* chore: remove bundle logic

* chore: remove bundle docs

* chore: move dynamic imports doc to the top

* chore: regenerate analysis.json

* chore: remove bundle tests
  • Loading branch information
abdonrd authored Jan 29, 2021
1 parent 62bd9ab commit 9d98980
Show file tree
Hide file tree
Showing 7 changed files with 151 additions and 468 deletions.
206 changes: 103 additions & 103 deletions analysis.json

Large diffs are not rendered by default.

150 changes: 46 additions & 104 deletions demo/vaadin-router-code-splitting-demos.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,110 +6,6 @@
}
</style>

<h3>Lazy Loading JS Bundles</h3>
<p>
Vaadin Router works great with code splitting. If your build tool allows
you to split your code into various bundles which can then be loaded on
demand, Vaadin Router can load these bundled lazily just-in-time before
rendering a route.
In order to use this feature specify a bundle URL in the <code>bundle
</code> property of the route object.
</p>
<p>
By default Vaadin Router loads route bundles as regular JavaScript files (async),
but it supports ES module bundles as well. In order to use a ES module as a route bundle,
set the <code>bundle</code> property to an object with the following structure:
<marked-element>
<script type="text/markdown">
```js
{
bundle: {
module: '/bundle.esm.js', // for browsers supporting ES modules
nomodule: '/bundle.es5.js' // fallback for older browsers
}
}
```
</script>
</marked-element>
<p>
Note: If the bundle URL does not end with <code>.js</code> nor with <code>
.mjs</code>, Vaadin Router throws an <code>Error</code> and does not
attempt to load it. Use a custom route action as shown in the next demo if
you need to load non-js bundles.
</p>
<p>
This demo shows how to load the <code>user.bundle.js</code>
script which defines the custom element for the <code>/user/:id</code> route.
Check the network tab in the browser DevTools to see that the script is
loaded only after clicking the <code>/user/guest</code> link.
</p>
<vaadin-demo-snippet id="vaadin-router-code-splitting-1" iframe-src="iframe.html">
<template preserve-content>
<a href="/">Home</a>
<a href="/user/guest">User Profile</a>
<div id="outlet"></div>
<script>
// import {Router} from '@vaadin/router'; // for Webpack / Polymer CLI
// const Router = Vaadin.Router; // for vaadin-router.umd.js

const router = new Router(document.getElementById('outlet'));
router.setRoutes([
{path: '/', component: 'x-home-view'},
{
path: '/user/:id',
bundle: `${Vaadin.Demo.componentsRoot}/user.bundle.js`,
component: 'x-user-js-bundle-view' // <-- defined in the bundle
},
]);
</script>
</template>
</vaadin-demo-snippet>

<h3>Lazy Loading non-JS Bundles, e.g. HTML Imports</h3>
<p>
In cases when loading <code>.js</code> and <code>.mjs</code> is not
enough&mdash;most notably, when using HTML imports in Polymer-based
apps&mdash;the lazy loading feature can be implemented with a custom route
action (for more details see <a href="#vaadin-router-route-actions-demos">
Route Actions</a>).
</p>
<p>
This demo shows a way to lazily add an HTML import. The <code>user.bundle.html</code>
file contains entire Polymer 2 component definition including a template, a class,
and a script that defines a custom element.
</p>
<vaadin-demo-snippet id="vaadin-router-code-splitting-2" iframe-src="iframe.html">
<template preserve-content>
<link rel="import" href="../../polymer/lib/utils/import-href.html">
<a href="/">Home</a>
<a href="/user/admin">User Profile</a>
<div id="outlet"></div>
<script>
// import {Router} from '@vaadin/router'; // for Webpack / Polymer CLI
// const Router = Vaadin.Router; // for vaadin-router.umd.js

const loadCustomBundle = (context) => {
// This is one way of loading a bundle lazily (works for Polymer apps).
// Other apps might use different ways.
Polymer.importHref(
`${Vaadin.Demo.componentsRoot}/user.bundle.html`,
null,
function(err) {
throw new Error('bundle not found');
},
true
);
};

const router = new Router(document.getElementById('outlet'));
router.setRoutes([
{path: '/', component: 'x-home-view'},
{path: '/user/:id', action: loadCustomBundle, component: 'x-user-html-bundle-view'}
]);
</script>
</template>
</vaadin-demo-snippet>

<h3>Using Dynamic Imports</h3>
<p>
Vaadin Router allows you to implement your own loading mechanism for bundles using
Expand Down Expand Up @@ -198,6 +94,52 @@ <h3>Splitting and Lazy-Loading the Routes Configuration</h3>
</script>
</template>
</vaadin-demo-snippet>

<h3>Lazy Loading non-JS Bundles, e.g. HTML Imports</h3>
<p>
In cases when loading <code>.js</code> and <code>.mjs</code> is not
enough&mdash;most notably, when using HTML imports in Polymer-based
apps&mdash;the lazy loading feature can be implemented with a custom route
action (for more details see <a href="#vaadin-router-route-actions-demos">
Route Actions</a>).
</p>
<p>
This demo shows a way to lazily add an HTML import. The <code>user.bundle.html</code>
file contains entire Polymer 2 component definition including a template, a class,
and a script that defines a custom element.
</p>
<vaadin-demo-snippet id="vaadin-router-code-splitting-2" iframe-src="iframe.html">
<template preserve-content>
<link rel="import" href="../../polymer/lib/utils/import-href.html">
<a href="/">Home</a>
<a href="/user/admin">User Profile</a>
<div id="outlet"></div>
<script>
// import {Router} from '@vaadin/router'; // for Webpack / Polymer CLI
// const Router = Vaadin.Router; // for vaadin-router.umd.js

const loadCustomBundle = (context) => {
// This is one way of loading a bundle lazily (works for Polymer apps).
// Other apps might use different ways.
Polymer.importHref(
`${Vaadin.Demo.componentsRoot}/user.bundle.html`,
null,
function(err) {
throw new Error('bundle not found');
},
true
);
};

const router = new Router(document.getElementById('outlet'));
router.setRoutes([
{path: '/', component: 'x-home-view'},
{path: '/user/:id', action: loadCustomBundle, component: 'x-user-html-bundle-view'}
]);
</script>
</template>
</vaadin-demo-snippet>

</template>
<script>
class VaadinRouterCodeSplittingDemos extends DemoReadyEventEmitter(ElementDemo(Polymer.Element)) {
Expand Down
6 changes: 0 additions & 6 deletions interfaces.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,6 @@ declare module './dist/vaadin-router' {
name?: string;
// Route requires at least one of the following optional properties
action?: ActionFn;
bundle?: string;
children?: Route[] | ChildrenFn;
component?: string;
redirect?: string;
Expand All @@ -117,10 +116,6 @@ declare module './dist/vaadin-router' {
action: ActionFn;
}

interface RouteWithBundle extends BaseRoute {
bundle: string;
}

interface RouteWithChildren extends AnimatableRoute {
children: Route[] | ChildrenFn;
}
Expand All @@ -134,7 +129,6 @@ declare module './dist/vaadin-router' {
}

export type Route = RouteWithAction
| RouteWithBundle
| RouteWithChildren
| RouteWithComponent
| RouteWithRedirect
Expand Down
16 changes: 0 additions & 16 deletions src/router.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import animate from './transitions/animate.js';
import {
ensureRoute,
fireRouterEvent,
loadBundle,
log,
logValue,
toArray,
Expand Down Expand Up @@ -279,13 +278,6 @@ export class Router extends Resolver {
if (isString(route.redirect)) {
return commands.redirect(route.redirect);
}

if (route.bundle) {
return loadBundle(route.bundle)
.then(() => {}, () => {
throw new Error(log(`Bundle not found: ${route.bundle}. Check if the file name is correct`));
});
}
})
.then(result => {
if (isResultNotEmpty(result)) {
Expand Down Expand Up @@ -359,14 +351,6 @@ export class Router extends Resolver {
* The target route should also be defined.
* See also **Redirects** section in [Live Examples](#/classes/Router/demos/demo/index.html).
*
* * `bundle` – string containing the path to `.js` or `.mjs` bundle to load before resolving the route,
* or the object with "module" and "nomodule" keys referring to different bundles.
* Each bundle is only loaded once. If "module" and "nomodule" are set, only one bundle is loaded,
* depending on whether the browser supports ES modules or not.
* The property is ignored when either an `action` returns the result or `redirect` property is present.
* Any error, e.g. 404 while loading bundle will cause route resolution to throw.
* See also **Code Splitting** section in [Live Examples](#/classes/Router/demos/demo/index.html).
*
* * `component` – the tag name of the Web Component to resolve the route to.
* The property is ignored when either an `action` returns the result or `redirect` property is present.
* If route contains the `component` property (or an action that return a component)
Expand Down
74 changes: 2 additions & 72 deletions src/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,33 +20,18 @@ export function logValue(value) {
}
}

const MODULE = 'module';
const NOMODULE = 'nomodule';
const bundleKeys = [MODULE, NOMODULE];

function ensureBundle(src) {
if (!src.match(/.+\.[m]?js$/)) {
throw new Error(
log(`Unsupported type for bundle "${src}": .js or .mjs expected.`)
);
}
}

export function ensureRoute(route) {
if (!route || !isString(route.path)) {
throw new Error(
log(`Expected route config to be an object with a "path" string property, or an array of such objects`)
);
}

const bundle = route.bundle;

const stringKeys = ['component', 'redirect', 'bundle'];
const stringKeys = ['component', 'redirect'];
if (
!isFunction(route.action) &&
!Array.isArray(route.children) &&
!isFunction(route.children) &&
!isObject(bundle) &&
!stringKeys.some(key => isString(route[key]))
) {
throw new Error(
Expand All @@ -57,20 +42,8 @@ export function ensureRoute(route) {
);
}

if (bundle) {
if (isString(bundle)) {
ensureBundle(bundle);
} else if (!bundleKeys.some(key => key in bundle)) {
throw new Error(
log('Expected route bundle to include either "' + NOMODULE + '" or "' + MODULE + '" keys, or both')
);
} else {
bundleKeys.forEach(key => key in bundle && ensureBundle(bundle[key]));
}
}

if (route.redirect) {
['bundle', 'component'].forEach(overriddenProp => {
['component'].forEach(overriddenProp => {
if (overriddenProp in route) {
console.warn(
log(
Expand All @@ -87,49 +60,6 @@ export function ensureRoutes(routes) {
toArray(routes).forEach(route => ensureRoute(route));
}

function loadScript(src, key) {
let script = document.head.querySelector('script[src="' + src + '"][async]');
if (!script) {
script = document.createElement('script');
script.setAttribute('src', src);
if (key === MODULE) {
script.setAttribute('type', MODULE);
} else if (key === NOMODULE) {
script.setAttribute(NOMODULE, '');
}
script.async = true;
}
return new Promise((resolve, reject) => {
script.onreadystatechange = script.onload = e => {
script.__dynamicImportLoaded = true;
resolve(e);
};
script.onerror = e => {
if (script.parentNode) {
script.parentNode.removeChild(script);
}
reject(e);
};
if (script.parentNode === null) {
document.head.appendChild(script);
} else if (script.__dynamicImportLoaded) {
resolve();
}
});
}

export function loadBundle(bundle) {
if (isString(bundle)) {
return loadScript(bundle);
} else {
return Promise.race(
bundleKeys
.filter(key => key in bundle)
.map(key => loadScript(bundle[key], key))
);
}
}

export function fireRouterEvent(type, detail) {
return !window.dispatchEvent(new CustomEvent(
`vaadin-router-${type}`,
Expand Down
31 changes: 0 additions & 31 deletions test/router/lifecycle-events.spec.html
Original file line number Diff line number Diff line change
Expand Up @@ -1193,37 +1193,6 @@
});
});

describe('lifecycle events with bundle', () => {
const existingBundlePath = encodeURI('data:application/javascript,callbacksLog.push("bundle");//.js');
function getBundleScript() {
return document.head.querySelector('script[src="' + existingBundlePath + '"][async]');
}
afterEach(() => {
const bundleScript = getBundleScript();
if (bundleScript) {
bundleScript.parentNode.removeChild(bundleScript);
}
});

it('should invoke lifecycle events after bundle loading is complete', async() => {
router.setRoutes([
{path: '/', component: 'x-home-view'},
{path: '/x-spy', bundle: existingBundlePath, component: 'x-spy'}
]);

await router.render('/');
callbacksLog = [];
await router.render('/x-spy');

verifyCallbacks([
'bundle',
'x-spy.onBeforeEnter',
'x-spy.connectedCallback',
'x-spy.onAfterEnter'
]);
});
});

describe('lifecycle events with action', () => {
it('lifecycle events when reusing element (#355)', async() => {
const view = document.createElement('x-spy');
Expand Down
Loading

0 comments on commit 9d98980

Please sign in to comment.