- module-federation-examples
- module-federation-vite-react
https://github.com/module-federation
Angular, React and Spring Boot Developer
There are three new categories, four categories with naming and scoping changes, and some consolidation in the Top 10 for 2021.

single spa root config -index ejs
------------------------------------
dynamic load balancer and load the latest build to ui app
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Single SPA root config</title>
<script src="https://cdn.jsdelivr.net/npm/regenerator-runtime@0.13.7/runtime.min.js"></script>
<link
rel="preload"
href="https://cdn.jsdelivr.net/npm/single-spa@5.9.0/lib/system/single-spa.min.js"
as="script"
/>
<!--
This CSP allows any SSL-enabled host and for arbitrary eval(), but you should limit these directives further to increase your app's security.
Learn more about CSP policies at https://content-security-policy.com/#directive
-->
<!-- <meta http-equiv="Content-Security-Policy" content="default-src 'self' https: localhost:*; script-src 'unsafe-inline' 'unsafe-eval' https: localhost:*; connect-src https: localhost:* ws://localhost:*; style-src 'unsafe-inline' https:; object-src 'none';"> -->
<meta name="importmap-type" content="systemjs-importmap" />
<!-- Add your organization's prod import map URL to this script's src -->
<script src="https://cdn.jsdelivr.net/npm/zone.js@0.11.3/dist/zone.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/import-map-overrides@2.2.0/dist/import-map-overrides.js"></script>
<% if (isLocal) { %>
<script src="https://cdn.jsdelivr.net/npm/systemjs@6.8.3/dist/system.js"></script>
<script src="https://cdn.jsdelivr.net/npm/systemjs@6.8.3/dist/extras/amd.js"></script>
<% } else { %>
<script src="https://cdn.jsdelivr.net/npm/systemjs@6.8.3/dist/system.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/systemjs@6.8.3/dist/extras/amd.min.js"></script>
<% } %>
</head>
<body>
<noscript> You need to enable JavaScript to run this app. </noscript>
<div id="nav-container"></div>
<main>
<div id="mfe1-container"></div>
<div id="mfe2-container"></div>
</main>
<div id="root"></div>
<script async>
async function isFirstPoolUp(url) {
try {
const response = await fetch(url, { method: 'HEAD' });
console.log('The URL is valid and accessible.');
return true;
} catch (error) {
console.error('Error fetching the URL:', error);
return false;
}
}
let poolOne = '';
(async () => {
let url = '';
let env = 'dev';
if(window.location.hostname.includes('prod')) {
url = "https://mfe1-godaddy-prod.com/main.js";
env = 'prod';
} else if(window.location.hostname.includes('test')) {
url = "https://mfe1-godaddy-test.com/main.js";
env = 'test';
} else {
url = "https://mfe1-godaddy-dev.com/main.js";
}
poolOne = await isFirstPoolUp(url);
console.log(poolOne);
// Create a dynamic import map based on window.location
const importMap = {
imports: {
"single-spa": "https://cdn.jsdelivr.net/npm/single-spa@5.9.0/lib/system/single-spa.min.js",
"@mfeappsinglespa/root-config": "/main.js",
"react": "https://cdn.jsdelivr.net/npm/react@17/umd/react.production.min.js",
"react-dom": "https://cdn.jsdelivr.net/npm/react-dom@17/umd/react-dom.production.min.js",
"@mfeappsinglespa/mfe1": env == 'prod' ? "https://mfe1-godaddy-prod.com/main.js?"+Date.now() : env == 'test' ? "https://mfe1-godaddy-test.com/main.js?"+Date.now() : "https://mfe1-godaddy-dev.com/main.js/main.js?"+Date.now(),
"@mfeappsinglespa/mfe2": env == 'prod' ? "https://mfe2-godaddy-prod.com/main.js?"+Date.now() : env == 'test' ? "https://mfe1-godaddy-test.com/main.js?"+Date.now() : "https://mfe1-godaddy-dev.com/main.js/main.js?"+Date.now(),
}
};
const importMap2 = {
imports: {
"single-spa": "https://cdn.jsdelivr.net/npm/single-spa@5.9.0/lib/system/single-spa.min.js",
"@mfeappsinglespa/root-config": "/main.js",
"react": "https://cdn.jsdelivr.net/npm/react@17/umd/react.production.min.js",
"react-dom": "https://cdn.jsdelivr.net/npm/react-dom@17/umd/react-dom.production.min.js",
"@mfeappsinglespa/mfe1": env == 'prod' ? "https://mfe1-godaddy-prod2.com/main.js?"+Date.now() : env == 'test' ? "https://mfe1-godaddy-test2.com/main.js?"+Date.now() : "https://mfe1-godaddy-dev2.com/main.js/main.js?"+Date.now(),
"@mfeappsinglespa/mfe2": env == 'prod' ? "https://mfe2-godaddy-prod2.com/main.js?"+Date.now() : env == 'test' ? "https://mfe1-godaddy-test2.com/main.js?"+Date.now() : "https://mfe1-godaddy-dev2.com/main.js/main.js?"+Date.now(),
}
};
// Inject the import map into the document
const script = document.createElement('script');
script.type = 'systemjs-importmap';
script.textContent = JSON.stringify(poolOne ? importMap : importMap2);
document.head.appendChild(script);
// Import the main module
System.import('@mfeappsinglespa/root-config').catch(console.error);
})();
</script>
<import-map-overrides-full
show-when-local-storage="devtools"
dev-libs
></import-map-overrides-full>
</body>
</html>
Setting Prettier on a React Typescript project:
===============================================
Step 1: Create a React Project with Typescript
npx create-react-app my-app --template typescript
Step 2: Install Prettier package
npm install --save-dev --save-exact prettier
Step 3: ‘prettierrc.json’ file
Create a ‘.prettierrc.json’ file and add some prettier rules:
Example:
{
"trailingComma": "es5",
"tabWidth": 4,
"semi": false,
"singleQuote": true
}
Step 4: ‘.prettierignore’ file
Create a ‘.prettierignore ‘ file and add the follow:
node_modules
# Ignore artifacts:
build
coverage
Step 5: Running Prettier
Inside the project directory, open a terminal.
To run Prettier and format the code, just run:
npx prettier --write <targetFile>
Step 5.1: Let’s Run!
On the project that we create, let’s run prettier over the file App.tsx.
npx prettier --write src/App.tsx
npx prettier --write . ( For all files )
Reference from YouTube Channel: Sahil & Sarra
► Everything in one place: Datacamp Associate Data Scientist with Python Career Track: https://datacamp.pxf.io/ds-trackData Scientist Certification: https://datacamp.pxf.io/ds-cert
► In this video we covered: 1. How to actually learn Data Science? 2. What skills do you need to develop? 3. What are the best Data Science courses and Certifications? ► Links to everything discussed in the video: 1. Khan academy Linear Algebra: https://www.khanacademy.org/math/line...
2. Khan academy Calculus: https://www.khanacademy.org/math/calc...
3. Khan academy Statistics and Probability: https://www.khanacademy.org/math/stat...
4. Python: https://www.learnpython.org/
5. SQL: https://www.w3schools.com/sql/
6. Machine Learning Specialization: https://imp.i384100.net/machine-learn...
7. Kaggle: https://www.kaggle.com/
Module Federation
The Module Federation is actually part of Webpack config. This config enables us to expose or receive different parts of the CRA to another CRA project. These separate project should not have dependencies between each other, so they can be developed and deployed individually.
Let’s first start by creating our Container project which exports other two app APP-1 and APP-2.
step:1
npx create-react-app container --template typescript
step:2
Container App
npm install html-webpack-plugin serve ts-loader webpack webpack-cli webpack-dev-server @chakra-ui/react @emotion/react@^11 @emotion/styled@^11 framer-motion@^5
step:3
index.tsx -> bootstrap.tsx
move content
step:4
index.tsx ->index.ts
import("./bootstrap");
export {};
step:5
App.tsx:
import { Box, Center, Flex, Heading, Spinner, Image, Link, Text } from '@chakra-ui/react';
import React from 'react';
const CounterAppOne = React.lazy(() => import('app1/MFE1WebpackAppName1')); //// impoert('appName/exposeCompoent');
const CounterAppTwo = React.lazy(() => import('app2/MFE2WebpackAppName2'));
export const App=()=>{
return(
<>
<React.Suspense fallback={<>loading... </>}>
<CounterAppOne />
</React.Suspense >
<React.Suspense fallback={<>loading... </>}>
<CounterAppTwo />
</React.Suspense >
</>
)
step:6
webpack.config.js
const HtmlWebpackPlugin = require("html-webpack-plugin");
const webpack = require("webpack"); // only add this if you don't have yet
const { ModuleFederationPlugin } = webpack.container;
const deps = require("./package.json").dependencies;
const buildDate = new Date().toLocaleString();
module.exports = (env, argv) => {
const isProduction = argv.mode === "production";
console.log({ isProduction });
return {
entry: "./src/index.ts",
mode: process.env.NODE_ENV || "development",
devServer: {
port: 3000,
open: true,
},
resolve: {
extensions: [".ts", ".tsx", ".js"],
},
module: {
rules: [
{
test: /\.(js|jsx|tsx|ts)$/,
loader: "ts-loader",
exclude: /node_modules/,
},
],
},
plugins: [
new webpack.EnvironmentPlugin({ BUILD_DATE: buildDate }),
new webpack.DefinePlugin({
"process.env": JSON.stringify(process.env),
}),
new ModuleFederationPlugin({
name: "container",
remotes: {
app1: "app1@http://localhost:3001/remoteEntry.js",
app2: "app2@http://localhost:3002/remoteEntry.js",
},
shared: {
...deps,
react: { singleton: true, eager: true, requiredVersion: deps.react },
"react-dom": {
singleton: true,
eager: true,
requiredVersion: deps["react-dom"],
},
},
}),
new HtmlWebpackPlugin({
template: "./public/index.html",
}),
],
};
};
step:7
Update your package.json scripts as follows:
"scripts": {
"start": "webpack serve --open",
"build": "webpack --config webpack.prod.js",
"serve": "serve dist -p 3000",
"clean": "rm -rf dist"
}
step:8
Update your tsconfig as follows:
tsconfig.ts
{
"compilerOptions": {
"target": "es5",
"lib": ["dom", "dom.iterable", "esnext"],
"baseUrl": "./",
"allowJs": true,
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"noFallthroughCasesInSwitch": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": false,
"jsx": "react-jsx"
},
"include": ["src"]
}
step:9
Create a .env in the project root folder:
DEV_APP1="MFE1WebpackAppName1@http://localhost:3001/remoteEntry.js"
DEV_APP2="app2@http://localhost:3002/remoteEntry.js"
PROD_APP1="MFE1WebpackAppName1@http://YOUR_APPLICATION_PRODUCTION_URL_HERE/remoteEntry.js"
PROD_APP2="app2@http://YOUR_APPLICATION_PRODUCTION_URL_HERE/remoteEntry.js"
npm start ( need to run all mfe's in standalone mode)
npm run build
then dist will create with mentioned remoteEntry.js files
npm run serve will provide the
MFE-1 ( app1)
step:1
npx create-react-app app-1 --template typescript
yarn add html-webpack-plugin serve ts-loader webpack webpack-cli webpack-dev-server @chakra-ui/react @emotion/react@^11 @emotion/styled@^11 framer-motion@^5
Just like we did in Container app we’ll setup bootstrap.tsx, index.ts and app.tsx.
bootstrap.tsx
import App from './App';
import React from 'react';
import ReactDOM from 'react-dom/client';
import { ChakraProvider } from "@chakra-ui/react";
const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement)
root.render(
<ChakraProvider>
<App />
</ChakraProvider>
);
Copy
And add those into index.ts
index.ts
import("./bootstrap");
App.tsx
import CounterAppOne from './components/CounterAppOne';
const App = () => (
<Box margin="1.2rem">
<Box>APP-1</Box>
<Box>
<CounterAppOne />
</Box>
</Box>
);
export default App;
step:4
webpack config.js
const HtmlWebpackPlugin = require("html-webpack-plugin");
const { ModuleFederationPlugin } = require("webpack").container;
const path = require("path");
const deps = require("./package.json").dependencies;
module.exports = {
entry: "./src/index.ts",
mode: "development",
devServer: {
port: 3001,
open: true,
},
resolve: {
extensions: [".ts", ".tsx", ".js"],
},
module: {
rules: [
{
test: /\.(js|jsx|tsx|ts)$/,
loader: "ts-loader",
exclude: /node_modules/,
},
],
},
plugins: [
new ModuleFederationPlugin({
name: "app1",
filename: "remoteEntry.js",
exposes: {
// expose each component
"./MFE1WebpackAppName1": "./src/components/CounterAppOne.tsx",
(OR)
"./MFE1WebpackAppName1": "./src/App.tsx",
},
shared: {
...deps,
react: { singleton: true, eager: true, requiredVersion: deps.react },
"react-dom": {
singleton: true,
eager: true,
requiredVersion: deps["react-dom"],
},
},
}),
new HtmlWebpackPlugin({
template: "./public/index.html",
}),
],
};
step:5
Update your package.json scripts as follows:
"scripts": {
"start": "webpack serve --open",
"build": "webpack --config webpack.prod.js",
"serve": "serve dist -p 3001",
"clean": "rm -rf dist"
}
step:6
tsconfig.ts
{
"compilerOptions": {
"target": "es5",
"lib": ["dom", "dom.iterable", "esnext"],
"baseUrl": "./",
"allowJs": true,
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"noFallthroughCasesInSwitch": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": false,
"jsx": "react-jsx"
},
"include": ["src"]
}
In the host app -
remotes: {
app1: 'app1@http://localhost:3001/remoteEntry.js',
},
step:7
npm run build
then dist will create
npm run serve
1
https://javascript.info/rest-parameters-spread
1.https://developer.mozilla.org/
https://developer.mozilla.org/en-US/docs/Web/JavaScript
https://developer.mozilla.org/en-US/docs/Web/API
https://developer.mozilla.org/en-US/docs/Web/Tutorials
Git flow is a Git branching strategy .
Git flow is not a tool or software that can be downloaded. Developers can use Git flow to organize their Git branches and development process to ship releases more efficiently.
Best practices for Source code management (SCM)
Other
GitHub Flow:
===========
More simple than Git flow, GitHub flow is great for smaller teams and web applications or products that don’t require supporting multiple versions. Because of its simplicity, the GitHub flow workflow allows for continuous delivery and continuous integration.
Of course, there are also related risks to consider. The lack of dedicated development branches, for example, makes this workflow more susceptible to bugs in production.
GitLab Flow:
===========
Also more simple than Git flow, GitLab flow is more organized and structured when compared to the GitHub flow workflow.
GitLab flow introduces environment branches, such as production and pre-production, or release branches, depending on your situation.
With slight modifications, GitLab flow can allow for versioned releases and continuous delivery.
import React, { useState, useEffect } from "react";
import axios from "axios";
import "./styles.css";
const memo = callback => {
const cache = new Map();
return (...args) => {
const selector = JSON.stringify(args);
if (cache.has(selector)) return cache.get(selector);
const value = callback(...args);
cache.set(selector, value);
return value;
};
};
const memoizedAxiosGet = memo(axios.get);
const SelectPokemonButton = ({ name, onClick }) => (
<button onClick={() => onClick(name)}>{name}</button>
);
export default function App() {
const [pokemon, setPokemon] = useState("");
const [pokemonData, setPokemonData] = useState({});
useEffect(() => {
if (pokemon) {
memoizedAxiosGet(`https://pokeapi.co/api/v2/pokemon/${pokemon}/`)
.then(response => {
setPokemonData(response);
})
.catch(error => {
console.error("Error retrieving pokemon with name ", pokemon);
});
}
}, [pokemon]);
const onClickPokemon = name => {
setPokemon(name);
};
return (
<div className="App">
<h1>Memoization request Demo</h1>
<h3>Before clicking the buttons, open the devtools.</h3>
<h3>
Check that, wih every click on different pokemon, the network request is
done
</h3>
<h3>
But, if the pokemon is clicked for second time, the request wont be done
</h3>
<div />
<SelectPokemonButton name="ditto" onClick={onClickPokemon} />
<SelectPokemonButton name="pikachu" onClick={onClickPokemon} />
<SelectPokemonButton name="charizard" onClick={onClickPokemon} />
<div>Pokemon data:</div>
<div>{JSON.stringify({ pokemonData })}</div>
</div>
);
}
import * as React from 'react';
import { render } from 'react-dom';
// List of supported HTML elements
type ModelElement = HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement;
// Custom hook for two-way data binding
// We can provide the initial value and an onChange function
// if we need to do additional things in our component
function useModel<E extends ModelElement>(
initial: string = null,
onChange?: React.ChangeEventHandler<E>
) {
const [value, setValue] = React.useState<string>(initial);
const handler: React.ChangeEventHandler<E> = (e) => {
// Store the current value and run the callback function if provided
setValue(e.currentTarget.value);
onChange && onChange(e);
};
const model = { value, onChange: handler };
return { model, setModel: setValue };
}
function App() {
// Use custom hook
const { model, setModel } = useModel('John', (e) => {
console.log('Model changed', e.currentTarget.value);
});
const reset = () => setModel('');
return (
<React.Fragment>
{/* Spread the model on the input element */}
<label htmlFor="name">Name: </label>
<input id="name" {...model} />
<div>Hello {model.value}</div>
<button onClick={reset}>Reset</button>
</React.Fragment>
);
}
render(<App />, document.getElementById('root'));
module-federation-examples / module-federation-vite-react https://github.com/modu...