Tuesday 16 April 2024

React + Typescript_ Module federation _ Micro Front end -Standalone and integrated


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

Thursday 4 April 2024

JS- 10 JavaScript Sites Every Web Developer Should Know

2. https://javascript.info/

1

2
3
4







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