Full Code of onerzafer/microfe-client for AI

master 577612460eed cached
31 files
38.2 KB
9.6k tokens
54 symbols
1 requests
Download .txt
Repository: onerzafer/microfe-client
Branch: master
Commit: 577612460eed
Files: 31
Total size: 38.2 KB

Directory structure:
gitextract_aqivtzgj/

├── .github/
│   └── ISSUE_TEMPLATE/
│       ├── bug_report.md
│       └── feature_request.md
├── .gitignore
├── .prettierrc
├── LICENSE.md
├── README.md
├── index.html
├── karma.config.js
├── package.json
├── spec.bundle.js
├── src/
│   ├── lib/
│   │   ├── AppsManager/
│   │   │   ├── AppsManager.ts
│   │   │   ├── status.enum.ts
│   │   │   └── tag.enum.ts
│   │   ├── Bootstrapper/
│   │   │   └── bootstrapper.ts
│   │   ├── Decorators/
│   │   │   └── Microfe.decorator.ts
│   │   ├── Interfaces/
│   │   │   ├── AppsManager.interface.ts
│   │   │   ├── AppsManager.internal.interface.ts
│   │   │   ├── Config.interface.ts
│   │   │   └── Router.interface.ts
│   │   ├── Loader/
│   │   │   └── Loader.ts
│   │   ├── Provider/
│   │   │   └── Provider.ts
│   │   ├── Router/
│   │   │   ├── Link.ts
│   │   │   ├── Router.ts
│   │   │   └── RouterOutlet.ts
│   │   ├── Store/
│   │   │   └── MicroAppStore.ts
│   │   └── index.ts
│   └── main.ts
├── tsconfig.json
├── tslint.json
├── webpack.config.js
└── webpack.production.config.js

================================================
FILE CONTENTS
================================================

================================================
FILE: .github/ISSUE_TEMPLATE/bug_report.md
================================================
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: ''
assignees: ''

---

**Describe the bug**
A clear and concise description of what the bug is.

**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error

**Expected behavior**
A clear and concise description of what you expected to happen.

**Screenshots**
If applicable, add screenshots to help explain your problem.

**Desktop (please complete the following information):**
 - OS: [e.g. iOS]
 - Browser [e.g. chrome, safari]
 - Version [e.g. 22]

**Smartphone (please complete the following information):**
 - Device: [e.g. iPhone6]
 - OS: [e.g. iOS8.1]
 - Browser [e.g. stock browser, safari]
 - Version [e.g. 22]

**Additional context**
Add any other context about the problem here.


================================================
FILE: .github/ISSUE_TEMPLATE/feature_request.md
================================================
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: ''
assignees: ''

---

**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]

**Describe the solution you'd like**
A clear and concise description of what you want to happen.

**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.

**Additional context**
Add any other context or screenshots about the feature request here.


================================================
FILE: .gitignore
================================================
node_modules/
dist/
.idea/


================================================
FILE: .prettierrc
================================================
{
  "trailingComma": "es5",
  "tabWidth": 4,
  "semi": true,
  "singleQuote": true,
  "jsxSingleQuote": true,
  "bracketSpacing": true,
  "jsxBracketSameLine": true,
  "printWidth": 120
}


================================================
FILE: LICENSE.md
================================================
MIT License

Copyright (c) 2018 Öner Zafer

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

================================================
FILE: README.md
================================================
# *microfe*
*(microfe - short for micro frontends)*

