• Stars
    star
    170
  • Rank 223,357 (Top 5 %)
  • Language
    TypeScript
  • License
    MIT License
  • Created almost 6 years ago
  • Updated about 1 month ago

Reviews

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

Repository Details

Pluggable micro frontends in React+Redux apps

Repluggable

master build npm version

Repluggable is a library that's implementing inversion of control for front end applications and makes development of medium or high-complexity projects much easier. Currently Repluggable implements micro-frontends in a React+Redux app, with plans to make it framework-independent in the future.

Functionality of a Repluggable app is composed incrementally from a list of pluggable packages. Every package extends the already loaded ones by contributing new functionality into them. Sections of UI, contributed by a certain package, can be rendered anywhere and are not limited to dedicated subtree of DOM. All packages privately manage their state in a modular Redux store, which plays the role of common event mechanism. Packages interact with each other by contributing and consuming APIs, which are objects that implement declared interfaces. Packages can be plugged in and out at runtime without the need to reload a page. Check out the architecture section of the docs to learn more about the design decisions behind Repluggable.

Quick docs links: How-to | Architecture and core concepts

Getting started

All code in this README is in TypeScript.

Installation

To add Repluggable to an existing React+Redux application:

$ npm install repluggable

Create a new Repluggable project

Run the following commands:

npx create-react-app your-app-name --template typescript
cd your-app-name
yarn add [email protected] [email protected] @types/[email protected] @types/[email protected] repluggable
rm src/App*
rm src/logo*
cp -R node_modules/repluggable/examples/helloWorld/src/ ./src
yarn start

Writing a pluggable package

A pluggable package is basically an array of entry points. An entry point is an object which contributes certain functionality to the application. Below is an example of a simple entry point.

foo.ts

import { EntryPoint } from 'repluggable'

export const Foo : EntryPoint = {
    name: 'FOO',

    attach() {
        console.log('FOO is here!')
    }
}

Usually, a pluggable package will be a separate npm project, which exports an array of entry points. But it isn't required - entry points can also be part of the main app.

Bootstrapping the main application

Main application is the React+Redux app that's being composed from packages. Suppose we also have bar.ts implemented similarly to Foo above.

App.tsx

import { createAppHost, AppMainView } from 'repluggable'
import { Foo } from './foo'
import { Bar } from './bar'

const host = createAppHost([
    // the list of initially loaded packages
    Foo,
    Bar
])

ReactDOM.render(
    <AppMainView host={host} />,
    document.getElementById('root')
)

When run, the application will print two messages to console, first 'FOO is here!', then 'BAR is here!'.

How-to

Developing main application

The main application is a React application, which uses the repluggable package.

The index.ts of the application must perform the following steps.

  1. Import from repluggable

    import { createAppHost, AppMainView } from 'repluggable'
  2. Provide loaders of pluggable packages. Below is an example of three packages, each loaded in a different way:

    • package-foo is statically bundled with the main app
    • package-bar is in a separate chunk (WebPack code splitting). We'll load it with dynamic import.
    • package-baz is in an AMD module, deployed separately. We'll load it with RequireJS.

    This is how the three packages are loaded:

    import foo from 'package-foo'
    const bar = () => import('package-bar').then(m => m.default)
    const baz = require('package-baz')
  3. Initialize AppHost with the packages:

    const host = createAppHost([
        foo,
        baz
    ])
    
    // Later
    void bar().then(p => host.addShells([p]))
  4. Render AppMainView component, passing it the host:

    ReactDOM.render(
        <AppMainView host={host} />,
        document.getElementById('root')
    )

Full code

import ReactDOM from 'react-dom'
import { createAppHost, AppMainView } from 'repluggable'

import packageOne from 'package-one'
const packageTwo = () => import('package-two').then(m => m.default)
const packageThree = require('package-three')

const host = createAppHost([
    packageOne,
    packageThree
])

