• Stars
    star
    163
  • Rank 231,141 (Top 5 %)
  • Language
    JavaScript
  • License
    MIT License
  • Created over 10 years ago
  • Updated over 1 year ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Lazy load isolated micro-apps in Angular

Angular Widget Build Status Coverage Status

Lazy load isolated micro-apps in Angular

Demo: http://shahata.github.io/angular-widget/

Slides: https://slides.com/shahartalmi/angular-widget/

Talk (English - Bad quality): https://youtu.be/D8fOHIwz8mY

Talk (Hebrew): http://youtu.be/Wgn2Vid8zCA

What it does

One of the main problems people discover in angular when they try to write a very big application with all sorts of components, is that you can't load code during run-time easily. When angular bootstraps your DOM, it creates an injector with the configuration that was defined at that moment and you cannot add services, directives, controllers, etc. easily after the injector was created. This library allows you to download js/css/html code into a running angular app and will create a new injector for that "widget". Since each widget has its own injector, each widget has a different instance for services that they use. They can configure them how ever they like without any effect on any other widget or on the main application that hosts the widgets. Regardless, all widgets share the same DOM, so a widget create modal dialogs or whatever it likes. Widgets are simply added to the DOM using the ng-widget directive. The directive download all required files and creates the widget. Widgets can get information from the hosting application using the options attribute of the directive and they can report to the hosting application using widgetConfig.exportProperties and widgetConfig.reportError.

But that's just the start! Widgets can actually be full blown applications with their own router. (both angular-route and ui-router are supported) See the demo page for an example that uses angular-route to host three lazy loaded applications - one uses ui-router internally, one uses angular-route and the third displays some widget (widgets within widgets, whoa...)

See https://github.com/wix/angular-widget/blob/master/app/scripts/demo.js for an example of how you would typically configure a hosting application to run multiple lazy loaded applications on different routes.

Installation

Install using bower

bower install --save angular-widget

Include script tag in your html document.

<script type="text/javascript" src="bower_components/angular-widget/angular-widget.js"></script>

Add a dependency to your application module.

angular.module('myApp', ['angularWidget']);

Directive Usage

<ng-widget src="'demo'" options="{name: 'value'}"></ng-widget>

Arguments

Param Type Details
src string Name of widget to download. This is resolved to a module name, html file url and js/css file url list when the directive invokes widgets.getWidgetManifest(src) (more on this soon)
options (optional) object An object of options which might effect the behavior of the widget. The widget gets those options by calling widgetConfig.getOptions() (more on this soon)
delay (optional) number Well, that's pretty silly, but with widgets you sometimes want to let the user feel that the widget is actually loading. So you can add a delay with this param

Events

The directive emits the following events:

