🖍️
Developer Note
  • Welcome
  • Git
    • Eslint & Prettier & Stylelint & Husky
  • Programming Language
    • JavaScript
      • Script Async vs Defer
      • Module
      • Const VS Let VS Var
      • Promise
      • Event Loop
      • Execution Context
      • Hoisting
      • Closure
      • Event Buddling and Capturing
      • Garbage Collection
      • This
      • Routing
      • Debounce and Throttle
      • Web Component
      • Iterator
      • Syntax
      • String
      • Array
      • Object
      • Proxy & Reflect
      • ProtoType
      • Class
      • Immutability
      • Typeof & Instanceof
      • Npm (Node package manager)
    • TypeScript
      • Utility Type
      • Type vs Interface
      • Any vs Unknown vs Never
      • Void and undefined
      • Strict Mode
      • Namespace
      • Enum
      • Module
      • Generic
    • Python
      • Local Development
      • Uv
      • Asyncio & Event loop
      • Context Manager
      • Iterator & Generator
      • Fast API
      • Pydantic & Data Class
    • Java
      • Compilation and Execution
      • Data Type
      • Enumeration
      • Data Structure
      • Try Catch
      • InputStream and OutputStream
      • Concurrent
      • Unicode Block
      • Build Tools
      • Servlet
      • Java 8
  • Coding Pattern
    • MVC vs MVVM
    • OOP vs Functional
    • Error Handling
    • MVC vs Flux
    • Imperative vs Declarative
    • Design Pattern
  • Web Communication
    • REST API
      • Web Hook
      • CORS issue
    • HTTPS
    • GraphQL
      • REST API vs GraphQL
      • Implementation (NodeJS + React)
    • Server-Sent Event
    • Web Socket
    • IP
    • Domain Name System (DNS)
  • Frontend
    • Progressive Web App (PWA)
    • Single Page & Multiple Page Application
    • Search Engine Optimiaztion (SEO)
    • Web bundling & Micro-frontend
      • Webpack
        • Using Webpack to build React Application
        • Using Webpack to build react library
      • Vite
      • Using rollup to build react library
      • Implementing micro frontend
    • Web Security
      • CSRF & Nonce
      • XSS
      • Click hijacking
    • Cypress
    • CSS
      • Core
        • Box Model
        • Inline vs Block
        • Flexbox & Grid
        • Pseudo Class
        • Position
      • Tailwind CSS
        • Shadcn
      • CSS In JS
        • Material UI
    • React
      • Core
        • Component Pattern
        • React Lazy & Suspense
        • React Portal
        • Error Boundary
        • Rendering Methods
        • Environment Variable
        • Conditional CSS
        • Memo
        • Forward Reference
        • High Order Component (HOC) & Custom Hook
        • TypeScript
      • State Management
        • Redux
        • Recoil
        • Zustand
      • Routing
        • React Router Dom
      • Data Fetching
        • Axios & Hook
        • React Query
        • Orval
      • Table
        • React Table
      • Form & Validation
        • React Hook Form
        • Zod
      • NextJS
        • Page Router
        • App Router
      • React Native
    • Angular
    • Svelte
      • Svelte Kit
  • Backend
    • Cache
      • Browser Cache
      • Web Browser Storage
      • Proxy
      • Redis
    • Rate limit
    • Monitoring
      • Logging
      • Distributed Tracing
    • Load Test
    • Encryption
    • Authentication
      • Password Protection
      • Cookie & Session
      • JSON Web Token
      • SSO
        • OAuth 2.0
        • OpenID Connect (OIDC)
        • SAML
    • Payment
      • Pre-built
      • Custom
    • File Handling
      • Upload & Download (Front-end)
      • Stream & Buffer
    • Microservice
      • API Gateway
      • Service Discovery
      • Load Balancer
      • Circuit Breaker
      • Message Broker
      • BulkHead & Zipkin
    • Elastic Search
    • Database
      • SQL
        • Group By vs Distinct
        • Index
        • N + 1 problem
        • Normalization
        • Foreign Key
        • Relationship
        • Union & Join
        • User Defined Type
      • NOSQL (MongoDB)
      • Transaction
      • Sharding
      • Lock (Concurrency Control)
    • NodeJS
      • NodeJS vs Java Spring
      • ExpressJS
      • NestJS
        • Swagger
        • Class Validator & Validation Pipe
        • Passport (Authentication)
      • Path Module
      • Database Connection
        • Integrating with MYSQL
        • Sequalize
        • Integrating with MongoDB
        • Prisma
        • MikroORM
        • Mongoose
      • Streaming
      • Worker Thread
      • Passport JS
      • JSON Web Token
      • Socket IO
      • Bull MQ
      • Pino (Logging)
      • Yeoman
    • Spring
      • Spring MVC
      • Spring REST
      • Spring Actuator
      • Aspect Oriented Programming (AOP)
      • Controller Advice
      • Filter
      • Interceptor
      • Concurrent
      • Spring Security
      • Spring Boot
      • Spring Cloud
        • Resilience 4j
      • Quartz vs Spring Batch
      • JPA and Hibernate
      • HATEOS
      • Swagger
      • Unit Test (Java Spring)
      • Unit Test (Spring boot)
  • DevOp
    • Docker
    • Kubernetes
      • Helm
    • Nginx
    • File System
    • Cloud
      • AWS
        • EC2 (Virtual Machine)
        • Network
        • IAM
          • Role-Service Binding
        • Database
        • Route 53
        • S3
        • Message Queue
        • Application Service
        • Serverless Framework
        • Data Analysis
        • Machine Learning
        • Monitoring
        • Security
      • Azure
        • Identity
        • Compute Resource
        • Networking
        • Storage
        • Monitoring
      • Google Cloud
        • IAM
          • Workload Identity Federation
        • Compute Engine
        • VPC Network
        • Storage
        • Kubernetes Engine
        • App Engine
        • Cloud function
        • Cloud Run
        • Infra as Code
        • Pub/Sub
    • Deployment Strategy
    • Jenkins
    • Examples
      • Deploy NextJS on GCP
      • Deploy Spring on Azure
      • Deploy React on Azure
  • Domain Knowledge
    • Web 3
      • Blockchain
      • Cryptocurrency
    • AI
      • Prompt
      • Chain & Agent
      • LangChain
      • Chunking
      • Search
      • Side Products