ReactDOM.render(
    <AppMainView host={host} />,
    document.getElementById('root')
)

// Sometime later
void packageTwo().then(p => host.addShells([p]))

Developing a pluggable package

Creating a package project

A package project is a regular Node project.

Typically, it is set up with TypeScript, React, and Redux. Such a project must include a repluggable dependency.

The rest of the configuration (Babel, WebPack, Jest, etc) heavily depends on the organization of your codebase and release pipeline, and is outside the scope of this README.

Creating entry points

As we mentioned before, each package must export one or more entry points in order to be loaded by the main app.

An entry point is an object which implements an EntryPoint interface:

import { EntryPoint } from 'repluggable'

const FooEntryPoint: EntryPoint = {

    // required: specify unique name of the entry point
    name: 'FOO',

    // optional
    getDependencyAPIs() {
        return [
            // DO list required API keys
            BarAPI
        ]
    },

    // optional
    declareAPIs() {
        // DO list API keys that will be contributed 
        return [
            FooAPI
        ]
    },

    // optional
    attach(shell: Shell) {
        // DO contribute APIs
        // DO contribute reducers
        // DO NOT consume APIs
        // DO NOT access store
        shell.contributeAPI(FooAPI, () => createFooAPI(shell))
    },

    // optional
    extend(shell: Shell) {
        // DO access store if necessary
        shell.getStore().dispatch(....)
        // DO consume APIs and contribute to other packages
        shell.getAPI(BarAPI).contributeBarItem(() => <FooItem />)
    },

    // optional
    detach(shell: Shell) {
        // DO perform any necessary cleanup
    }
}

The EntryPoint interface consists of:

  • declarations: name, getDependencies()
  • lifecycle hooks: attach(), extend(), detach()

The lifecycle hooks receive a Shell object, which represents the AppHost for this specific entry point.

Exporting entry points

The default export of a package must be an array of its entry points. For example, in package root index.ts :

import { FooEntryPoint } from './fooEntryPoint'
import { BarEntryPoint } from './barEntryPoint'

export default [
    FooEntryPoint,
    BarEntryPoint
]

Creating an API

To create an API, perform these steps:

  1. Declare an API interface. For example:

    export interface FooAPI {
        doSomething(): void
        doSomethingElse(what: string): Promise<number>
    }
  2. Declare an API key, which is a const named after the interface, as follows:

    import { SlotKey } from 'repluggable'
    
    export const FooAPI: SlotKey<FooAPI> = {
        name: 'Foo API',
        public: true
    }

    Note that public: true is required if you plan to export your API outside of your package. The key must be declared in the same .ts file with the interface.

  3. Implement your API. For example:

    export function createFooAPI(shell: Shell): FooAPI {
        return {
            doSomething(): void {
                // ...
            },
            doSomethingElse(what: string): Promise<number> {
                // ...
            }
        }
    }
  4. Contribute your API from an entry point attach function:

    import { FooAPI, createFooAPI } from './fooApi'
    
    const FooEntryPoint: EntryPoint = {
    
        ...
    
        attach(shell: Shell) {
            shell.contributeAPI(FooAPI, () => createFooAPI(shell))
        }
    
        ...
    
    }
  5. Export your API from the package. For example, in the index.ts of your package:

    export { FooAPI } from './fooApi'

Managing state

In order to manage state in a package, you need to contribute one or more reducers.

In the example below, FooEntryPoint will contribute two reducers, bazReducer and quxReducer.

