This content originally appeared on DEV Community and was authored by Issam El Nasiri
Hello everyone! This is my first time doing a tutorial so I'll hope you like it! In this tutorial, we'll learn how to create a very simple web application with Firebase based on the Micro Frontend Architecture.
Defining Our Micro Frontend
There are two ways to create your own micro frontend. The first one is horizontal split which basically means that you will have multiple applications running on 1 page/view. The second one is the vertical split which is one application running on 1 page/view.
For the sake of this tutorial, we will be using the vertical split.
Let's start with cloning the starters repo:
run
npm install
in the root folder.
STEP 1 - React Micro App
We need to setup 4 things before implementing Firebase:
- Add
.rescriptsrc.js
file - Add
.env
file - Add
public-path.js
file - Edit the
index.js
file
.rescriptsrc.js
The .rescriptsrc.js is a file where we can configure settings for launching the micro application. Create the file in the root folder of react and add following code:
const { name } = require('./package');
module.exports = {
webpack: config => {
config.output.library = `${name}-[name]`;
config.output.libraryTarget = 'umd';
config.output.jsonpFunction = `webpackJsonp_${name}`;
config.output.globalObject = 'window';
return config;
},
devServer: _ => {
const config = _;
config.headers = {
'Access-Control-Allow-Origin': '*',
};
config.historyApiFallback = true;
config.hot = false;
config.watchContentBase = false;
config.liveReload = false;
return config;
},
};
.env
We also need to create a .env file to store our keys and port.
Create the file and add following code:
SKIP_PREFLIGHT_CHECK=true
BROWSER=none
PORT=7100
WDS_SOCKET_PORT=7100
REACT_APP_FIREBASE_API_KEY=<key>
REACT_APP_FIREBASE_AUTH_DOMAIN=<key>
REACT_APP_FIREBASE_PROJECT_ID=<key>
REACT_APP_FIREBASE_STORAGE_BUCKET=<key>
REACT_APP_FIREBASE_MESSAGING_SENDER_ID=<key>
REACT_APP_FIREBASE_APP_ID=<key>
public-path.js
In the source folder of the micro app. We need to define the public path for the application. Create the file with the same name as the title and add following code:
if (window.__POWERED_BY_QIANKUN__) {
// eslint-disable-next-line no-undef
__webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
}
Qiankun will define the public path through the main shell.
index.js
Now we need to edit the index.js file so that the main shell will find this application.
Copy the code below and paste it in the index.js file:
import './public-path';
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import * as serviceWorker from './serviceWorker';
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);
function render (props) {
const { container } = props;
ReactDOM.render(
<App />,
container
? container.querySelector('#root')
: document.querySelector('#root')
);
}
// This is to render the micro application when not going through the main shell
if (!window.__POWERED_BY_QIANKUN__) {
render({});
}
export async function bootstrap () {
console.log('react app bootstraped');
}
export async function mount (props) {
console.log('react props from main framework', props);
render(props);
}
export async function unmount (props) {
const { container } = props;
ReactDOM.unmountComponentAtNode(
container
? container.querySelector('#root')
: document.querySelector('#root')
);
}
serviceWorker.unregister();
There are three functions/methods that are needed with each micro application:
- bootstrap
- mount
- unmount
Without those 3 methods the micro app will not load through the main shell.
Firebase
in the src folder of the react app, we need to create a new folder called firebase. In that folder we'll create a new javascript file with the name "firebaseConfig.js".
Add the following code to setup your firebase and import extra packages if needed (like storage, firestore,...) we only need the auth package.
import firebase from 'firebase/app';
import 'firebase/auth';
const config = {
apiKey: process.env.REACT_APP_FIREBASE_API_KEY,
authDomain: process.env.REACT_APP_FIREBASE_AUTH_DOMAIN,
projectId: process.env.REACT_APP_FIREBASE_PROJECT_ID,
storageBucket: process.env.REACT_APP_FIREBASE_STORAGE_BUCKET,
messagingSenderId: process.env.REACT_APP_FIREBASE_MESSAGING_SENDER_ID,
appId: process.env.REACT_APP_FIREBASE_APP_ID,
};
var fb = null;
// Check how many times the firebase app is initialized.
if (firebase.apps.length === 0) {
fb = firebase.initializeApp(config);
console.log('Firebase [react] Initialized');
} else {
console.log('Firebase [react] is already Initialized');
}
export default fb;
App.js
now we can start editing our App.js to show two input elements for registering a new user.
First, let's handle the imports. These 3 are the only one needed so you can remove the other ones.
import React, {useState} from 'react';
import './App.css';
import fb from './firebase/firebaseConfig';
Afterwards, let's setup a state for an email and a password and a method to register:
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const onSubmit = () => {
fb.auth()
.createUserWithEmailAndPassword(email, password)
.then(() => {
console.log("route to vue app.");
window.history.pushState(null, "/vueapp", "/vueapp");
})
.catch((error) => {
console.log(error);
});
};
Now we'll edit the html code to show 2 inputs and a button:
<div className="app-main">
<h1>React App</h1>
<label for="email">Email</label>
<input
name="email"
type="text"
value={email}
onChange={(event) => setEmail(event.target.value)}
></input>
<label for="password">Password</label>
<input
name="password"
type="password"
value={password}
onChange={(event) => setPassword(event.target.value)}
></input>
<button onClick={onSubmit}>Register</button>
</div>
That should be it for the react micro application.
STEP 2 - Vue Micro App
After signing up we want to redirect the user to our vue micro app. In that application we'll show the users email.
Navigate to the vueapp folder.
Now we only need to do 5 things:
- Create a
vue.config.js
file - Add a
public-path.js
file - Edit the
main.js
file - Configure Firebase
- Edit the
Home.vue
vue.config.js
Let's create vue.config.js in our root folder of the vue micro app. The public path should be the name of your micro app. In our case, we'll put /vue.
const { name } = require('../package.json');
module.exports = {
publicPath: '/vueapp',
chainWebpack: config => config.resolve.symlinks(false),
configureWebpack: {
output: {
library: `${name}-[name]`,
libraryTarget: 'umd',
jsonpFunction: `webpackJsonp_${name}`
}
},
devServer: {
port: process.env.VUE_APP_PORT,
headers: {
'Access-Control-Allow-Origin': '*'
}
}
};
public-path.js
In the src folder of the vue app, we'll add the public path with following code:
(function() {
if (window.__POWERED_BY_QIANKUN__) {
if (process.env.NODE_ENV === 'development') {
__webpack_public_path__ = `//localhost:${process.env.VUE_APP_PORT}${process.env.BASE_URL}`;
return;
}
__webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
}
})();
main.js
We need to setup the 3 things that a micro app always needs. So to do that, we need to remove:
const router = new VueRouter({
base: window.__POWERED_BY_QIANKUN__ ? routerBase : process.env.BASE_URL,
mode: 'history',
routes
});
new Vue({
render: h => h(App),
}).$mount('#app')
and add:
let instance = null;
function render(props = {}) {
const { container, routerBase } = props;
const router = new VueRouter({
base: window.__POWERED_BY_QIANKUN__ ? routerBase : process.env.BASE_URL,
mode: 'history',
routes
});
instance = new Vue({
router,
render: h => h(App)
}).$mount(container ? container.querySelector('#app') : '#app');
}
if (!window.__POWERED_BY_QIANKUN__) {
render();
}
export async function bootstrap() {
console.log('[vue] vue app bootstraped');
}
export async function mount(props) {
console.log('[vue] props from main framework', props);
render(props);
}
export async function unmount() {
instance.$destroy();
instance.$el.innerHTML = '';
instance = null;
}
Firebase
This is pretty much the same as in the react application.
We'll create a new folder called Firebase in the src folder. After that we'll create a new file called FirebaseConfig.js with following code:
import firebase from 'firebase/app';
import 'firebase/auth';
const config = {
apiKey: '<key>',
authDomain: '<key>',
projectId: ' <key>',
storageBucket: '<key>',
messagingSenderId: '<key>',
appId: '<key>',
measurementId: '<key>'
};
var fb = null;
if (firebase.apps.length === 0) {
fb = firebase.initializeApp(config);
console.log('Firebase [Vue] Initialized');
} else {
console.log('Firebase [Vue] is already Initialized');
}
export default fb;
Home.vue
Now we need to configure our Home.vue
First we'll import the firebase config
import fb from '../firebase/firebaseConfig';
After that we wanna add two fields [User, isLoaded]
data() {
return {
user: {},
isLoaded: false
};
},
In the created we are gonna add the firebase onAuthStateChanged to wait for the user.
created() {
fb.auth().onAuthStateChanged(user => {
this.user = user;
this.isLoaded = true;
});
}
The only thing we need to do is edit the template tag to show the email.
<template>
<div>
<h1>Vue App</h1>
<h1 v-if="isLoaded">Welcome! {{ user.email }}</h1>
<h6 v-if="!isLoaded">Loading...</h6>
</div>
</template>
Quick Note
You have to give a port through the env file so create in the root of the vue application an .env file and add following line:
VUE_APP_PORT=7777
That's it for the vue micro app!
STEP 3 - Main Shell
When working with a Micro Frontend Architecture, we need to have one main shell that will be used to show our other micro applications. Our main shell will be in Vue.
Creation
Navigate to the main shell folder.
We will be using the package Qiankun
(This is a micro frontend framework)
Now we only need to do 4 things:
- Create a
vue.config.js
file - Add a
micro-apps.js
file - Edit the
main.js
file - Edit the
App.vue
vue.config.js
In the root folder of the main-shell, we'll create a new file called vue.config.js
. In that file we'll add the following code:
module.exports = {
configureWebpack: {
module: {
rules: [
{
test: /\.(ttf|otf|eot|woff|woff2)$/,
use: {
loader: 'file-loader',
options: {
name: 'fonts/[name].[ext]'
}
}
}
]
}
}
};
This will be used when using different fonts in your application.
micro-apps.js
In the src
folder of the main-shell, we'll create a new file called micro-apps.js
. This file will be used to define our micro applications.
// This is where we define our micro applications
const microApps = [
{
name: 'reactapp',
entry: '//localhost:7100',
activeRule: '/reactapp'
},
{
name: 'vue',
entry: '//localhost:7777/vueapp',
activeRule: '/vueapp'
}
];
const apps = microApps.map((item) => {
return {
...item,
// this will be the element where the micro application will be in
container: "#subapp-viewport",
props: {
routerBase: item.activeRule,
},
};
});
export default apps;
main.js
This is where the fun begins! ??
Firstly, we need to import methods from Qiankun and the micro-app.js
into the main.js
file.
import { registerMicroApps, start, setDefaultMountApp } from "qiankun";
import microApps from "./micro-apps";
Secondly, we need to register our micro apps and setting a default route. After that we just need to run the start method. Add the following code at the end of the file.
const apps = microApps.map((item) => {
return {
...item,
};
});
registerMicroApps(apps, {
beforeLoad: (app) => {
console.log("before load app.name====>>>>>", app.name);
},
beforeMount: [
(app) => {
console.log("[LifeCycle] before mount %c%s", "color: green;", app.name);
},
],
afterMount: [
(app) => {
console.log("[LifeCycle] after mount %c%s", "color: green;", app.name);
},
],
afterUnmount: [
(app) => {
console.log("[LifeCycle] after unmount %c%s", "color: green;", app.name);
},
],
});
setDefaultMountApp("/reactapp");
start();
App.vue
The last one!
First, let's change the HTML code.
Change the HTML to this:
<template>
<div id="subapp-viewport"></div>
</template>
This will put our current micro application inside the div element.
Next up, the script tag will have 2 methods. We also need to import micro-app.js again to bind it to the current route and some fields to our data function.
import microApps from "./micro-apps";
data() {
return {
microApps,
current: "/reactapp",
};
},
The 2 methods that are needed. The first one binds the current path to the current Path field in the App.vue. The second method will listen to any router changes.
methods: {
// Binds the current path to the current Path in the main shell
bindCurrent() {
const path = window.location.pathname;
if (this.microApps.findIndex((item) => item.activeRule === path) >= 0) {
this.current = path;
}
},
// Will listen to any router changes
listenRouterChange() {
const _wr = function (type) {
const orig = history[type];
return function () {
const rv = orig.apply(this, arguments);
const e = new Event(type);
e.arguments = arguments;
window.dispatchEvent(e);
return rv;
};
};
history.pushState = _wr("pushState");
// will listen when navigating to another micro application
window.addEventListener("pushState", this.bindCurrent);
window.addEventListener("popstate", this.bindCurrent);
this.$once("hook:beforeDestroy", () => {
window.removeEventListener("pushState", this.bindCurrent);
window.removeEventListener("popstate", this.bindCurrent);
});
},
},
Lastly, we need to call our bindCurrent method the created and the
listenRouterChange in mounted:
created() {
this.bindCurrent();
},
mounted() {
this.listenRouterChange();
},
That's it!
Now to see it in action. Run the main shell and the 2 micro applications with the command npm run start
.
Navigate to http://localhost:8080/
where you should be seeing this:
You can find the complete code for this tutorial on the completed/tutorial branch of the starters Repo
I hope you find this tutorial somewhat useful. I apologize for my writing skills as I am still learning on how to explain things in a better way ??.
I recommend reading this medium article If you are interested in learning more about micro frontends!
Micro-frontends decisions framework | by Luca Mezzalira | Medium
Luca Mezzalira ・ ・ 7 min read
Medium
Thank you! ?
This content originally appeared on DEV Community and was authored by Issam El Nasiri
Issam El Nasiri | Sciencx (2021-03-13T02:07:26+00:00) Let’s Create A Web Application With Micro Frontends And Firebase. Retrieved from https://www.scien.cx/2021/03/13/lets-create-a-web-application-with-micro-frontends-and-firebase/
Please log in to upload a file.
There are no updates yet.
Click the Upload button above to add an update.