Param Details
widgetLoading Sent when the widget loading starts
widgetLoaded Sent when the widget is done loading. This happens when all the files were downloaded and the new DOM node was bootstrapped. In case the widget itself wants to postpone sending this event until it is done initializing, it can optionally call widgetConfig.exportProperties({loading: true} in a run block and then call widgetConfig.exportProperties({loading: false } when done
widgetError Sent when some download or bootstrap fails. Called also when the widget calls widgetConfig.reportErrror()
exportPropertiesUpdated Sent along with the updated properties when the widget calls widgetConfig.exportProperties()

The directive will reload the widget if it receives a reloadWidget event from a parent scope.

Service Usage (hosting application)

angular.module('myApp').config(function (widgetsProvider) {
  widgetsProvider.setManifestGenerator(['dep1', 'dep1', function (dep1, dep2) {
    return function (name) {
      return {
        module: name + 'Widget',
        config: [], //optional array of extra modules to load into the new injector
        priority: 1, //optional priority for conflicting generators
        html: 'views/' + name + '.html',
        files: [
          'scripts/controllers/' + name + '.js',
          'styles/' + name + '.css'
        ]
      };
    };
  }]);
})

Arguments

You must set the manifest generator function in order for the directive to work. This is how we can know for a specific plugin, what files should be loaded and with which module name to create the injector. Above you can see an example for a manifest generator, but you can do whatever you like. You can put both relative and absolute URL's, of course.

Note: In case requirejs is available in the global scope, it will be used to load the javascript files. So if your widget needs more than one js file, you can include requirejs and use AMD to load them.

You can actually set multiple manifest generators and they will be evaluated in the order that they were defined. So a generator is allowed to return undefined in case it simply wants a different generator to handle it. The way the generators responses are handled is that the last generator that didn't return undefined will be used, unless a different generator returned a result with higher priority.

Service Usage (widget)

In order to communicate with the hosting application, the widget uses the widgetConfig service. (the widget module always has a module dependency on angularWidget, if no such dependency exists, it will be added automatically during bootstrap)

Methods

Name Param Details
exportProperties properties (obj) Send information to the hosting application. The object sent in the param will extend previous calls, so you can send only the properties that have changed. The directive will emit a exportPropertiesUpdated event.
reportError N/A Report some kind of error to the hosting application. The directive will emit a widgetError event.
getOptions N/A Get the options object supplied by the object. The options will always have the same reference, so you can save it on the scope. A scope digest will be triggered automatically if the options change.

Sharing information between widgets

In some cases it might be needed to share some global state between widgets. When this global state changes you'll probably need to run a digest cycle in all widgets. $rootScope.$digest() will run the digest only in the injector which owns that $rootScope instance. To run $rootScope.$digest() on all $rootScope instances in all widgets, use widgtes.notifyWidgtes().

Also, if you want to broadcast an event on the $rootScope of all widgets, just call widgets.notifyWidgets(eventName, args, ...). It returns an array of the scope event that were dispatched.

Sharing services

As mentioned before, each widget has its very own injector, which means that each widget has its own service instances which are isolated from the services of other widgets and of the hosting application. A nice way to share information between widgets and the the hosting application is to have a shared service instance. So you can ask angular-widget to have the service shared pretty easily by running widgetsProvider.addServiceToShare(name, description) in a config section of the hosting application - name is the name of the service you want to share, that's pretty obvious, but description (optional) is a bit more difficult to explain.

It is important to remember that the widgets and hosting application do not share the same digest cycle, so if you are going to make a call to a shared service from a widget, you want to trigger a digest in all root scopes that share this service instance. You could just call widgets.notifyWidgets(), but an easier way would be to declare which methods of the shared service might change the state (no need to mention getters, for example) and have angular-widget do the rest for you. So description can be an array of such method names, or it can be an object where the method name is the key and the minimum amount of arguments is the value. The object option should be used when you have something like methods that behave as getters when they have no arguments and as setters when they have one arguments. (in this case you would pass {methodName: 1} as description)

BTW, one service that is shared by default in order for angular-widget to work is $location.

Sharing events

One more important option to share information between widgets and the main application are scope events. Since the widgets have a different injector, their root scope is isolated from scope events in different injectors, but this can easily be changed by adding widgetsProvider.addEventToForward(name) in a config section of the hosting application. This will make the ngWidget directive propagate events with this name to the widget's root scope. The widget may call preventDefault() on the event in order to prevent the default behavior of the original event.

BTW, one event that is shared by default is $locationChangeStart. This is in order to allow widgets to preventDefault() and display some "you have unsaved changes" dialog if they want to. If the user decides to continue, the widget can do something like $location.$$parse(absUrl). (absUrl is the first parameter passed along with the $locationChangeStart event) Calling $$parse will trigger a digest in the hosting application automatically as described in the previous section, since this service is shared by default.

How to use in the real world

This framework is best used by having a separate project for each widget. During development, the developer sees only his own widget. All widgets should be built in a consistent manner, usually with one concatenated minified .js and .css files.

License

The MIT License.

See LICENSE

More Repositories

1

react-native-interactable

Experimental implementation of high performance interactable views in React Native
JavaScript
5,179
star
2

react-templates

Light weight templates for react
JavaScript
2,813
star
3

vscode-glean

The extension provides refactoring tools for your React codebase
TypeScript
1,461
star
4

mjml-react

React component library to generate the HTML emails on the fly
JavaScript
992
star
5

react-native-zss-rich-text-editor

React Native rich text editor based on ZSSRichTextEditor
HTML
841
star
6

react-native-keyboard-input

Use your own custom input component instead of the system keyboard
Objective-C
797
star
7

wml

An alternative to symlinks that actually copies changed files from source to destination folders
JavaScript
769
star
8

angular-tree-control

Angular JS Tree
HTML
709
star
9

DetoxInstruments

Detox Instruments is a performance–analysis and testing framework, designed to help developers profile their mobile apps in order to better understand and optimize their app's behavior and performance.
Objective-C
621
star
10

react-native-controllers

Native IOS Navigation for React Native (navbar, tabs, drawer)
Objective-C
610
star
11

react-native-autogrow-textinput

Objective-C
542
star
12

react-native-crash-course

The React Native crash course by Wix is a self-learning course designed to help you learn everything you need to know before diving into writing production code in React Native.
JavaScript
541
star
13

accord

Accord: A sane validation library for Scala
Scala
534
star
14

react-native-keyboard-aware-scrollview

Created by artald
JavaScript
490
star
15

wix-embedded-mysql

embedded mysql based on https://github.com/flapdoodle-oss/de.flapdoodle.embed.process
Java
382
star
16

DetoxRecorder

Detox Recorder is a utility for recordings steps for a Detox test as you use your app in Simulator. After recording the test, add expectations that check if interface elements are in the expected state.
Objective-C
286
star
17

react-dataflow-example

Experimenting with different dataflow approaches for a real life React app
JavaScript
279
star
18

eslint-plugin-lodash

ESLint rules for lodash
JavaScript
276
star
19

pro-gallery

Blazing fast & beautiful galleries built for the web
JavaScript
270
star
20

quix

Quix Notebook Manager
TypeScript
267
star
21

petri

Wix experiment system (A/B test and feature toggle framework)
JavaScript
264
star
22

redux-saga-tester

Full redux environment testing helper for redux-saga
JavaScript
249
star
23

react-native-wordpress-editor

React Native Wrapper for WordPress Rich Text Editor
Objective-C
246
star
24

redux-testkit

Complete and opinionated testkit for testing Redux projects (reducers, selectors, actions, thunks)
JavaScript
226
star
25

remx

Opinionated mobx
JavaScript
224
star
26

exodus

Easily migrate your JVM code from Maven to Bazel
Scala
222
star
27

react-native-action-view

An easy to use component that allows displaying swipeable buttons with a variety of transitions.
Objective-C
187
star
28

tdd-katas

TDD katas
JavaScript
175
star
29

repluggable

Pluggable micro frontends in React+Redux apps
TypeScript
170
star
30

react-native-custom-segmented-control

Custom version of the IOS SegmentedControl component
Objective-C
168
star
31

lerna-script

Lerna addon for adding custom tasks
JavaScript
164
star
32

react-native-wix-engine

Java
164
star
33

angular-viewport-watch

Angular directive that disables watchers in scopes out of viewport
JavaScript
148
star
34

kampos

Tiny and fast effects compositor on WebGL
JavaScript
134
star
35

react-native-keyboard-tracking-view

Objective-C
134
star
36

react-native-swipe-view

Native container for a React Native view which supports swipe behavior (for swipe to delete and such)
Java
124
star
37

list-view-experiments

React Native ListView Experiments
Objective-C
123
star
38

rn-perf-experiments

Various performance experiments with React Native over a swipeable card pattern
JavaScript
119
star
39

rn-perf-experiments2

React Native performance experiments revisited
JavaScript
115
star
40

codio

A media format to record and playback the process of programming
Kotlin
107
star
41

rn-synchronous-render

Experiments with synchronous rendering in React Native
Objective-C
104
star
42

react-native-gifted-chat

JavaScript
99
star
43

as-typed

Ambient mapping from JSON schema to typescript
TypeScript
98
star
44

playable

No hassle, no fuss, just nice and easy video player
TypeScript
96
star
45

obsidian

Dependency injection library for React and React Native applications
TypeScript
88
star
46

tspoon

(DEPRECATED) AST visitors for TypeScript
TypeScript
83
star
47

remote-dom

JavaScript
82
star
48

react-native-paged-contacts

Paged contacts for React Native
Java
80
star
49

react-native-newrelic

New Relic reporting for React Native
JavaScript
79
star
50

react-module-container

Small library for building micro apps in React and Angular
JavaScript
68
star
51

react-native-repackager

Custom extensions for react-native packager
JavaScript
67
star
52

rapido

🏃 A site performance test kit, built using Chrome's DevTools.
JavaScript
63
star
53

BindingListView

React Native ListView experimental implementation supporting direct view binding
Objective-C
62
star
54

rawss

Generic CSS polyfill framework, with a CSS variables implementation
TypeScript
59
star
55

wix-animations

Tools for easy and simple animating capabilities
JavaScript
59
star
56

haste

An extendable, blazing fast build system that cares about user experience
JavaScript
58
star
57

kafka-connect-s3

A Kafka-Connect Sink for S3 with no Hadoop dependencies.
Java
56
star
58

unidriver

UniDriver - Universal Component Drivers 🚀
TypeScript
53
star
59

carmi

CARMI - Compiler for Automatic Reactive Modelling of Inference
JavaScript
49
star
60

mobile-crash-course

Crash course for engineers in Wix to start working on the mobile stack
49
star
61

react-native-extended-cli

Extended CLI with convenient scripts and utilities for developing React Native apps
Shell
47
star
62

protractor-helpers

Set of matchers, locators, and helper functions for Protractor
JavaScript
46
star
63

Kompot

Component testing for React Native using Detox
JavaScript
45
star
64

future-perfect

A helper for Futures covering non-functional concerns such as retries, timeouts and reporting
Scala
44
star
65

mjml-react-example

mjml-react example project
JavaScript
42
star
66

specs2-jmock

This is a specs2 adapter + DSL for using the popular mocking framework JMock
Scala
41
star
67

corvid

Download your Wix site, code in a local IDE, collaborate, use git, and more!
JavaScript
38
star
68

javascript-essentials

Essential reading and learning materials for Wix client-side engineers
37
star
69

fed-training-kit

A self-guided onboarding kit for new FED Guild members
JavaScript
35
star
70

DeviantArt-API

The DeviantArt API
35
star
71

commons-validator-js

JavaScript port of Apache Commons Validator
JavaScript
35
star
72

redux-cornell

A Redux library which helps reduce boilerplate
TypeScript
34
star
73

wix-http-testkit

Tools for testing HTTP services
Scala
34
star
74

DetoxSync

Synchronization framework for Detox and other testing frameworks
Objective-C
34
star
75

enzyme-drivers

Enzyme Drivers is a JavaScript library that makes react component testing with enzyme a lot easier and fun to write
JavaScript
33
star
76

mutable

State containers with dirty checking and more
JavaScript
32
star
77

eyes.it

Add screenshot comparison to existing protractor tests simply by changing `it` to `eyes.it`
JavaScript
31
star
78

react-native-sane-listview

Why do we need all this datasource nonsense?!
JavaScript
31
star
79

wix-ui-backoffice

Common React UI components for all Wix backoffice React applications
TypeScript
31
star
80

turnerjs

An angular test kit for components and directives. See:
TypeScript
29
star
81

wixmadefor

Wix Madefor font
Python
27
star
82

zorechka-bot

Github bot for keeping your Bazel dependencies up-to-date and clean
Scala
27
star
83

Koboshi

Obsessed with your precious data
Scala
27
star
84

react-popup-manager

Manage react popups, Modals, Lightboxes, Notifications
TypeScript
26
star
85

sample-wix-rest-app

JavaScript
25
star
86

wix-code-docs

Wix Code Reference Documentation - docworks jsons
JavaScript
25
star
87

wix-react-native-storybook-template

Server to host storybook for react native apps
JavaScript
24
star
88

hello-react-templates

Starter project for react-templates
JavaScript
24
star
89

react-native-open-file

Objective-C
24
star
90

isolated-runtime

Run untrusted Javascript code in a multi-tenant, isolated environment
JavaScript
23
star
91

react-hoverbox

Created by malsomnus
JavaScript
23
star
92

react-sequence-animator

A React library for sequence animations
TypeScript
23
star
93

fast-boot

Caching of the FS location of node modules between node process startups
JavaScript
22
star
94

svg2react-icon

Generate React icon components from SVG raw files
JavaScript
22
star
95

quick-2fa

Safely generate two-factor authentication tokens into clipboard
JavaScript
21
star
96

async-graph-resolver

A Utility to handle execution and aggregation of async actions
TypeScript
21
star
97

DetoxIPC

DetoxIPC is an asynchronous, bi-directional inter-process remote invocation library for Apple platforms with an API similar to Apple's NSXPCConnection.
Objective-C
21
star
98

react-native-animation-library

JavaScript
20
star
99

data-capsule

A pluggable capsule for storing key/value data for your application
TypeScript
20
star
100

DTXLoggingInfra

Logging infrastructure for Apple platforms
Objective-C
18
star