To contribute the reducers, perform these steps:

  1. Declare types that represent the state for each reducer:

    // state managed by bazReducer
    export interface BazState {
        ...
        xyzzy: number // for example
    }
    
    // state managed by quxReducer
    export interface QuxState {
        ...
    }
  2. Wrap these state types in a root state type. This root type determines the shape of the state in the entry point.

    // the root type on entry point level
    export interface FooState {
        baz: BazState
        qux: QuxState
    }
  3. Write the two reducers. For example, they can look like this:

    function bazReducer(
        state: BazState = { /* initial values */ },
        action: Action)
    {
         ...
    }
    
    function quxReducer(
        state: QuxState = { /* initial values */ },
        action: Action)
    {
         ...
    }
  4. Contribute state in the entry point:

    attach(shell: Shell) {
        shell.contributeState<FooState>(() => ({
            baz: bazReducer,
            qux: quxReducer
        }))
    }

    Here, an argument passed to contributeState() is a reducer map object. This object contains all the same keys of FooState (the baz and qux), but this time the keys are assigned their respective reducers. Such derivation of reducers' map shape is enforced by the typings.

  5. Expose selectors and action dispatchers through APIs:

    export interface FooAPI {
        ...
        getBazXyzzy(): number
        setBazXyzzy(value: number): void
        ...
    }

    The above API allows to read and change the value of xyzzy in the BazState.

    Note that neither of these two functions are passed the state or the Store object. This is because their implementations are already bound to the store of the AppHost:

    const createFooAPI = (shell: Shell): FooAPI => {
        // this returns a scoped wrapper over the full
        // store of the main application
        // IMPORTANT! the generic parameter (FooState)
        // must match the one specified when contributing state!
        // In our example, we did contributeState<FooState>(...)
        const entryPointStore = shell.getStore<FooState>()
    
        const getState = () => entryPointStore.getState()
    
        return {
            ...
            // example of selector
            getBazXyzzy(): number {
                const state: FooState = getState()
                return state.baz.xyzzy
            },
            // example of action dispatcher
            setBazXyzzy(value: number): void {
                entryPointStore.dispatch(BazActionCreators.setXyzzy(value))
            }
            ...
        }
    }

Creating React components

When creating a React component, we strongly recommend to follow the React-Redux pattern, and separate your component into a stateless render and a connect container.

In repluggable, components often need to consume APIs. Although APIs can be obtained through Shell, when it is passed to lifecycle hooks in your entry point, propagating them down the component hierarchy would be cumbersome.

A more elegant solution is to use connectWithShell() function instead of the regular connect(). This provides the connector with the ability to obtain APIs.

The example below illustrates how connectWithShell() is used. Suppose we want to create a component <Foo />, which would render like this:

(props) => (
    <div className="foo">
        <div>
            <label>XYZZY</label>
            <input
                type="text"
                defaultValue={props.xyzzy}
                onChange={e => props.setXyzzy(e.target.value)} />
        </div>
        <div>
            Current BAR = {props.bar}
            <button onClick={() => props.createNewBar()}>
                Create new BAR
            </button>
        </div>
    </div>
)

In order to implement such a component, follow these steps:

  1. Declare the type of state props, which is the object you return from mapStateToProps:

    type FooStateProps = {
        // retrieved from own package state
        xyzzy: string
        // retrieved from another package API
        bar: number
    }
  2. Declare type of dispatch props, which is the object you return from mapDispatchToProps:

    type FooDispatchProps = {
        setXyzzy(newValue: string): void
        createNewBar(): void
    }
  3. Write the stateless function component. Note that its props type is specified as FooStateProps & FooDispatchProps:

    const FooSfc: React.SFC<FooStateProps & FooDispatchProps> =
        (props) => (
            <div className="foo">
                ...
            </div>        
        )
  4. Write the connected container using connectWithShell. The latter differs from connect in that it passes Shell as the first parameter to mapStateToProps and mapDispatchToProps. The new parameter is followed by the regular parameters passed by connect. For example:

    export const createFoo = (boundShell: Shell) => connectWithShell(
        // mapStateToProps
        // - shell: represents the associated entry point
        // - the rest are regular parameters of mapStateToProps
        (shell, state) => {
            return {
                // some properties can map from your own state
                xyzzy: state.baz.xyzzy,
                // some properties may come from other packages' APIs
                bar: shell.getAPI(BarAPI).getCurrentBar()
            }
        },
        // mapDispatchToProps
        // - shell: represents the associated entry point
        // - the rest are regular parameters of mapDispatchToProps
        (shell, dispatch) => {
            return {
                // some actions may alter your own state
                setXyzzy(newValue: string): void {
                    dispatch(FooActionCreators.setXyzzy(newValue))
                },
                // others may request actions from other packages' APIs
                createNewBar() {
                    shell.getAPI(BarAPI).createNewBar()  
                }
            }
        },
        boundShell
    )(FooSfc)

    The Shell parameter is extracted from React context EntryPointContext, which represents current package boundary for the component.