A naive infrastructure/meta-framework implementation for micro frontends. This project intends to provide the necessary tooling to achieve independent apps loaded separately and run on different parts on a single web page in complete isolation.
For detailed information on the topic can be found [micro-frontends.org](https://micro-frontends.org/)
## Motivation
When developing microservices there are lots of tools and libraries to help developers to focus the effort on the things needs to be done instead of fighting against a monolithic monster. For now, "micro frontends" idea is still premature and it needs time to grow something easy to use. My intention is to contribute to this discussion and also provide necessary tooling and a sample architecture for developers who would like to give it a try. Providing an easy to use infrastructure for individuals and companies can be considered as an ultimate goal.
## Who will/may/can use *microfe*?
Ideally *microfe* is not suitable for small teams and for them trying to use it would not be necessary. For this kind of teams refactoring their monolithic fe apps would be more productive instead of using *microfe* to divide a relatively big app into smaller pieces and trying to maintain each piece. If the project contains at least two independent teams which are responsible for the same monolithic app then *microfe* can be beneficial. Because *microfe* gives the opportunity of working on independent tech stack by each team. It can provide isolation and managed communication channels between micro-apps.
## On Micro Frontends
While companies growing they usually move from one team to two or more and they start to divide the code base and on the backend side microservice architecture has lots of benefits to scale the company up. On the frontend side, the code base becomes a growing monolith even if it is written in a modular fashion. So scaling a front end team is not so easy and problems start to appear. Lack of communication between teams, conflicting merges, hard to change tech stacks, hard to update dependencies and the list goes on.

Similar to microservices, the micro frontends provides the opportunity to isolate code bases and make the teams free to use any code standards and tech stack and focus on relatively small parts of the application.
## Goals
* Isolated and Independent apps
* A way to have a unified UI
* Inter-app communication (i.e. authentication)
* Easy to maintain apps
* Not to break already available build environments for major frameworks (React, Angular, Vue)
* Freedom of tech stack choice

## Requirements
To run the microfe locally you need to clone and run [micro-fe-registry](https://github.com/onerzafer/micro-fe-registry). The documentation for micro-fe-registry can be found under its own repository.

## Usage
Currently, there is no npm package provided and the usage is not recommended at this phase. Yet if you are willing to experiment by yourself clone both repositories. For micro-fe-registry part follow the instructions on its own repository. Then execute following commands
```bash
npm install
npm start
```
This command will open your browser on http://localhost:8080 and you will be able to see the page is running.

If you see just blank page be sure your micro-fe-registry installation is up and running. And if it is running already please check if the requested micro-apps are available on the registry folder with requested names. If you have still problems of running please open an issue I will be happy to help you.

## Top level architecture
The microfe library basically has 4 different main parts *AppsManager, Loader, Router* and *Store*. It also provides some helper functions and classes: *Bootstrapper, Microfe decorator* and  *provider*.
These all parts of the microfe library can function with a specific micro-apps wich implements microfe interface.

### Definition of a microfe app
A microfe app should implement the following interface
```TypeScript
interface MicroApp {
    name: string;
    deps?: string[];
    initialize: (args: {
        AppsManager: AppsManager;
        Config: ConfigInterface;
        [key: string]: any;
    }) => any | void;
}
```
**initialize** function may return the instance of the app

### Bootstrapper
The responsibility of Bootstrapper is initializing the AppsManager and all other micro-apps provided inside the library. So it can be considered as the entry point of the microfe library. The signature for bootstrapper can be described like this:
```TypeScript
const bootstrap = (
    routes: Route[],
    config: ConfigInterface
) => (...microApps: MicroApp[]) => void
```
To boostrap the microfe meta-framework the following example can be used as a refrence:
```TypeScript
import { Microfe, Bootstrap, Route, ConfigInterface } from './lib';

@Microfe({
    deps: ['LayoutApp'],
})
class Main {
    constructor() {
        console.log('Initialised');
    }
}

const Routes: Route[] = [
    { path: '/', redirectTo: '/angular' },
    { path: '/angular', microApp: 'demoAngular', tagName: 'demo-angular' },
    { path: '/react', microApp: 'reactDemo', tagName: 'react-demo' },
    { path: '/static', microApp: 'staticApp', tagName: 'static-app' },
    { path: '*', microApp: 'NotFoundApp', tagName: 'not-found-app' },
];

const Config: ConfigInterface = {
    registryApi: 'http://localhost:3000/registry',
    registryPublic: 'http://localhost:3000',
};

Bootstrap(Routes, Config)(Main);
```

### AppsManager
The main functionality of AppsManager is creating the dependency tree and when all of the dependencies of a micro-app are ready, it instantiates the micro-app by providing the dependencies instances. The public API for AppsManager can be summarized as follows:
```TypeScript
interface AppsManager {
    register: (app: MicroApp) => void;
    subscribe: (fn: (notFoundApps: MicroApp[]) => void) => {
        unsubscribe: () => void
    }
}
```
AppsManager passes the config and itself as default dependency to all of the instances of provided micro-apps. Which means all have the access to AppsManager and its public API. Alternatively, AppsManager can be accessed from window global as AppsManager.

*AppsManager is the only part which does not implement the MicroApp interface. The rest of the library actually is a collection of micro-apps.*
### Loader
When registered by Bootstrapper the Loader requires Config and waits until it is provided. With the config Loader receives the micro-fe-registry public URLs. After getting the Config AppsManagers instantiates the Loader. On constructer Loader subscribes to AppsManagers and start the not found micro-apps. When a new not found micro-app available the Loader parse the micro-app URL by combining the name of the micro-app and public URL of micro-fe-registry injects it to the dom as a remote script. Naturally, the browser loads the micro-app from given URL. The loader can be a dependency and it has only one public function.
```TypeScript
const Loader {
    fetchMicroApp: (name: string) => void
}
```
### Router
Unlike the common routers, the microfe router has limited functionality. It is capable of solving the first part of the declared URLs. This implementation assumes the rest of the URL will be resolved by the responsible micro-app. If the Router can resolve the URL from the browser location it triggers the Loader.fetchMicroApp function with the name of resolved micro-app. So it has two dependencies routes and Loader.
#### Route
The routes object is an array of the Route objects which has the following interface:
```TypeScript
interface Route {
    path: string;
    tagName?: string;
    redirectTo?: string;
    microApp?: string;
}
```
#### micro-router the Router outlet
When Router instantiates it register a web component called micro-router. This is the expected place for all other micro-apps loads on route hit. The usage is pretty simple and available for all micro-apps living on the client at the moment.
```html
<micro-router></micro-router>
```
Currently, it has no targetting of sub-routes. Which means all of the micro-router tags will display the same target micro-app. So current recommendations are using only one micro-router the page. In the future, some sub-routes can be targetted to some named micro-router tags.
#### micro-link
Router also provides a simple navigation element with no design. All micro-apps will be able to access it any time since it is provided as a web component like micro-router. micro-link has one attribute which is href and if the given path is the current route, it assigns itself automatically active class. So no need to observe history and match correct path to put active class to the links.
```html
<micro-link href="/some/cool/page">
    Some Cool Page
</micro-link>
```
When we navigate to /some/cool/page this micro-link above will be marked as active. 
### Store
With the assumption of only big teams and big code bases will need the microfe and nearly all of the already managing app state, the microfe library provides a global shared inter-app state. this state can be used as a shared event bus or shared global state. By nature, this store is reactive and powered by RxJS. Yet it still has the similar functionalities of Redux library.
```TypeScript
interface Action {
    type: string;
    [key: string]: any;
}

interface State {
    [key: string]: any;
}

interface Reducer {
    (action: Action, state: State) => State) => void;
}

interface ReducerTreePiece {
    [key: string]: Reducer | ReducerTreePiece
}

interface MicroAppStore {
    addReducer: (reducerTreePiece: ReducerTreePiece) => void;
    dispatch: (action: Action) => void;
    select: (selector: string) => Observable<State>;
}
```
The main issue with the MicroAppStore is the reducers may arrive on different times. The select function is pretty useful on this case. Because if the selected reducer is not available it sibly emits undefined and when the reducer arrives it emmits to all subscribers the related state.
```TypeScript
const Todos$ = MicroAppsStore.select('todos');
Todos$.subscribe(todos => console.log(todos)); // immediatelly logs undefined
const todosReducer = (state = [], action: Action) => {
    return state;
}
MicroAppsStore.addReducer({todos: todoRecucer});
// At this point Todos$.subscribe will receive [] as todos and will log []
```
### Microfe decorator
This decorator can be used as an helper for casting any class to a micro-app
```TypeScript
@Microfe({
    deps: ['LayoutApp']
})
export class Main {
    private layoutApp;
    constructor({LayoutApp}) {
        this.layoutApp = LayoutApp;
        this.render();
    }

    private render() {
        this.layoutApp.someLayoutAppFunction();
    }
}
```
The code block above will be equavalent to following code:
```javascript
{
    name: 'Main',
    deps: ['LayoutApp']
    initialize: function({LayoutApp}) {
        LayoutApp.someLayoutAppFunction();
    }
}
```
### Provider
The provider is a helper function to provide objects as micro-app. So any static data can be provided to other micro-apps with Provide function:
```TypeScript
const languageEn = {hello: 'Hello'};
const languageEnProvider = provide(languageEn);
```
Then languageEnProvider can be passed down to all micro-apps which has the dependency as follows:
```TypeScript
Bootstrap(Routes, Config)(Main, LanguageEnProvider);
```
# License
[MIT](https://choosealicense.com/licenses/mit/)

================================================
FILE: index.html
================================================
<html>
<head>
    <title>Test App</title>
    <style>
        body, html {
            margin: 0;
            padding: 0;
        }
    </style>
</head>
<body>
    <layout-app></layout-app>
    <script src="/main.js"></script>
</body>
</html>


================================================
FILE: karma.config.js
================================================
const webpackConfig = require('./webpack.config.js');
webpackConfig.mode = 'production';

module.exports = function(config) {
  config.set({
    singleRun: true,
    
    browsers: [
      'PhantomJS'
    ],

    frameworks: [
      'jasmine'
    ],

    files: [
      'spec.bundle.js'
    ],

    preprocessors: {
      'spec.bundle.js': ['webpack']
    },

    webpack: webpackConfig,

    webpackMiddleware: {
      stats: 'errors-only'
    },

    plugins: [
      require('karma-jasmine'),
      require('karma-phantomjs-launcher'),
      require('karma-webpack')
    ]
  });
};

================================================
FILE: package.json
================================================
{
  "name": "micro-fe",
  "version": "0.0.1",
  "description": "A naive micro frontend solution",
  "main": "index.js",
  "scripts": {
    "start": "webpack-dev-server  --progress --open --history-api-fallback",
    "build": "webpack --config webpack.production.config.js --mode production",
    "test": "karma start karma.config.js"
  },
  "author": "Öner Zafer",
  "license": "MIT",
  "devDependencies": {
    "@types/jasmine": "2.8.7",
    "@types/node": "7.0.0",
    "jasmine-core": "3.1.0",
    "karma": "2.0.4",
    "karma-jasmine": "1.1.2",
    "karma-phantomjs-launcher": "1.0.4",
    "karma-webpack": "3.0.0",
    "ts-loader": "^4.1.0",
    "typescript": "^2.6.2",
    "tslint": "5.10.0",
    "tslint-loader": "3.6.0",
    "webpack": "^4.28.4",
    "webpack-cli": "^3.2.1",
    "webpack-dev-server": "^3.1.14",
    "fork-ts-checker-webpack-plugin": "^0.5.2"
  },
  "dependencies": {
    "rxjs": "^6.3.3"
  }
}


================================================
FILE: spec.bundle.js
================================================
var testsContext = require.context(".", true, /.spec.ts/);
testsContext.keys().forEach(testsContext);

================================================
FILE: src/lib/AppsManager/AppsManager.ts
================================================
import { STATUS } from './status.enum';
import { MicroAppProvider } from '../Interfaces/AppsManager.interface';
import { AnyObj, BoolObj, MicroAppDef, MicroAppsGraph } from '../Interfaces/AppsManager.internal.interface';

export class AppsManager {
    private microAppsGraph: MicroAppsGraph = {};
    private instanceCache: AnyObj = {};
    private subscriptions: Array<(appList: MicroAppDef[]) => void> = [];

    constructor() {
        window['AppsManager'] = this;
    }

    register(microApp: MicroAppProvider | any) {
        const microAppDef = AppsManager.generateMicroAppDef(microApp);
        const tempGraph = { ...this.microAppsGraph, [microAppDef.name]: microAppDef };
        if (this.isDefinedBefore(microAppDef.name)) {
            console.error(`[Conflict error]: "${microAppDef.name}" is defined before.`);
            return;
        }
        if (this.isCyclic(microAppDef.name, undefined, undefined, tempGraph)) {
            const deps = microApp.deps.join(', ');
            console.error(`[Dependency error]: "${microApp.name}" has cyclic dependency. Check "${deps}"`);
            return;
        }
        this.addMicroAppToGraph(microAppDef);
        microAppDef.deps.forEach(microAppName => {
            const dep = this.microAppsGraph[microAppName];
            if (!dep) {
                this.addMicroAppToGraph(AppsManager.generatePlaceholderMicroAppDef(microAppName));
            }
        });
        this.updateMicroAppStatuses();
        this.runReadyMicroApps();
        this.dispatch();
    }

    isDefinedBefore(microAppName: string): boolean {
        return this.microAppsGraph[microAppName] && this.microAppsGraph[microAppName].status !== STATUS.NOTFOUND;
    }

    subscribe(fn: (appList: MicroAppDef[]) => void) {
        this.subscriptions.push(fn);
    }

    dispatch() {
        const appList = Object.keys(this.microAppsGraph).map(microAppName => this.microAppsGraph[microAppName]);
        const notFoundList = appList.filter(microApp => microApp.status === STATUS.NOTFOUND);
        this.subscriptions.forEach(fn => {
            fn.call(null, notFoundList);
        });
    }

    private checkDepsRunning(microApp: MicroAppDef): boolean {
        return (
            !microApp.deps.length ||
            (microApp.deps.length &&
                microApp.deps.filter(microAppName => {
                    return this.microAppsGraph[microAppName].status === STATUS.RUNNING;
                }).length === microApp.deps.length)
        );
    }

    private isCyclic(vertex: string, visited: BoolObj = {}, recStack: BoolObj = {}, list: MicroAppsGraph): boolean {
        if (!visited[vertex]) {
            visited[vertex] = true;
            recStack[vertex] = true;
            const neighbours = (list[vertex] && list[vertex].deps) || [];
            for (let i = 0; i < neighbours.length; i++) {
                const current = neighbours[i];
                if (!visited[current] && this.isCyclic(current, visited, recStack, list)) {
                    return true;
                } else if (recStack[current]) {
                    return true;
                }
            }
        }
        recStack[vertex] = false;
        return false;
    }

    private addMicroAppToGraph(microApp: MicroAppDef) {
        if (!this.microAppsGraph[microApp.name]) {
            this.microAppsGraph = { ...this.microAppsGraph, [microApp.name]: microApp };
        } else {
            this.microAppsGraph = {
                ...this.microAppsGraph,
                [microApp.name]: {
                    ...this.microAppsGraph[microApp.name],
                    ...microApp,
                },
            };
        }
    }

    private runReadyMicroApps() {
        let hasSomethingRun = false;
        Object.keys(this.microAppsGraph)
            .filter(
                microAppName =>
                    this.microAppsGraph[microAppName].status === STATUS.READY && this.microAppsGraph[microAppName].app
            )
            .forEach(microAppName => {
                const deps = this.provideDepsInstances(microAppName, this.microAppsGraph[microAppName].deps);
                this.instanceCache[microAppName] = this.microAppsGraph[microAppName].app.initialize(deps);
                this.microAppsGraph[microAppName].status = STATUS.RUNNING;
                hasSomethingRun = true;
            });
        if (hasSomethingRun) {
            this.updateMicroAppStatuses();
        }
    }

    private updateMicroAppStatuses() {
        let hasUpdated = false;
        Object.keys(this.microAppsGraph)
            .filter(microAppName => this.microAppsGraph[microAppName].status === STATUS.WAITING)
            .forEach(microAppName => {
                if (this.checkDepsRunning(this.microAppsGraph[microAppName])) {
                    this.microAppsGraph[microAppName].status = STATUS.READY;
                    hasUpdated = true;
                }
            });
        if (hasUpdated) {
            this.runReadyMicroApps();
        }
    }

    private provideDepsInstances(microAppName: string, deps: string[]): { [key: string]: any } {
        return deps.reduce(
            (cumulative, current) => {
                return {
                    ...cumulative,
                    [current]: this.instanceCache[current],
                };
            },
            { AppsManager: this, PATH: this.generateAppScopedPath(microAppName) }
        );
    }

    private generateAppScopedPath(microAppName: string): string {
        return this.instanceCache.Config && this.instanceCache.Config.registryPublic
            ? `${this.instanceCache.Config.registryPublic}/${microAppName}`
            : '';
    }

    static generateMicroAppDef(microApp: MicroAppProvider): MicroAppDef {
        return {
            name: microApp.name,
            status: microApp.deps ? STATUS.WAITING : STATUS.READY,
            deps: microApp.deps ? [...microApp.deps] : [],
            app: microApp,
        };
    }

    static generatePlaceholderMicroAppDef(name: string): MicroAppDef {
        return {
            name,
            status: STATUS.NOTFOUND,
            deps: [],
            app: undefined,
        };
    }
}


================================================
FILE: src/lib/AppsManager/status.enum.ts
================================================
export enum STATUS {
    NOTFOUND = 0,
    WAITING = 1,
    READY = 2,
    RUNNING = 3,
}


================================================
FILE: src/lib/AppsManager/tag.enum.ts
================================================
export enum TAG {
    script = 'script',
    style = 'style',
}

export enum TAG_TYPE {
    script = 'text/javascript',
    style = 'text/css',
}


================================================
FILE: src/lib/Bootstrapper/bootstrapper.ts
================================================
import { AppsManager } from '../AppsManager/AppsManager';
import { Route } from '..';
import { Loader } from '../Loader/Loader';
import { MicroAppStore } from '../Store/MicroAppStore';
import { RouterOutlet } from '../Router/RouterOutlet';
import { MicroAppRouter } from '../Router/Router';
import { Provide } from '../Provider/Provider';
import { MicroLink } from '../Router/Link';

export const Bootstrap = (
    routes?: Route[],
    config?: { registryApi: string; registryPublic: string; [key: string]: any }
) => (...entryApps: any[]) => {
    if (!entryApps.length) {
        throw new Error('At least one entry app should be provided');
    }

    const manager = new AppsManager();
    manager.register(Provide('Routes', routes || []));
    manager.register(Provide('Config', config));
    manager.register(MicroAppStore);
    manager.register(Loader);
    manager.register(MicroAppRouter);
    manager.register(RouterOutlet);
    manager.register(MicroLink);
    entryApps.forEach(entryApp => {
        manager.register(entryApp);
    });
};


================================================
FILE: src/lib/Decorators/Microfe.decorator.ts
================================================
import { MicroAppMeta } from '..';

export const Microfe = function(meta?: MicroAppMeta ) {
    return function(WrappedClass) {
        WrappedClass.deps = meta && meta.deps;
        WrappedClass.initialize = (args) => new WrappedClass(args);
    };
};


================================================
FILE: src/lib/Interfaces/AppsManager.interface.ts
================================================
export interface MicroAppMeta {
    deps?: string[];
}

export interface MicroAppProvider extends MicroAppMeta {
    name: string;
    initialize: (deps: {[key: string]: any}) => void;
}


================================================
FILE: src/lib/Interfaces/AppsManager.internal.interface.ts
================================================
import { STATUS } from '../AppsManager/status.enum';
import { MicroAppProvider } from './AppsManager.interface';

export interface MicroAppDef {
    name: string; // must be unique
    status: STATUS;
    deps: string[];
    app: MicroAppProvider;
}

export interface MicroAppsGraph {
    [key: string]: MicroAppDef;
}

export interface BoolObj {
    [key: string]: boolean;
}

export interface AnyObj {
    [key: string]: any;
}


================================================
FILE: src/lib/Interfaces/Config.interface.ts
================================================
export interface ConfigInterface {
    registryApi: string;
    registryPublic: string;
    [key: string]: any;
}


================================================
FILE: src/lib/Interfaces/Router.interface.ts
================================================
export interface Route {
    path: string;
    tagName?: string;
    redirectTo?: string;
    microApp?: string;
}

export interface ResolvedRoute {
    path: string;
    resolvedPath: string;
    route: Route;
    query?: {[key: string]: string | number | boolean};
    hash?: string;
}


================================================
FILE: src/lib/Loader/Loader.ts
================================================
import { AppsManager } from '../AppsManager/AppsManager';
import { TAG, TAG_TYPE } from '../AppsManager/tag.enum';
import { Microfe } from '../Decorators/Microfe.decorator';
import { MicroAppDef } from '../Interfaces/AppsManager.internal.interface';
import { ConfigInterface } from '../Interfaces/Config.interface';

@Microfe({
    deps: ['Config']
})
export class Loader {
    private loadingList: string[] = [];
    private readonly apiUrl: string = '';
    private appsManager: AppsManager;
    constructor({AppsManager, Config}: {AppsManager: AppsManager, Config: ConfigInterface}) {
        this.apiUrl = (Config && Config.registryApi) || '';
        this.appsManager = AppsManager;
        this.appsManager.subscribe(this.onNotFoundApp.bind(this));
    }

    fetchMicroApp(microAppName: string) {
        if (!this.appsManager.isDefinedBefore(microAppName)) {
            const id = `${microAppName}_js_${new Date().getTime()}`;
            Loader.injectJsToHead(id, `${this.apiUrl}/${microAppName}.js`);
        }
    }

    private onNotFoundApp(appList: MicroAppDef[]) {
        appList.forEach(({ name }) => {
            if (this.loadingList.indexOf(name) === -1) {
                this.loadingList.push(name);
                this.fetchMicroApp(name);
            }
        });
    }

    private static injectJsToHead(id: string, appUrl: string) {
        const script = document.createElement(TAG.script) as HTMLScriptElement;
        script.id = id;
        script.type = TAG_TYPE.script;
        script.src = appUrl;
        script.setAttribute('async', '');
        const firstScriptTag = document.getElementsByTagName('script')[0];
        firstScriptTag.parentNode.insertBefore(script, firstScriptTag);
    }
}


================================================
FILE: src/lib/Provider/Provider.ts
================================================
export const Provide = (name: string, provideable: any) => ({
    name,
    initialize: () => provideable,
});

================================================
FILE: src/lib/Router/Link.ts
================================================
import { MicroAppRouter } from './Router';
import { Microfe } from '../Decorators/Microfe.decorator';

@Microfe({
    deps: ['MicroAppRouter'],
})
export class MicroLink {
    constructor({ MicroAppRouter }: { MicroAppRouter: MicroAppRouter }) {
        class MicroLinkElement extends HTMLElement {
            private styleText = `
                :host {
                    display: inline-block;
                    cursor: pointer;
                }
            `;
            constructor() {
                super();
                this.attachShadow({ mode: 'open' });
                MicroAppRouter.onChange(this.handleRouteChange);
                this.render();
            }

            get href() {
                return this.getAttribute('href');
            }

            set href(newValue) {
                this.setAttribute('href', newValue);
            }

            onclick = () => {
                MicroAppRouter.navigate(this.href);
            };

            handleRouteChange = () => {
                MicroAppRouter.isActive(this.href) ? this.classList.add('active') : this.classList.remove('active');
            };

            private render = () => {
                const styleElm = document.createElement('style');
                styleElm.innerHTML = this.styleText;
                this.shadowRoot.appendChild(styleElm);
                this.shadowRoot.appendChild(document.createElement('slot'));
            };
        }
        customElements.define('micro-link', MicroLinkElement);
    }
}


================================================
FILE: src/lib/Router/Router.ts
================================================
import { ResolvedRoute, Route } from '../Interfaces/Router.interface';
import { Microfe } from '../Decorators/Microfe.decorator';

@Microfe({
    deps: ['Routes'],
})
export class MicroAppRouter {
    private oldRoute: ResolvedRoute;
    private onChangeHandlers: Array<(oldPath: string, newPath: string) => void> = [];
    private routes: Array<Route>;

    constructor({ Routes }: { Routes: Array<Route> }) {
        this.routes = Routes;
        window.onpopstate = () => {
            this.navigate(window.location.pathname);
        };

        this.navigate(window.location.pathname, true);
    }

    navigate(path: string, isSilent: boolean = false) {
        const resolvedRoute = this.resolve(MicroAppRouter.cleanPath(path));
        if (resolvedRoute) {
            if (!this.oldRoute || this.oldRoute.path !== resolvedRoute.path) {
                if (!isSilent) {
                    window.history.pushState(undefined, undefined, resolvedRoute.path);
                }
                this.changed(resolvedRoute);
            }
        } else {
            window.location.href = MicroAppRouter.cleanPath(path);
        }
    }

    onChange(fn: (oldPath: string, newPath: string, resolvedRoute?: ResolvedRoute) => void) {
        this.onChangeHandlers.push(fn);
        if (this.oldRoute) {
            fn.apply(null, [undefined, this.oldRoute.path, this.oldRoute]);
        }
    }

    isActive(pathToCheck: string): boolean {
        return this.oldRoute && MicroAppRouter.isHit(this.oldRoute.route, MicroAppRouter.cleanPath(pathToCheck));
    }

    private changed(resolvedRoute: ResolvedRoute) {
        const oldPath = this.oldRoute && this.oldRoute.path;
        this.oldRoute = {
            ...resolvedRoute,
        };
        this.onChangeHandlers.forEach(fn => {
            fn.apply(null, [oldPath, resolvedRoute.path, resolvedRoute]);
        });
    }

    private resolve(path: string): ResolvedRoute {
        const foundRoute = this.routes.find(route => MicroAppRouter.isHit(route, path));
        if (foundRoute && !foundRoute.redirectTo) {
            return {
                path: path,
                resolvedPath: foundRoute.path,
                route: {
                    ...foundRoute,
                },
            };
        } else if (foundRoute && foundRoute.redirectTo) {
            return this.resolve(foundRoute.redirectTo);
        } else {
            return undefined;
        }
    }

    private static isHit(route: Route, path: string): boolean {
        return route.path === '/' ? route.path === path : MicroAppRouter.pathToRegexp(route.path).test(path);
    }

    private static pathToRegexp(path: string): RegExp {
        return new RegExp(`^${path.replace(/\\\//g, '/').replace('*', '.*?')}`);
    }

    private static cleanPath(path: string): string {
        return path && path.replace(new RegExp(window.location.origin), '');
    }
}


================================================
FILE: src/lib/Router/RouterOutlet.ts
================================================
import { Loader } from '../Loader/Loader';
import { MicroAppRouter } from './Router';
import { ResolvedRoute } from '../Interfaces/Router.interface';
import { Microfe } from '../Decorators/Microfe.decorator';

@Microfe({
    deps: ['Loader', 'MicroAppRouter'],
})
export class RouterOutlet {
    constructor({ Loader, MicroAppRouter }: { Loader: Loader; MicroAppRouter: MicroAppRouter }) {
        class RouterOutletElement extends HTMLElement {
            shadow = this.attachShadow({ mode: 'open' });
            constructor() {
                super();
                MicroAppRouter.onChange((oldPath, newPath, resolvedRoute) =>
                    this.handlePath(oldPath, newPath, resolvedRoute)
                );
            }

            private handlePath(oldPath: string, newPath: string, resolvedRoute: ResolvedRoute) {
                if (resolvedRoute) {
                    Loader.fetchMicroApp(resolvedRoute.route.microApp);
                    const appTag = document.createElement(resolvedRoute.route.tagName);
                    while (this.shadow.firstChild) {
                        this.shadow.removeChild(this.shadow.firstChild);
                    }
                    this.shadow.appendChild(appTag);
                }
            }
        }
        customElements.define('micro-router', RouterOutletElement);
    }
}


================================================
FILE: src/lib/Store/MicroAppStore.ts
================================================
import { BehaviorSubject } from 'rxjs';
import { pluck, scan } from 'rxjs/operators';
import { Microfe } from '../Decorators/Microfe.decorator';

@Microfe()
export class MicroAppStore  {
    private subject = new BehaviorSubject({});
    private source = this.subject.pipe(scan((state, action) => this.applyReducers(state, action), this.subject.value));
    private reducers = {};

    constructor() {
        this.dispatch({type: '[@@MicroAppStore]: Init'});
    }

    private applyReducers(state, action) {
        return Object.keys(this.reducers).reduce((cum, curr) => {
            return {
                ...cum,
                [curr]: this.reducers[curr](state[curr], action) || undefined,
            };
        }, {});
    }

    public addReducer(reducerTreePiece) {
        // TODO: validate the reducer schema
        this.reducers = {
            ...this.reducers,
            ...reducerTreePiece,
        };
    }

    public dispatch(action: { type: string; payload?: any }) {
        this.subject.next(action);
    }

    public select(...selector) {
        return this.source.pipe(pluck(...selector));
    }
}


================================================
FILE: src/lib/index.ts
================================================
// PUBLIC INTERFACES
export * from './Interfaces/AppsManager.interface';
export * from './Interfaces/Router.interface';
export * from './Interfaces/Config.interface';

// PUBLIC API
export * from './Bootstrapper/bootstrapper';
export * from './Decorators/Microfe.decorator';
export * from './Provider/Provider';


================================================
FILE: src/main.ts
================================================
import { Microfe, Bootstrap, Route, ConfigInterface } from './lib';

@Microfe({
    deps: ['LayoutApp'],
})
class Main {
    constructor() {
        console.log('Initialised');
    }
}

const Routes: Route[] = [
    { path: '/', redirectTo: '/angular' },
    { path: '/angular', microApp: 'demoAngular', tagName: 'demo-angular' },
    { path: '/react', microApp: 'reactDemo', tagName: 'react-demo' },
    { path: '/static', microApp: 'staticApp', tagName: 'static-app' },
    { path: '*', microApp: 'NotFoundApp', tagName: 'not-found-app' },
];

const Config: ConfigInterface = {
    registryApi: 'http://localhost:3000/registry',
    registryPublic: 'http://localhost:3000',
};

Bootstrap(Routes, Config)(Main);


================================================
FILE: tsconfig.json
================================================
{
    "compilerOptions": {
        "sourceMap": true,
        "typeRoots": ["node_modules/@types"],
        "lib": ["es2017", "dom"],
        "target": "es6",
        "moduleResolution": "node",
        "experimentalDecorators": true
    }
}


================================================
FILE: tslint.json
================================================
{
    "jsRules": {
        "class-name": true,
        "comment-format": [
            true,
            "check-space"
        ],
        "indent": [
            true,
            "spaces"
        ],
        "no-duplicate-variable": true,
        "no-eval": true,
        "no-trailing-whitespace": true,
        "no-unsafe-finally": true,
        "one-line": [
            true,
            "check-open-brace",
            "check-whitespace"
        ],
        "quotemark": [
            true,
            "single"
        ],
        "semicolon": [
            true,
            "always"
        ],
        "triple-equals": [
            true,
            "allow-null-check"
        ],
        "variable-name": [
            true,
            "ban-keywords"
        ],
        "whitespace": [
            true,
            "check-branch",
            "check-decl",
            "check-operator",
            "check-separator",
            "check-type"
        ]
    },
    "rules": {
        "class-name": true,
        "comment-format": [
            true,
            "check-space"
        ],
        "indent": [
            true,
            "spaces"
        ],
        "no-eval": true,
        "no-internal-module": true,
        "no-trailing-whitespace": true,
        "no-unsafe-finally": true,
        "no-var-keyword": false,
        "one-line": [
            true,
            "check-open-brace",
            "check-whitespace"
        ],
        "quotemark": [
            true,
            "single"
        ],
        "semicolon": [
            true,
            "always"
        ],
        "triple-equals": [
            true,
            "allow-null-check"
        ],
        "typedef-whitespace": [
            true,
            {
                "call-signature": "nospace",
                "index-signature": "nospace",
                "parameter": "nospace",
                "property-declaration": "nospace",
                "variable-declaration": "nospace"
            }
        ],
        "variable-name": [
            true,
            "ban-keywords"
        ],
        "whitespace": [
            true,
            "check-branch",
            "check-decl",
            "check-operator",
            "check-separator",
            "check-type"
        ]
    }
}

================================================
FILE: webpack.config.js
================================================
'use strict';
const rxPaths = require('rxjs/_esm5/path-mapping');
const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');

module.exports = {
    devtool: 'inline-source-map',
    entry: './src/main.ts',
    output: {
        pathinfo: false,
    },
    mode: 'development',
    optimization: {
        removeAvailableModules: false,
        removeEmptyChunks: false,
        splitChunks: false,
    },
    module: {
        rules: [
            {
                test: /\.tsx?$/,
                use: [
                    {
                        loader: 'ts-loader',
                        options: {
                            transpileOnly: true,
                            experimentalWatchApi: true,
                        },
                    },
                ],
            },
        ],
    },
    resolve: {
        extensions: ['.ts', '.tsx', '.js'],
        modules: ['./node_modules'],
        alias: rxPaths(),
    },
    plugins: [
        new ForkTsCheckerWebpackPlugin({
            tslintAutoFix: true,
            formatter: 'codeframe',
        }),
    ],
};


================================================
FILE: webpack.production.config.js
================================================
'use strict';
const rxPaths = require('rxjs/_esm5/path-mapping');
const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');

module.exports = {
    devtool: 'inline-source-map',
    entry: './src/main.ts',
    output: {
        pathinfo: false,
    },
    mode: 'production',
    module: {
        rules: [
            {
                test: /\.tsx?$/,
                use: [
                    {
                        loader: 'ts-loader',
                        options: {
                            transpileOnly: false,
                        },
                    },
                ],
            },
        ],
    },
    resolve: {
        extensions: ['.ts', '.tsx', '.js'],
        modules: ['./node_modules'],
        alias: rxPaths(),
    },
    plugins: [
        new ForkTsCheckerWebpackPlugin({
            tslintAutoFix: true,
            formatter: 'codeframe',
        }),
    ],
};
Download .txt
gitextract_aqivtzgj/

├── .github/
│   └── ISSUE_TEMPLATE/
│       ├── bug_report.md
│       └── feature_request.md
├── .gitignore
├── .prettierrc
├── LICENSE.md
├── README.md
├── index.html
├── karma.config.js
├── package.json
├── spec.bundle.js
├── src/
│   ├── lib/
│   │   ├── AppsManager/
│   │   │   ├── AppsManager.ts
│   │   │   ├── status.enum.ts
│   │   │   └── tag.enum.ts
│   │   ├── Bootstrapper/
│   │   │   └── bootstrapper.ts
│   │   ├── Decorators/
│   │   │   └── Microfe.decorator.ts
│   │   ├── Interfaces/
│   │   │   ├── AppsManager.interface.ts
│   │   │   ├── AppsManager.internal.interface.ts
│   │   │   ├── Config.interface.ts
│   │   │   └── Router.interface.ts
│   │   ├── Loader/
│   │   │   └── Loader.ts
│   │   ├── Provider/
│   │   │   └── Provider.ts
│   │   ├── Router/
│   │   │   ├── Link.ts
│   │   │   ├── Router.ts
│   │   │   └── RouterOutlet.ts
│   │   ├── Store/
│   │   │   └── MicroAppStore.ts
│   │   └── index.ts
│   └── main.ts
├── tsconfig.json
├── tslint.json
├── webpack.config.js
└── webpack.production.config.js
Download .txt
SYMBOL INDEX (54 symbols across 13 files)

FILE: src/lib/AppsManager/AppsManager.ts
  class AppsManager (line 5) | class AppsManager {
    method constructor (line 10) | constructor() {
    method register (line 14) | register(microApp: MicroAppProvider | any) {
    method isDefinedBefore (line 38) | isDefinedBefore(microAppName: string): boolean {
    method subscribe (line 42) | subscribe(fn: (appList: MicroAppDef[]) => void) {
    method dispatch (line 46) | dispatch() {
    method checkDepsRunning (line 54) | private checkDepsRunning(microApp: MicroAppDef): boolean {
    method isCyclic (line 64) | private isCyclic(vertex: string, visited: BoolObj = {}, recStack: Bool...
    method addMicroAppToGraph (line 82) | private addMicroAppToGraph(microApp: MicroAppDef) {
    method runReadyMicroApps (line 96) | private runReadyMicroApps() {
    method updateMicroAppStatuses (line 114) | private updateMicroAppStatuses() {
    method provideDepsInstances (line 129) | private provideDepsInstances(microAppName: string, deps: string[]): { ...
    method generateAppScopedPath (line 141) | private generateAppScopedPath(microAppName: string): string {
    method generateMicroAppDef (line 147) | static generateMicroAppDef(microApp: MicroAppProvider): MicroAppDef {
    method generatePlaceholderMicroAppDef (line 156) | static generatePlaceholderMicroAppDef(name: string): MicroAppDef {

FILE: src/lib/AppsManager/status.enum.ts
  type STATUS (line 1) | enum STATUS {

FILE: src/lib/AppsManager/tag.enum.ts
  type TAG (line 1) | enum TAG {
  type TAG_TYPE (line 6) | enum TAG_TYPE {

FILE: src/lib/Interfaces/AppsManager.interface.ts
  type MicroAppMeta (line 1) | interface MicroAppMeta {
  type MicroAppProvider (line 5) | interface MicroAppProvider extends MicroAppMeta {

FILE: src/lib/Interfaces/AppsManager.internal.interface.ts
  type MicroAppDef (line 4) | interface MicroAppDef {
  type MicroAppsGraph (line 11) | interface MicroAppsGraph {
  type BoolObj (line 15) | interface BoolObj {
  type AnyObj (line 19) | interface AnyObj {

FILE: src/lib/Interfaces/Config.interface.ts
  type ConfigInterface (line 1) | interface ConfigInterface {

FILE: src/lib/Interfaces/Router.interface.ts
  type Route (line 1) | interface Route {
  type ResolvedRoute (line 8) | interface ResolvedRoute {

FILE: src/lib/Loader/Loader.ts
  class Loader (line 10) | class Loader {
    method constructor (line 14) | constructor({AppsManager, Config}: {AppsManager: AppsManager, Config: ...
    method fetchMicroApp (line 20) | fetchMicroApp(microAppName: string) {
    method onNotFoundApp (line 27) | private onNotFoundApp(appList: MicroAppDef[]) {
    method injectJsToHead (line 36) | private static injectJsToHead(id: string, appUrl: string) {

FILE: src/lib/Router/Link.ts
  class MicroLink (line 7) | class MicroLink {
    method constructor (line 8) | constructor({ MicroAppRouter }: { MicroAppRouter: MicroAppRouter }) {

FILE: src/lib/Router/Router.ts
  class MicroAppRouter (line 7) | class MicroAppRouter {
    method constructor (line 12) | constructor({ Routes }: { Routes: Array<Route> }) {
    method navigate (line 21) | navigate(path: string, isSilent: boolean = false) {
    method onChange (line 35) | onChange(fn: (oldPath: string, newPath: string, resolvedRoute?: Resolv...
    method isActive (line 42) | isActive(pathToCheck: string): boolean {
    method changed (line 46) | private changed(resolvedRoute: ResolvedRoute) {
    method resolve (line 56) | private resolve(path: string): ResolvedRoute {
    method isHit (line 73) | private static isHit(route: Route, path: string): boolean {
    method pathToRegexp (line 77) | private static pathToRegexp(path: string): RegExp {
    method cleanPath (line 81) | private static cleanPath(path: string): string {

FILE: src/lib/Router/RouterOutlet.ts
  class RouterOutlet (line 9) | class RouterOutlet {
    method constructor (line 10) | constructor({ Loader, MicroAppRouter }: { Loader: Loader; MicroAppRout...

FILE: src/lib/Store/MicroAppStore.ts
  class MicroAppStore (line 6) | class MicroAppStore  {
    method constructor (line 11) | constructor() {
    method applyReducers (line 15) | private applyReducers(state, action) {
    method addReducer (line 24) | public addReducer(reducerTreePiece) {
    method dispatch (line 32) | public dispatch(action: { type: string; payload?: any }) {
    method select (line 36) | public select(...selector) {

FILE: src/main.ts
  class Main (line 3) | @Microfe({
    method constructor (line 7) | constructor() {
Condensed preview — 31 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (42K chars).
[
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.md",
    "chars": 834,
    "preview": "---\nname: Bug report\nabout: Create a report to help us improve\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\n**Describe the b"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.md",
    "chars": 595,
    "preview": "---\nname: Feature request\nabout: Suggest an idea for this project\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\n**Is your fea"
  },
  {
    "path": ".gitignore",
    "chars": 27,
    "preview": "node_modules/\ndist/\n.idea/\n"
  },
  {
    "path": ".prettierrc",
    "chars": 188,
    "preview": "{\n  \"trailingComma\": \"es5\",\n  \"tabWidth\": 4,\n  \"semi\": true,\n  \"singleQuote\": true,\n  \"jsxSingleQuote\": true,\n  \"bracket"
  },
  {
    "path": "LICENSE.md",
    "chars": 1066,
    "preview": "MIT License\n\nCopyright (c) 2018 Öner Zafer\n\nPermission is hereby granted, free of charge, to any person obtaining a copy"
  },
  {
    "path": "README.md",
    "chars": 11476,
    "preview": "# *microfe*\n*(microfe - short for micro frontends)*\n\nA naive infrastructure/meta-framework implementation for micro fron"
  },
  {
    "path": "index.html",
    "chars": 243,
    "preview": "<html>\n<head>\n    <title>Test App</title>\n    <style>\n        body, html {\n            margin: 0;\n            padding: 0"
  },
  {
    "path": "karma.config.js",
    "chars": 584,
    "preview": "const webpackConfig = require('./webpack.config.js');\nwebpackConfig.mode = 'production';\n\nmodule.exports = function(conf"
  },
  {
    "path": "package.json",
    "chars": 919,
    "preview": "{\n  \"name\": \"micro-fe\",\n  \"version\": \"0.0.1\",\n  \"description\": \"A naive micro frontend solution\",\n  \"main\": \"index.js\",\n"
  },
  {
    "path": "spec.bundle.js",
    "chars": 101,
    "preview": "var testsContext = require.context(\".\", true, /.spec.ts/);\ntestsContext.keys().forEach(testsContext);"
  },
  {
    "path": "src/lib/AppsManager/AppsManager.ts",
    "chars": 6193,
    "preview": "import { STATUS } from './status.enum';\nimport { MicroAppProvider } from '../Interfaces/AppsManager.interface';\nimport {"
  },
  {
    "path": "src/lib/AppsManager/status.enum.ts",
    "chars": 90,
    "preview": "export enum STATUS {\n    NOTFOUND = 0,\n    WAITING = 1,\n    READY = 2,\n    RUNNING = 3,\n}\n"
  },
  {
    "path": "src/lib/AppsManager/tag.enum.ts",
    "chars": 146,
    "preview": "export enum TAG {\n    script = 'script',\n    style = 'style',\n}\n\nexport enum TAG_TYPE {\n    script = 'text/javascript',\n"
  },
  {
    "path": "src/lib/Bootstrapper/bootstrapper.ts",
    "chars": 1052,
    "preview": "import { AppsManager } from '../AppsManager/AppsManager';\nimport { Route } from '..';\nimport { Loader } from '../Loader/"
  },
  {
    "path": "src/lib/Decorators/Microfe.decorator.ts",
    "chars": 253,
    "preview": "import { MicroAppMeta } from '..';\n\nexport const Microfe = function(meta?: MicroAppMeta ) {\n    return function(WrappedC"
  },
  {
    "path": "src/lib/Interfaces/AppsManager.interface.ts",
    "chars": 187,
    "preview": "export interface MicroAppMeta {\n    deps?: string[];\n}\n\nexport interface MicroAppProvider extends MicroAppMeta {\n    nam"
  },
  {
    "path": "src/lib/Interfaces/AppsManager.internal.interface.ts",
    "chars": 430,
    "preview": "import { STATUS } from '../AppsManager/status.enum';\nimport { MicroAppProvider } from './AppsManager.interface';\n\nexport"
  },
  {
    "path": "src/lib/Interfaces/Config.interface.ts",
    "chars": 114,
    "preview": "export interface ConfigInterface {\n    registryApi: string;\n    registryPublic: string;\n    [key: string]: any;\n}\n"
  },
  {
    "path": "src/lib/Interfaces/Router.interface.ts",
    "chars": 288,
    "preview": "export interface Route {\n    path: string;\n    tagName?: string;\n    redirectTo?: string;\n    microApp?: string;\n}\n\nexpo"
  },
  {
    "path": "src/lib/Loader/Loader.ts",
    "chars": 1731,
    "preview": "import { AppsManager } from '../AppsManager/AppsManager';\nimport { TAG, TAG_TYPE } from '../AppsManager/tag.enum';\nimpor"
  },
  {
    "path": "src/lib/Provider/Provider.ts",
    "chars": 110,
    "preview": "export const Provide = (name: string, provideable: any) => ({\n    name,\n    initialize: () => provideable,\n});"
  },
  {
    "path": "src/lib/Router/Link.ts",
    "chars": 1533,
    "preview": "import { MicroAppRouter } from './Router';\nimport { Microfe } from '../Decorators/Microfe.decorator';\n\n@Microfe({\n    de"
  },
  {
    "path": "src/lib/Router/Router.ts",
    "chars": 2907,
    "preview": "import { ResolvedRoute, Route } from '../Interfaces/Router.interface';\nimport { Microfe } from '../Decorators/Microfe.de"
  },
  {
    "path": "src/lib/Router/RouterOutlet.ts",
    "chars": 1350,
    "preview": "import { Loader } from '../Loader/Loader';\nimport { MicroAppRouter } from './Router';\nimport { ResolvedRoute } from '../"
  },
  {
    "path": "src/lib/Store/MicroAppStore.ts",
    "chars": 1131,
    "preview": "import { BehaviorSubject } from 'rxjs';\nimport { pluck, scan } from 'rxjs/operators';\nimport { Microfe } from '../Decora"
  },
  {
    "path": "src/lib/index.ts",
    "chars": 312,
    "preview": "// PUBLIC INTERFACES\nexport * from './Interfaces/AppsManager.interface';\nexport * from './Interfaces/Router.interface';\n"
  },
  {
    "path": "src/main.ts",
    "chars": 713,
    "preview": "import { Microfe, Bootstrap, Route, ConfigInterface } from './lib';\n\n@Microfe({\n    deps: ['LayoutApp'],\n})\nclass Main {"
  },
  {
    "path": "tsconfig.json",
    "chars": 242,
    "preview": "{\n    \"compilerOptions\": {\n        \"sourceMap\": true,\n        \"typeRoots\": [\"node_modules/@types\"],\n        \"lib\": [\"es2"
  },
  {
    "path": "tslint.json",
    "chars": 2283,
    "preview": "{\n    \"jsRules\": {\n        \"class-name\": true,\n        \"comment-format\": [\n            true,\n            \"check-space\"\n "
  },
  {
    "path": "webpack.config.js",
    "chars": 1111,
    "preview": "'use strict';\nconst rxPaths = require('rxjs/_esm5/path-mapping');\nconst ForkTsCheckerWebpackPlugin = require('fork-ts-ch"
  },
  {
    "path": "webpack.production.config.js",
    "chars": 927,
    "preview": "'use strict';\nconst rxPaths = require('rxjs/_esm5/path-mapping');\nconst ForkTsCheckerWebpackPlugin = require('fork-ts-ch"
  }
]

About this extraction

This page contains the full source code of the onerzafer/microfe-client GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 31 files (38.2 KB), approximately 9.6k tokens, and a symbol index with 54 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!