Powered by GitBook
On this page
  • Stack
  • ReactJS + Web component
  • VueJS
  • Result

Was this helpful?

  1. Frontend
  2. Web bundling & Micro-frontend

Implementing micro frontend

Stack

  • VueJS -> container

  • ReactJS + web component -> component

  • Rollup -> bundling component

ReactJS + Web component

  • Here is the react component

Count/index.js
import React from 'react'
import styles from "./count.module.scss";
const Count = ({count}) => {
  return (
    <div className={styles.text}>{count}</div>
  )
}

export default Count
Count/count.module.scss
.text{
    color: aquamarine;
}
  • Here is the script of web component which is wrapper of react component

Count/count.js
import ReactDOM from 'react-dom/client';
import Count from '.';

class CountElement extends HTMLElement {

    get count(){
        return this.getAttribute("count");
    }

    set count(val){
        this.setAttribute("count",val);
    }

    connectedCallback() {
        this.attachShadow({mode: 'open'});
        let link = document.createElement('link');
        link.setAttribute('rel', 'stylesheet');
        link.setAttribute('href', 'http://localhost:3000/component.css');
        this.shadowRoot.appendChild(link);
        const mountPoint = document.createElement("div");
        this.shadowRoot.appendChild(mountPoint);
        const root = ReactDOM.createRoot(mountPoint);
        root.render(<Count count={this.count}/>);
    }

}
window.customElements.define("count-display", CountElement);
CountButton/countButton.js
import ReactDOM from 'react-dom/client';
import CountButton from '.';

class CountButtonElement extends HTMLElement {
    connectedCallback() {
        this.attachShadow({mode: 'open'});
        let link = document.createElement('link');
        link.setAttribute('rel', 'stylesheet');
        link.setAttribute('href', 'http://localhost:3000/component.css');
        this.shadowRoot.appendChild(link);
        const mountPoint = document.createElement("div");
        this.shadowRoot.appendChild(mountPoint);
        const root = ReactDOM.createRoot(mountPoint);
       
       // emit the event with custom name
        const event = new CustomEvent("onAddCount",{ 
            // allow event buddle up to parent
            buddles: true, 
            // allow event to propagate across shadow boundaries
            composed:true
        })

        root.render(<CountButton onAddCount={()=>{
            document.dispatchEvent(event);
        }} />);
    }
}

