2. Hi, I’m Brecht! I help
companies with web
technologies...
@brechtbilliet
3. I... A few references...
» Kickstart projects
» Give trainings/workshops
» Coach companies
» Do code-reviews
» Do audits
» Blog about stuff
http://blog.brecht.io
» Talk on meetups
» Help with architectural
decisions
@brechtbilliet
10. We can do
this!
We can do
this!
REST
Backend Web application
Frontend Web application
(spa)
@brechtbilliet
11. We can
still do
this!
We can do
this!
We can do
this!
REST
Backend Web application
We can
still do
this!
Frontend Web application
(spa)
@brechtbilliet
12. We can
still do
this!
We can do
this!
We can do
this!
REST
Backend Web application
We can
still do
this!
Err...
Err...
Frontend Web application
(spa)
@brechtbilliet
13. Spotify engineering culture
» Autonomous teams
» Every team has its own
⋄ Ownership
⋄ Codebase
⋄ Build process
⋄ Deployment
» Choice of tech-stack
» Checkout these movies
» https://labs.spotify.com/
2014/03/27/spotify-
engineering-culture-part-
1/
» https://labs.spotify.com/
2014/09/20/spotify-
engineering-culture-part-
2/
@brechtbilliet
20. We want
» Code splitting
» Code sharing
» Decoupling
» Lazy loading
» Separate codebases
» To divide work in
different teams
» To give ownership to
specific teams
@brechtbilliet
32. How to communicate between the
iframes
// send a message from iframe to the orchestrator app for communication
window.parent.postMessage({type: 'PLAY_SONG', data: {'title': 'Michael Jackson -
Billy Jean'}}, '*');
@brechtbilliet
33. How to communicate between the
iframes
// send a message from iframe to the orchestrator app for communication
window.parent.postMessage({type: 'PLAY_SONG', data: {'title': 'Michael Jackson -
Billy Jean'}}, '*');
// send a message to the orchestrator app for communication
window.addEventListener('message', receiveMessage, false);
function receiveMessage(msg): void {
switch(event.data.type){
case 'PLAY_SONG':
// todo (set some label or whatever)
}
@brechtbilliet
34. Reactive is cooler =)
// get a stream from all messages
postMessage$ = Observable.fromEvent(window, 'message').map(res => res.data);
// get a stream of the 'PLAY_SONG' messages
playSongMessage$ = postMessage$.filter(item => item.type === 'PLAY_SONG');
@brechtbilliet
35. Advantages
» Great isolation of code => assign to specific
teams
» Not tied to specific framework
» Works with all different javascript technologies
» Independant deploys
» Ability to migrate old project easily
» Easy to plug-and-play in older projects
» AB-testing becomes a breeze
» No code conflicts
» Iframes have their own inside routing
@brechtbilliet
36. Tradeoffs
» Performance hit (manageable in most cases)
» CSS issues, tooltips behind the iframe, ...
» Drag and drop (can be fixed, but not native)
» Dependencies will be loaded multiple times
» Harder to share state
» Only works for block-shaped elements
@brechtbilliet
37. Use cases
» Legacy code bases: Add ng4 project into old app in 1 line
» Platforms
⋄ One application per tab
⋄ Multiple applications per tab
» Independant deploys of projects
Don’t overuse it!
@brechtbilliet
38. Summary
» Use it for specific projects (platforms, legacy
codebases)
» Becomes complex when too many shared state…
» Share backend changes over sockets
» Share state changes over document-events
@brechtbilliet
45. How to load multiple angular
apps
Ng4 app (cli)
Ng4 app (cli)
@brechtbilliet
46. How to load multiple angular
apps
<!doctype html>
<html>
<head>
</head>
<body>
<!--These should come from a shared bundle-->
<script type="text/javascript" src="somesharedbundle/dist/inline.bundle.js"></script>
<!--Polyfills can only be loaded ONCE!!-->
<script type="text/javascript" src="somesharedbundle/dist/polyfills.bundle.js"></script>
...
</body>
</html>
@brechtbilliet
47. How to load multiple angular
apps
// create the DOM tag
document.body.appendChild(document.createElement('app-courses'));
// load the script from the dist folder
loadScriptsSync(['courses/dist/inline.bundle.js',
'courses/dist/vendor.bundle.js',
'courses/dist/main.bundle.js']);
// create the DOM tag
document.body.appendChild(document.createElement('app-users'));
// load the script from the dist folder
loadScriptsSync(['users/dist/inline.bundle.js',
'users/dist/vendor.bundle.js',
'users/dist/main.bundle.js']);
@brechtbilliet
48. How to load multiple angular
apps
// It’s important that the script are loaded synchronous
function loadScript(path, cb) {
var scriptTag = document.createElement('script');
scriptTag.src = path;
scriptTag.onload = cb;
scriptTag.onreadystatechange = cb;
document.body.appendChild(scriptTag);
}
function loadScriptsSync(paths) {
loadScript(paths[0], () => {
loadScriptsSync(paths.filter(item => item !== paths[0]));
});
}
@brechtbilliet
49. Advantages
» You don’t need iframes to load multiple angular
apps
» You can easily divide the work between teams
» Independant deploys
@brechtbilliet
50. Tradeoffs
» No routing inside the child-apps
» Can’t have multiple instances of a child-app
» Not completely sandboxed
» Dependencies will be loaded multiple times
@brechtbilliet
51. Summary
» Some people are for it, some are against it
» A personal feeling: It feels a bit hacky
» You can use it when you hit the limitations of an
iframe (e.g css)
» Routing is impossible
@brechtbilliet
58. Angular (>2) is made for large
apps
It’s build as a platform framework
It’s build for large teams (typescript, modules, DI)
Provides:
» Modules with great encapsulation
» Lazy loading
» Ahead-of-time compilation
» A CLI (to reduce the setup process to a minimum)
@brechtbilliet
61. What does a module look like?
Every module has
» Its own package.json
» Its own build process
» Its own test
environment
» Its own versions
» Its own test suite
» Its own repo
(debatable)
So we can:
» Assign a specific team
» Have separate deploy
to specific NPM
registry
» Lazy load them
@brechtbilliet
62. The orchestration App:
Module
...
import { routing } from './routes';
import { SpotifySearchModule } from '@spotify-app/spotify-search'; // Npm package
import { SpotifyPlayerModule } from '@spotify-app/spotify-player'; // Npm package
@NgModule({
...
imports: [
routing, // here we lazy load our modules
SpotifySearchModule, // directly import the angular module from npm
SpotifyPlayerModule, // directly import the angular module from npm
BrowserModule,
...
]
})
export class MainModule {
64. Creating a child-module
» ng new spotify-player
» Rename src to testenv
» Create folder src, and move the source code there
» Change the .angular-cli.json root property in “app”
to “testenv”
@brechtbilliet
65. Just use the source code (no
build)
» Set the Package.json main property to src/index.js
index.js:
export {AppModule} from './app/app.module';
@brechtbilliet
66. Advantages
» Lazy loading out of the box
» Module system out of the box
» Creating projects is easy with the CLI
» Routing + child-routing works perfectly
@brechtbilliet
67. Tradeoffs
» For every module deploy you also have to deploy
the root application
» Bound to a framework (debatable)
» Not easy to combine with AOT
» Not completely sandboxed, but angular provides
great encapsulation
@brechtbilliet
77. Divide in teams again =)
import { SearchModule } from '@spotify-app/spotify-search';
import { MainModule } from '@spotify-app/spotify-main';
import { PlayerModule } from '@spotify-app/spotify-player';
@NgModule({
...
imports: [BrowserModule, SpotifySearchModule, SpotifyMainModule, SpotifyPlayerModule],
bootstrap: [SearchComponent, MainComponent, PlayerComponent]
})
export class AppModule {
}
@brechtbilliet
78. Advantages
» You can use multiple ng4 apps (as components) in
a non angular application
» You can combine it with the angular modules
approach (same advantages)
@brechtbilliet
79. Tradeoffs
» Iframes still provide better encapsulation
» No independant deploys (only to npm)
@brechtbilliet
83. Credits
This template is free to use under Creative Commons Attribution license.
Thank you 4 having me!
@brechtbilliet
https://www.linkedin.com/in/brecht-billiet-58417426/
billietbrecht@gmail.com
http://brecht.io
http://blog.brecht.io
http://strongbrew.io
@brechtbilliet