single-spa-angular
Advanced tools
Comparing version 2.0.0 to 2.1.0
@@ -1,2 +0,2 @@ | ||
'use strict'; | ||
"use strict"; | ||
@@ -6,8 +6,10 @@ Object.defineProperty(exports, "__esModule", { | ||
}); | ||
exports.default = singleSpaAngular; | ||
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; | ||
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; var ownKeys = Object.keys(source); if (typeof Object.getOwnPropertySymbols === 'function') { ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) { return Object.getOwnPropertyDescriptor(source, sym).enumerable; })); } ownKeys.forEach(function (key) { _defineProperty(target, key, source[key]); }); } return target; } | ||
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; | ||
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } | ||
exports.default = singleSpaAngular; | ||
function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } | ||
var defaultOpts = { | ||
@@ -20,24 +22,30 @@ // required opts | ||
Router: null, | ||
ApplicationRef: null, | ||
domElementGetter: null // only optional if you provide a domElementGetter as a custom prop | ||
}; | ||
function singleSpaAngular(userOpts) { | ||
if ((typeof userOpts === 'undefined' ? 'undefined' : _typeof(userOpts)) !== 'object') { | ||
throw new Error('single-spa-angular requires a configuration object'); | ||
if (_typeof(userOpts) !== 'object') { | ||
throw new Error("single-spa-angular requires a configuration object"); | ||
} | ||
var opts = _extends({}, defaultOpts, userOpts); | ||
var opts = _objectSpread({}, defaultOpts, userOpts); | ||
if (!opts.angularPlatform) { | ||
throw new Error('single-spa-angular must be passed opts.angularPlatform. Usually this should be the return value of platformBrowserDynamic()'); | ||
throw new Error("single-spa-angular must be passed opts.angularPlatform. Usually this should be the return value of platformBrowserDynamic()"); | ||
} | ||
if (!opts.mainModule) { | ||
throw new Error('single-spa-angular must be passed opts.mainModule, which is the Angular module to bootstrap'); | ||
throw new Error("single-spa-angular must be passed opts.mainModule, which is the Angular module to bootstrap"); | ||
} | ||
if (typeof opts.template !== 'string') { | ||
throw new Error('single-spa-angular must be passed opts.template string'); | ||
throw new Error("single-spa-angular must be passed opts.template string"); | ||
} | ||
if (opts.Router && !opts.ApplicationRef || opts.ApplicationRef && !opts.Router) { | ||
throw Error('For @angular/router to work with single-spa, you must provide both the Router and ApplicationRef opts'); | ||
} | ||
return { | ||
@@ -51,3 +59,21 @@ bootstrap: bootstrap.bind(null, opts), | ||
function bootstrap(opts) { | ||
return Promise.resolve(); | ||
return Promise.resolve().then(function () { | ||
opts.routingEventListener = function (evt) { | ||
/* When popstate and hashchange events occur, single-spa delays them in order to | ||
* check which applications should be active and perform any necessary mounting/unmounting. | ||
* | ||
* ZoneJS freaks out about this because it hears about the events but it wasn't inside of a | ||
* Zone.current.run() block (or similar). I tried out modifying single-spa to call the event listener | ||
* inside of a Zone.run() block, but that didn't seem to help. I think if we could get that working | ||
* that it would be the best solution. | ||
* | ||
* I also tried out trying to detect with single-spa:routing-event events are the ones that actually | ||
* need to trigger an application tick, since not every one of them does. But I wasn't able to find a reliable | ||
* way of detecting it. So I fell back to just always causing an application tick, even though that's probably | ||
* not great for performance. | ||
*/ | ||
var applicationRef = opts.bootstrappedModule.injector.get(opts.ApplicationRef); | ||
applicationRef.tick(); | ||
}; | ||
}); | ||
} | ||
@@ -58,4 +84,5 @@ | ||
var domElementGetter = chooseDomElementGetter(opts, props); | ||
if (!domElementGetter) { | ||
throw new Error('cannot mount angular application \'' + (props.name || props.appName) + '\' without a domElementGetter provided either as an opt or a prop'); | ||
throw new Error("cannot mount angular application '".concat(props.name || props.appName, "' without a domElementGetter provided either as an opt or a prop")); | ||
} | ||
@@ -67,3 +94,9 @@ | ||
return opts.angularPlatform.bootstrapModule(opts.mainModule).then(function (module) { | ||
return opts.bootstrappedModule = module; | ||
opts.bootstrappedModule = module; | ||
if (opts.ApplicationRef) { | ||
window.addEventListener('single-spa:routing-event', opts.routingEventListener); | ||
} | ||
return module; | ||
}); | ||
@@ -74,10 +107,15 @@ }); | ||
function unmount(opts, props) { | ||
return new Promise(function (resolve, reject) { | ||
return Promise.resolve().then(function () { | ||
if (opts.Router) { | ||
// Workaround for https://github.com/angular/angular/issues/19079 | ||
var routerRef = opts.bootstrappedModule.injector.get(opts.Router); | ||
routerRef.dispose(); | ||
} | ||
if (opts.ApplicationRef) { | ||
window.removeEventListener('single-spa:routing-event', opts.routingEventListener); | ||
} | ||
opts.bootstrappedModule.destroy(); | ||
delete opts.bootstrappedModule; | ||
resolve(); | ||
}); | ||
@@ -88,4 +126,5 @@ } | ||
var element = domElementGetter(); | ||
if (!element) { | ||
throw new Error('domElementGetter did not return a valid dom element'); | ||
throw new Error("domElementGetter did not return a valid dom element"); | ||
} | ||
@@ -92,0 +131,0 @@ |
{ | ||
"name": "single-spa-angular", | ||
"version": "2.0.0", | ||
"version": "2.1.0", | ||
"description": "Helpers for building single-spa applications which use Angular 2", | ||
@@ -9,3 +9,3 @@ "main": "lib/single-spa-angular.js", | ||
"test": "echo \"Error: no test specified\" && exit 1", | ||
"prepublish": "npm run build" | ||
"prepublish": "yarn build" | ||
}, | ||
@@ -27,7 +27,7 @@ "repository": { | ||
"devDependencies": { | ||
"babel-cli": "^6.26.0", | ||
"babel-preset-latest": "^6.24.1", | ||
"babel-preset-stage-3": "^6.24.1", | ||
"@babel/cli": "^7.2.3", | ||
"@babel/core": "^7.2.2", | ||
"@babel/preset-env": "^7.2.3", | ||
"rimraf": "^2.6.2" | ||
} | ||
} |
@@ -8,3 +8,3 @@ # single-spa-angular | ||
## Example | ||
An example can be found in the [single-spa-examples](https://github.com/CanopyTax/single-spa-examples/blob/master/src/angular2/angular2.app.js) repository. | ||
An example can be found in the [single-spa-examples](https://github.com/CanopyTax/single-spa-examples/blob/master/src/angular/angular.app.js) repository. | ||
@@ -16,2 +16,3 @@ ## Quickstart | ||
import {platformBrowserDynamic} from '@angular/platform-browser-dynamic'; | ||
import {ApplicationRef} from '@angular/core'; | ||
import singleSpaAngular from 'single-spa-angular'; | ||
@@ -21,24 +22,13 @@ import mainModule from './main-module.ts'; | ||
const ngLifecycles = singleSpaAngular({ | ||
domElementGetter, | ||
mainModule, | ||
angularPlatform: platformBrowserDynamic(), | ||
template: `<component-to-render />`, | ||
Router, | ||
export default singleSpaAngular({ | ||
domElementGetter, | ||
mainModule, | ||
angularPlatform: platformBrowserDynamic(), | ||
template: `<component-to-render />`, | ||
Router, | ||
ApplicationRef, | ||
}) | ||
export const bootstrap = [ | ||
ngLifecycles.bootstrap, | ||
]; | ||
export const mount = [ | ||
ngLifecycles.mount, | ||
]; | ||
export const unmount = [ | ||
ngLifecycles.unmount, | ||
]; | ||
function domElementGetter() { | ||
return document.getElementById('angular'); | ||
return document.getElementById('angular'); | ||
} | ||
@@ -54,3 +44,4 @@ ``` | ||
- `template`: (required) An html string that will be put into the DOM Element returned by `domElementGetter`. This template can be anything, but it is recommended that you keeping it simple by making it only one Angular component. For example, `<my-component />` is recommended, but `<div><my-component /><span>Hello</span><another-component /></div>` is allowed. Note that `innerHTML` is used to put the template onto the DOM. | ||
- `Router`: (optional) The angular router class. If not provided, single-spa-angular will assume you are not using @angular/router. | ||
- `Router`: (optional) The angular router class. This is required when you are using `@angular/router` and must be used in conjunction with the `ApplicationRef` option. | ||
- `ApplicationRef`: (optional) The angular application ref interface. This is required when you are using `@angular/router` and must be used in conjunction with the `Router` option. | ||
- `domElementGetter`: (optional) A function that takes in no arguments and returns a DOMElement. This dom element is where the Angular application will be bootstrapped, mounted, and unmounted. | ||
@@ -57,0 +48,0 @@ Note that this opt can only be omitted when domElementGetter is passed in as a [custom prop](https://github.com/CanopyTax/single-spa/blob/master/docs/applications.md#custom-props). So you must either |
@@ -8,2 +8,3 @@ const defaultOpts = { | ||
Router: null, | ||
ApplicationRef: null, | ||
domElementGetter: null, // only optional if you provide a domElementGetter as a custom prop | ||
@@ -34,2 +35,6 @@ }; | ||
if (opts.Router && !opts.ApplicationRef || opts.ApplicationRef && !opts.Router) { | ||
throw Error('For @angular/router to work with single-spa, you must provide both the Router and ApplicationRef opts'); | ||
} | ||
return { | ||
@@ -43,3 +48,21 @@ bootstrap: bootstrap.bind(null, opts), | ||
function bootstrap(opts) { | ||
return Promise.resolve(); | ||
return Promise.resolve().then(() => { | ||
opts.routingEventListener = function(evt) { | ||
/* When popstate and hashchange events occur, single-spa delays them in order to | ||
* check which applications should be active and perform any necessary mounting/unmounting. | ||
* | ||
* ZoneJS freaks out about this because it hears about the events but it wasn't inside of a | ||
* Zone.current.run() block (or similar). I tried out modifying single-spa to call the event listener | ||
* inside of a Zone.run() block, but that didn't seem to help. I think if we could get that working | ||
* that it would be the best solution. | ||
* | ||
* I also tried out trying to detect with single-spa:routing-event events are the ones that actually | ||
* need to trigger an application tick, since not every one of them does. But I wasn't able to find a reliable | ||
* way of detecting it. So I fell back to just always causing an application tick, even though that's probably | ||
* not great for performance. | ||
*/ | ||
const applicationRef = opts.bootstrappedModule.injector.get(opts.ApplicationRef) | ||
applicationRef.tick() | ||
} | ||
}) | ||
} | ||
@@ -64,3 +87,7 @@ | ||
.then(module => { | ||
return opts.bootstrappedModule = module; | ||
opts.bootstrappedModule = module; | ||
if (opts.ApplicationRef) { | ||
window.addEventListener('single-spa:routing-event', opts.routingEventListener) | ||
} | ||
return module | ||
}) | ||
@@ -71,11 +98,14 @@ }) | ||
function unmount(opts, props) { | ||
return new Promise((resolve, reject) => { | ||
return Promise.resolve().then(() => { | ||
if (opts.Router) { | ||
// Workaround for https://github.com/angular/angular/issues/19079 | ||
const routerRef = opts.bootstrappedModule.injector.get(opts.Router); | ||
routerRef.dispose(); | ||
} | ||
if (opts.ApplicationRef) { | ||
window.removeEventListener('single-spa:routing-event', opts.routingEventListener) | ||
} | ||
opts.bootstrappedModule.destroy(); | ||
delete opts.bootstrappedModule; | ||
resolve(); | ||
}); | ||
}) | ||
} | ||
@@ -82,0 +112,0 @@ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
33319
211
50