window.customElements.define("count-button", CountButtonElement);
  • Here is the main target bundling file

component.js
import "./Count/count";
import "./CountButton/countButton";
  • Here is the rollup file, to bundle css and web component js file as a output

rollup.config.js
import resolve from "@rollup/plugin-node-resolve";
import { terser } from "rollup-plugin-terser";
import postcss from 'rollup-plugin-postcss';
import commonjs from '@rollup/plugin-commonjs';
import babel from '@rollup/plugin-babel';
import externalGlobals from "rollup-plugin-external-globals";

// hard node env to production for bundled js file
const Global = `var process = {
    env: {
      NODE_ENV: 'production'
    }
  }`
// eslint-disable-next-line import/no-anonymous-default-export
export default {
    input: "src/component/component.js",
    output: {
        file: "public/component.js",
        format: "esm",
        banner: Global
    },
    // prevent bundling with react 
    external: ["react","react-dom", "react-scripts"],
    plugins: [
        resolve(),
        babel({
            presets: ["@babel/preset-react"],
        }),
        commonjs(),
        // reduce the bundle size
        terser(),
        // support sass, bundle multiple sass files into single css file
        postcss({
            extract: true,
            modules: true,
            use: ['sass'],
        }),
        // make sure react is injected from the script of vue container
        externalGlobals({
            react: "React",
            "react-dom": "ReactDOM",
        })
        
    ],
}
  • Here is the package.json

package.json
{
  "name": "react-microfrontend",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "@testing-library/jest-dom": "^5.16.4",
    "@testing-library/react": "^13.3.0",
    "@testing-library/user-event": "^13.5.0",
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "react-scripts": "5.0.1",
    "web-vitals": "^2.1.4"
  },
  "devDependencies": {
    "@babel/preset-react": "^7.18.6",
    "@rollup/plugin-babel": "^5.3.1",
    "@rollup/plugin-commonjs": "^22.0.0",
    "@rollup/plugin-node-resolve": "^13.3.0",
    "node-sass": "^7.0.1",
    "postcss": "^8.4.14",
    "rollup": "^2.75.7",
    "rollup-plugin-dts": "^4.2.2",
    "rollup-plugin-external-globals": "^0.6.1",
    "rollup-plugin-peer-deps-external": "^2.2.4",
    "rollup-plugin-postcss": "^4.0.2",
    "rollup-plugin-sass": "^1.2.12",
    "rollup-plugin-terser": "^7.0.2",
    "sass": "^1.53.0"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject",
    "build:rollup": "rollup -c"
  },
  "eslintConfig": {
    "extends": [
      "react-app",
      "react-app/jest"
    ]
  },
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  }
}

VueJS

  • Here is the public html file which is injected the output script file from react repo and react script file

public/index.html
<!DOCTYPE html>
<html lang="">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <link rel="icon" href="<%= BASE_URL %>favicon.ico">
    <script src="https://unpkg.com/react@18/umd/react.development.js" crossorigin ></script>
    <script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js" crossorigin ></script>
    <script type="module" src="http://localhost:3000/component.js" defer></script>
    <title><%= htmlWebpackPlugin.options.title %></title>
  </head>
  <body>
    <noscript>
      <strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
    </noscript>
    <div id="app"></div>
    <!-- built files will be auto injected -->
  </body>
</html>
  • Here is main app file of vue

App.vue
<template>
  <count-display :count="count" :key="count" />
  <count-button  />
</template>

<script>

export default {
  name: 'App',
  components: {
  },
  data() {
    return {
      count: 0
    }
  },
   methods: {
    increment() {
      this.count++
    }
  },
  mounted(){
    document.addEventListener("onAddCount", this.increment);
  }
}
</script>

<style>
</style>

Result

PreviousUsing rollup to build react libraryNextWeb Security

Last updated 6 months ago

Was this helpful?

https://github.com/headshootcheng/react-microfrontendgithub.com
https://github.com/headshootcheng/vue-containergithub.com