Exporting React components

TBD (advanced topic)

Testing a package

TBD

Local development

HMR (hot module replacement)

For a smooth local development experience, it's recommended to enable HMR, allowing packages' code to update immediately without the need to reload the entire page. (For more information on HMR, see webpack's docs)

To enable HMR, use Repluggable's hot util to wrap the export of your repluggable package. For example, in the package root index.ts:

import { hot } from 'repluggable'
import { FooEntryPoint } from './fooEntryPoint'
import { BarEntryPoint } from './barEntryPoint'

export default hot(module, [
    FooEntryPoint,
    BarEntryPoint
])

Architecture

repluggable allows composition of a React+Redux application entirely from a list of pluggable packages.

Think of a package as a box of lego pieces - such as UI, state, and logic. When a package is plugged in, it contributes its pieces by connecting them to other pieces added earlier. In this way, the entire application is built up from connected pieces, much like a lego set.

For two pieces to connect, one piece defines a connection point (an extension slot) for another specific type of a piece. In order to connect, the other piece has to match the type of the slot. One slot can contain many pieces.

Packages can be plugged in and out at runtime. Contributed pieces are added and removed from the application on the fly, without the need for a page to reload.

Main application

This is the application being composed, much like a lego set. We refer to it as main application.

The main application can be as small as an empty shell. Its functionality can be completely composed by the packages, where each plugged package contributes its pieces to the whole.

The minimal responsibilities of the main application are:

  • Initialize an AppHost object with a list of pluggable packages.

    The AppHost object orchestrates lifecycle of the packages, handles cross-cutting concerns at package boundaries, and provides dependency injection to Redux-connected components.

  • Render AppMainView component, passing it the initialized AppHost in props.

Pluggable packages

Pluggable package (or simply package) is a regular Node package, which exports an array of entry points.

The packages are plugged in the order they are listed when passed to AppHost. Entry points are invoked in the list order of the packages, in the array order within the package.

Entry points

Every entry point contributes one or more pieces to the whole lego set of the application.

Examples of contributed pieces include React components, panel item descriptors, UI command descriptors, etc, etc. They can be anything, provided that they are expected by the "lego set". Here expected means that some package provides an API, through which it accepts contributions of this specific type.

There are also two kinds of contributions supported directly by repluggable: APIs and reducers.

Besides contributing lego pieces, entry points may contain additional lifecycle hooks.

APIs

Some packages (providers) provide services to other packages (consumers). The services are provided through APIs. An API is an object, which implements a TypeScript interface, and is identified by an API key. An API key is another object declared as a const TODO: link to example, and exported from the package.

In general, APIs allow packages to extend other packages (consumers call APIs, which let them pass contributions to the provider), and otherwise interact. Moreover, APIs are the only allowed way of interaction between packages.

In order to provide an API, a provider package:

  • declares and exports an API interface and an API key
  • implements an API object according to the interface
  • contributes an API object under the key

In order to consume an API, a consumer package:

  • imports an API key and an API interface from the provider package
  • declares dependency on the API in relevant entry points
  • retrieves an API object by calling getAPI and passing it the API key TODO: link to example.

Reducers

repluggable requires that all state of the application is managed in a Redux store. This ensures that all pieces are connected to a single event-driven mechanism. In turn, this guarantees that pure React components mapped to values returned by APIs will re-render once these values change.

A package that has state must contribute one or more reducers responsible for managing that state. If such a package contributes APIs, it can also include selectors and action dispatchers in the APIs.

The Redux store of the main application is combined from reducers, contributed by stateful packages.

Extension Slots

When a package accepts contributions from other packages, it must store contributed pieces in some kind of an array.

repluggable provides a "smart" array for this purpose, named extension slot. Extension slot is a generic object ExtensionSlot<T>, which accepts contributions of type T.

Its additional responsibility is remembering which package and entry point each contribution was received from. This allows applying package boundaries and easily handling other cross-cutting concerns.

Extension slots are implementation details of a package, and they should never be directly exposed outside of the package. Instead, a package:

  • internally initializes an extension slot for every kind or group of accepted contributions.
  • contributes an API that receives contributions from the outside and pushes them to an internal extension slot.

With that, the AppHost also tracks all existing extension slots. This approach allows for an easy implementation of application-wide aspects. For example, removal of a package with all of its contributions across an application.

Package boundaries in DOM

Every React component rendered under the AppMainView is associated with an entry point context.

The entry point context is a React context, which associates its children with a specific entry point, and thus the package that contains it.

Such association provides several aspects to the children:

  • performance measurements and errors reported by the children are automatically tagged with the entry point and the package

  • in Redux-connected components (TODO: link to details):

    • dependency injection (the getAPI function): all dependencies are resolved in the context of the entry point

    • state scoping (the state in mapStateToProps, and getState() in thunks): returned state object is scoped to reducers contributed by the entry point.

    TODO: verify that getState() in thunks is actually scoped

    • when rendering an extension slot of contributed React components: each component is rendered within the context of the entry point it was contributed by.

Progressive loading

To make application loading reliable and fast, repluggable allows flexible control over package loading process.

The loading process is abstracted from any concrete module system or loader. Packages can be in a monolith bundle, or loaded with dynamic imports, or with loaders like RequireJS. To add a package to an AppHost, all that's needed is a Promise of a package default export.

Packages can be added to an AppHost at different stages:

  • During initialization of the AppHost
  • Right after the AppMainView was rendered for the first time
  • Lazily at any later time

Moreover, AppHost allows separating the whole package into multiple entry points. Some of the entry points are added right as the package is added to the AppHost, while others can be added later.

Such separation allows incremental contribution of functional parts as they become ready. Some parts may need to dynamically load additional dependencies or request data from backends. Without the separation approach, a user won't be able to interact with any functionality of the package, until the entire package is initialized -- which would hurt the experience.

In addition, AppHost supports removal of previously added entry points or entire packages, at any time. Removal of a package means removal of all its entry points. When an entry point is removed, all contributions made from that entry point are removed too.

API dependencies

Since APIs are contributed though entry points, their availability depends on the loading time of the provider package and a specific entry point within it. From a consumer package perspective, this creates a situation in which one or more of the APIs the package depends on may be temporarily unavailable.

AppHost resolves that with the help of explicit dependency declarations. Every entry point must declare APIs which it's dependent on (including dependencies of all pieces contributed by the entry point). If any of the required APIs is unavailable, the entry point is put on hold. There are two possible cases:

  • Attempted to add an entry point, but some of required APIs weren't available: the entry point is put on hold, and will be added as soon as all required APIs are contributed.
  • An entry point was added, but then some of its required APIs became unavailable: the entry point will be removed together with all of its contributions, and put on hold. It will be added once again as soon as all required APIs are available.

Such approach guarantees that code dependent on an API from another package will not run unless that API is available.

Licenses

3-rd party licenses are listed in docs/3rd-party-licenses.md

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

react-native-custom-segmented-control

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

lerna-script

Lerna addon for adding custom tasks
JavaScript
164
star
31

react-native-wix-engine

Java
164
star
32

angular-widget

Lazy load isolated micro-apps in Angular
JavaScript
163
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