├── react-home ├── src │ ├── App.css │ ├── index.css │ ├── config.ts │ ├── index.tsx │ └── App.tsx ├── postcss.config.cjs ├── tailwind.config.cjs ├── tsconfig.json ├── index.html ├── vite.config.ts ├── README.md └── package.json ├── solid-about ├── src │ ├── App.module.css │ ├── index.css │ ├── config.ts │ ├── index.tsx │ └── App.tsx ├── postcss.config.js ├── tailwind.config.js ├── tsconfig.json ├── index.html ├── vite.config.ts └── package.json ├── solid-shell ├── src │ ├── App.module.css │ ├── config.ts │ ├── index.css │ ├── index.tsx │ ├── web-components │ │ ├── vue-cart.tsx │ │ ├── react-home.tsx │ │ ├── solid-about.tsx │ │ ├── svelte-product.tsx │ │ └── angular-contact.tsx │ └── App.tsx ├── postcss.config.js ├── tailwind.config.js ├── web-components.d.ts ├── tsconfig.json ├── index.html ├── package.json └── vite.config.ts ├── angular-contact ├── src │ ├── assets │ │ └── .gitkeep │ ├── app │ │ ├── app.component.css │ │ ├── config.ts │ │ ├── app.module.ts │ │ ├── app.component.html │ │ ├── app.component.spec.ts │ │ └── app.component.ts │ ├── main.ts │ ├── styles.css │ ├── favicon.ico │ ├── bootstrap.ts │ └── index.html ├── webpack.prod.config.js ├── postcss.config.js ├── .vscode │ ├── extensions.json │ ├── launch.json │ └── tasks.json ├── tailwind.config.js ├── tsconfig.app.json ├── tsconfig.spec.json ├── tsconfig.json ├── README.md ├── package.json ├── webpack.config.js └── angular.json ├── vue-cart ├── src │ ├── vite-env.d.ts │ ├── style.css │ ├── config.ts │ ├── main.ts │ └── App.vue ├── .vscode │ └── extensions.json ├── postcss.config.cjs ├── tailwind.config.cjs ├── tsconfig.node.json ├── index.html ├── tsconfig.json ├── vite.config.ts ├── package.json ├── public │ └── vite.svg └── README.md ├── share ├── config.ts ├── assets │ ├── images │ │ ├── solid-about │ │ │ └── solid.png │ │ ├── angular-contact │ │ │ ├── angular.png │ │ │ └── webpack.png │ │ ├── vue-cart │ │ │ ├── vue.svg │ │ │ └── vite.svg │ │ ├── vite.svg │ │ ├── react-home │ │ │ ├── vite.svg │ │ │ └── react.svg │ │ ├── solid-shell │ │ │ └── vite.svg │ │ └── svelte-product │ │ │ └── svelte.svg │ ├── app.js │ └── package.json ├── utils │ └── functions.ts └── store │ └── store.ts ├── svelte-product ├── src │ ├── app.css │ ├── vite-env.d.ts │ ├── config.ts │ ├── main.ts │ ├── App.svelte │ └── assets │ │ └── svelte.svg ├── .vscode │ └── extensions.json ├── postcss.config.cjs ├── tsconfig.node.json ├── tailwind.config.cjs ├── svelte.config.js ├── index.html ├── vite.config.ts ├── tsconfig.json ├── package.json ├── public │ └── vite.svg └── README.md ├── progress.js ├── .editorconfig ├── .gitignore ├── tasks ├── run.js ├── build.js └── serve.js ├── logger.js ├── package.json └── README.md /react-home/src/App.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /solid-about/src/App.module.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /solid-shell/src/App.module.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /angular-contact/src/assets/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /angular-contact/src/app/app.component.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /vue-cart/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /share/config.ts: -------------------------------------------------------------------------------- 1 | export const ASSETS_BASE_URL = "http://localhost:9000"; 2 | -------------------------------------------------------------------------------- /angular-contact/webpack.prod.config.js: -------------------------------------------------------------------------------- 1 | module.exports = require('./webpack.config'); 2 | -------------------------------------------------------------------------------- /vue-cart/src/style.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; -------------------------------------------------------------------------------- /angular-contact/src/main.ts: -------------------------------------------------------------------------------- 1 | import('./bootstrap') 2 | .catch(err => console.error(err)); 3 | -------------------------------------------------------------------------------- /solid-about/src/index.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; -------------------------------------------------------------------------------- /svelte-product/src/app.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | -------------------------------------------------------------------------------- /angular-contact/src/styles.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | -------------------------------------------------------------------------------- /react-home/src/index.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | -------------------------------------------------------------------------------- /svelte-product/.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": ["svelte.svelte-vscode"] 3 | } 4 | -------------------------------------------------------------------------------- /svelte-product/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | -------------------------------------------------------------------------------- /vue-cart/.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": ["Vue.volar", "Vue.vscode-typescript-vue-plugin"] 3 | } 4 | -------------------------------------------------------------------------------- /vue-cart/postcss.config.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /react-home/postcss.config.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /solid-about/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /solid-shell/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /angular-contact/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /svelte-product/postcss.config.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /solid-shell/src/config.ts: -------------------------------------------------------------------------------- 1 | import { configuationBase } from "../../share/utils/functions"; 2 | export const baseConfig = configuationBase(""); 3 | -------------------------------------------------------------------------------- /angular-contact/src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quangnv13/micro-frontend-multi-framework-boilerplate/HEAD/angular-contact/src/favicon.ico -------------------------------------------------------------------------------- /vue-cart/src/config.ts: -------------------------------------------------------------------------------- 1 | import { configuationBase } from "../../share/utils/functions"; 2 | export const baseConfig = configuationBase("vue-cart"); 3 | -------------------------------------------------------------------------------- /react-home/src/config.ts: -------------------------------------------------------------------------------- 1 | import { configuationBase } from "../../share/utils/functions"; 2 | export const baseConfig = configuationBase("react-home"); 3 | -------------------------------------------------------------------------------- /solid-about/src/config.ts: -------------------------------------------------------------------------------- 1 | import { configuationBase } from "../../share/utils/functions"; 2 | export const baseConfig = configuationBase("solid-about"); 3 | -------------------------------------------------------------------------------- /svelte-product/src/config.ts: -------------------------------------------------------------------------------- 1 | import { configuationBase } from '../../share/utils/functions'; 2 | export const baseConfig = configuationBase('svelte-product'); 3 | -------------------------------------------------------------------------------- /angular-contact/src/app/config.ts: -------------------------------------------------------------------------------- 1 | import { configuationBase } from '../../../share/utils/functions'; 2 | export const baseConfig = configuationBase('angular-contact'); 3 | -------------------------------------------------------------------------------- /share/assets/images/solid-about/solid.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quangnv13/micro-frontend-multi-framework-boilerplate/HEAD/share/assets/images/solid-about/solid.png -------------------------------------------------------------------------------- /share/assets/images/angular-contact/angular.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quangnv13/micro-frontend-multi-framework-boilerplate/HEAD/share/assets/images/angular-contact/angular.png -------------------------------------------------------------------------------- /share/assets/images/angular-contact/webpack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quangnv13/micro-frontend-multi-framework-boilerplate/HEAD/share/assets/images/angular-contact/webpack.png -------------------------------------------------------------------------------- /angular-contact/.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=827846 3 | "recommendations": ["angular.ng-template"] 4 | } 5 | -------------------------------------------------------------------------------- /progress.js: -------------------------------------------------------------------------------- 1 | const cliProgress = require("cli-progress"); 2 | const progressBar = new cliProgress.SingleBar( 3 | {}, 4 | cliProgress.Presets.shades_classic 5 | ); 6 | 7 | module.exports = progressBar; 8 | -------------------------------------------------------------------------------- /react-home/tailwind.config.cjs: -------------------------------------------------------------------------------- 1 | /** @type {import('tailwindcss').Config} */ 2 | module.exports = { 3 | content: ["./src/**/*.tsx"], 4 | theme: { 5 | extend: {}, 6 | }, 7 | plugins: [], 8 | }; 9 | -------------------------------------------------------------------------------- /solid-about/tailwind.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('tailwindcss').Config} */ 2 | module.exports = { 3 | content: ["./src/**/*.tsx"], 4 | theme: { 5 | extend: {}, 6 | }, 7 | plugins: [], 8 | }; 9 | -------------------------------------------------------------------------------- /solid-shell/tailwind.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('tailwindcss').Config} */ 2 | module.exports = { 3 | content: ["./src/**/*.tsx"], 4 | theme: { 5 | extend: {}, 6 | }, 7 | plugins: [], 8 | }; 9 | -------------------------------------------------------------------------------- /svelte-product/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "module": "ESNext", 5 | "moduleResolution": "Node" 6 | }, 7 | "include": ["vite.config.ts"] 8 | } 9 | -------------------------------------------------------------------------------- /vue-cart/tailwind.config.cjs: -------------------------------------------------------------------------------- 1 | /** @type {import('tailwindcss').Config} */ 2 | module.exports = { 3 | content: ["./src/**/*.vue"], 4 | theme: { 5 | extend: {}, 6 | }, 7 | plugins: [], 8 | }; 9 | -------------------------------------------------------------------------------- /svelte-product/tailwind.config.cjs: -------------------------------------------------------------------------------- 1 | /** @type {import('tailwindcss').Config} */ 2 | module.exports = { 3 | content: ["./src/**/*.svelte"], 4 | theme: { 5 | extend: {}, 6 | }, 7 | plugins: [], 8 | }; 9 | -------------------------------------------------------------------------------- /angular-contact/tailwind.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('tailwindcss').Config} */ 2 | module.exports = { 3 | content: ["./src/**/*.{html,ts}"], 4 | theme: { 5 | extend: {}, 6 | }, 7 | plugins: [], 8 | }; 9 | -------------------------------------------------------------------------------- /solid-shell/src/index.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | .active { 6 | @apply text-blue-700 7 | } 8 | 9 | .inactive { 10 | @apply hover:text-blue-700 11 | } -------------------------------------------------------------------------------- /solid-about/src/index.tsx: -------------------------------------------------------------------------------- 1 | import App from "./App"; 2 | 3 | import { customElement, hot } from "solid-element"; 4 | import "./index.css"; 5 | 6 | customElement("solid-about-ce", {}, App); 7 | 8 | hot(module, "solid-about-ce"); 9 | -------------------------------------------------------------------------------- /vue-cart/src/main.ts: -------------------------------------------------------------------------------- 1 | import { defineCustomElement } from "vue"; 2 | import "./style.css"; 3 | import App from "./App.vue"; 4 | 5 | const vueCartCe = defineCustomElement(App); 6 | 7 | customElements.define("vue-cart-ce", vueCartCe); 8 | -------------------------------------------------------------------------------- /vue-cart/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "module": "ESNext", 5 | "moduleResolution": "Node", 6 | "allowSyntheticDefaultImports": true 7 | }, 8 | "include": ["vite.config.ts"] 9 | } 10 | -------------------------------------------------------------------------------- /angular-contact/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "./out-tsc/app", 5 | "types": [] 6 | }, 7 | "files": [ 8 | "src/main.ts" 9 | ], 10 | "include": [ 11 | "src/**/*.d.ts" 12 | ] 13 | } -------------------------------------------------------------------------------- /solid-shell/web-components.d.ts: -------------------------------------------------------------------------------- 1 | declare module "solid_about/web-components"; 2 | declare module "react_home/web-components"; 3 | declare module "angular_contact/web-components"; 4 | declare module "vue_cart/web-components"; 5 | declare module "svelte_product/web-components"; 6 | -------------------------------------------------------------------------------- /svelte-product/svelte.config.js: -------------------------------------------------------------------------------- 1 | import { vitePreprocess } from "@sveltejs/vite-plugin-svelte"; 2 | 3 | export default { 4 | // Consult https://svelte.dev/docs#compile-time-svelte-preprocess 5 | // for more information about preprocessors 6 | preprocess: vitePreprocess(), 7 | }; 8 | -------------------------------------------------------------------------------- /angular-contact/src/bootstrap.ts: -------------------------------------------------------------------------------- 1 | import 'zone.js'; 2 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 3 | 4 | import { AppModule } from './app/app.module'; 5 | 6 | platformBrowserDynamic() 7 | .bootstrapModule(AppModule) 8 | .catch((err) => console.error(err)); 9 | -------------------------------------------------------------------------------- /share/assets/app.js: -------------------------------------------------------------------------------- 1 | const express = require("express"); 2 | const app = express(); 3 | const cors = require("cors"); 4 | const port = 9000; 5 | 6 | app.use(cors()); 7 | app.use(express.static(".")); 8 | 9 | app.listen(port, () => { 10 | console.log(`Example app listening on port ${port}`); 11 | }); 12 | -------------------------------------------------------------------------------- /solid-shell/src/index.tsx: -------------------------------------------------------------------------------- 1 | import App from "./App"; 2 | import { render } from "solid-js/web"; 3 | import "./index.css"; 4 | import { Router } from "@solidjs/router"; 5 | 6 | render( 7 | () => ( 8 | 9 | 10 | 11 | ), 12 | document.getElementById("root")! 13 | ); 14 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see https://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.ts] 12 | quote_type = single 13 | 14 | [*.md] 15 | max_line_length = off 16 | trim_trailing_whitespace = false 17 | -------------------------------------------------------------------------------- /solid-shell/src/web-components/vue-cart.tsx: -------------------------------------------------------------------------------- 1 | import("vue_cart/web-components"); 2 | 3 | declare module "solid-js" { 4 | namespace JSX { 5 | interface IntrinsicElements { 6 | "vue-cart-ce": any; 7 | } 8 | } 9 | } 10 | 11 | const VueCart = () => { 12 | return ; 13 | }; 14 | 15 | export default VueCart; 16 | -------------------------------------------------------------------------------- /angular-contact/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | AngularContact 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /angular-contact/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */ 2 | { 3 | "extends": "./tsconfig.json", 4 | "compilerOptions": { 5 | "outDir": "./out-tsc/spec", 6 | "types": [ 7 | "jasmine" 8 | ] 9 | }, 10 | "include": [ 11 | "src/**/*.spec.ts", 12 | "src/**/*.d.ts" 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /solid-shell/src/web-components/react-home.tsx: -------------------------------------------------------------------------------- 1 | import("react_home/web-components"); 2 | 3 | declare module "solid-js" { 4 | namespace JSX { 5 | interface IntrinsicElements { 6 | "react-home-ce": any; 7 | } 8 | } 9 | } 10 | 11 | const ReactHome = () => { 12 | return ; 13 | }; 14 | 15 | export default ReactHome; 16 | -------------------------------------------------------------------------------- /share/assets/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "solid-about", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "node app.js" 8 | }, 9 | "keywords": [], 10 | "author": "quangnv13", 11 | "license": "ISC", 12 | "dependencies": { 13 | "cors": "^2.8.5", 14 | "express": "^4.18.2" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /solid-shell/src/web-components/solid-about.tsx: -------------------------------------------------------------------------------- 1 | import("solid_about/web-components"); 2 | 3 | declare module "solid-js" { 4 | namespace JSX { 5 | interface IntrinsicElements { 6 | "solid-about-ce": any; 7 | } 8 | } 9 | } 10 | 11 | const SolidAbout = () => { 12 | return ; 13 | }; 14 | 15 | export default SolidAbout; 16 | -------------------------------------------------------------------------------- /solid-shell/src/web-components/svelte-product.tsx: -------------------------------------------------------------------------------- 1 | import("svelte_product/web-components"); 2 | 3 | declare module "solid-js" { 4 | namespace JSX { 5 | interface IntrinsicElements { 6 | "svelte-product-ce": any; 7 | } 8 | } 9 | } 10 | 11 | const SvelteProduct = () => { 12 | return ; 13 | }; 14 | 15 | export default SvelteProduct; 16 | -------------------------------------------------------------------------------- /solid-shell/src/web-components/angular-contact.tsx: -------------------------------------------------------------------------------- 1 | import("angular_contact/web-components"); 2 | 3 | declare module "solid-js" { 4 | namespace JSX { 5 | interface IntrinsicElements { 6 | "angular-contact-ce": any; 7 | } 8 | } 9 | } 10 | 11 | const AngularContact = () => { 12 | return ; 13 | }; 14 | 15 | export default AngularContact; 16 | -------------------------------------------------------------------------------- /react-home/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "strict": true, 4 | "target": "ESNext", 5 | "module": "ESNext", 6 | "moduleResolution": "node", 7 | "allowSyntheticDefaultImports": true, 8 | "esModuleInterop": true, 9 | "jsx": "react-jsx", 10 | "jsxImportSource": "react", 11 | "types": ["vite/client"], 12 | "noEmit": true, 13 | "isolatedModules": true 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /solid-about/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "strict": true, 4 | "target": "ESNext", 5 | "module": "ESNext", 6 | "moduleResolution": "node", 7 | "allowSyntheticDefaultImports": true, 8 | "esModuleInterop": true, 9 | "jsx": "preserve", 10 | "jsxImportSource": "solid-js", 11 | "types": ["vite/client"], 12 | "noEmit": true, 13 | "isolatedModules": true 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /solid-shell/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "strict": true, 4 | "target": "ESNext", 5 | "module": "ESNext", 6 | "moduleResolution": "node", 7 | "allowSyntheticDefaultImports": true, 8 | "esModuleInterop": true, 9 | "jsx": "preserve", 10 | "jsxImportSource": "solid-js", 11 | "types": ["vite/client"], 12 | "noEmit": true, 13 | "isolatedModules": true 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .DS_Store 17 | *.suo 18 | *.ntvs* 19 | *.njsproj 20 | *.sln 21 | *.sw? 22 | .angular 23 | 24 | *.Identifier 25 | 26 | #Package manager 27 | pnpm-lock.yaml 28 | yarn.lock 29 | package-lock.json 30 | -------------------------------------------------------------------------------- /vue-cart/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Vite + Vue + TS 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /react-home/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Vite + React + TS 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /svelte-product/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Vite + Svelte + TS 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /solid-shell/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Solid App 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /solid-about/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Solid App 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /tasks/run.js: -------------------------------------------------------------------------------- 1 | const inquirer = require("inquirer"); 2 | 3 | const pms = ["pnpm", "yarn", "npm"]; 4 | 5 | async function runTask(callback) { 6 | const prompt = await inquirer.createPromptModule(); 7 | const pmAnswer = await prompt([ 8 | { 9 | name: "pm", 10 | message: "What is your package manager would like to use?", 11 | type: "list", 12 | choices: pms, 13 | }, 14 | ]); 15 | const pm = pmAnswer["pm"]; 16 | callback(pm); 17 | } 18 | 19 | module.exports = runTask; 20 | -------------------------------------------------------------------------------- /share/assets/images/vue-cart/vue.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /logger.js: -------------------------------------------------------------------------------- 1 | const chalk = require("chalk"); 2 | 3 | const errorChalk = chalk.bold.red; 4 | const infoChalk = chalk.blue; 5 | const successChalk = chalk.green; 6 | const warningChalk = chalk.hex("#FFA500"); 7 | 8 | const logger = { 9 | error: (...messages) => console.error(errorChalk(messages)), 10 | info: (...messages) => console.info(infoChalk(messages)), 11 | success: (...messages) => console.log(successChalk(messages)), 12 | warn: (...messages) => console.log(warningChalk(messages)), 13 | }; 14 | 15 | module.exports = logger; 16 | -------------------------------------------------------------------------------- /vue-cart/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "useDefineForClassFields": true, 5 | "module": "ESNext", 6 | "moduleResolution": "Node", 7 | "strict": true, 8 | "jsx": "preserve", 9 | "resolveJsonModule": true, 10 | "isolatedModules": true, 11 | "esModuleInterop": true, 12 | "lib": ["ESNext", "DOM"], 13 | "skipLibCheck": true, 14 | "noEmit": true 15 | }, 16 | "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"], 17 | "references": [{ "path": "./tsconfig.node.json" }] 18 | } 19 | -------------------------------------------------------------------------------- /vue-cart/vite.config.ts: -------------------------------------------------------------------------------- 1 | import vue from "@vitejs/plugin-vue"; 2 | import { defineConfig } from "vite"; 3 | import federation from "@originjs/vite-plugin-federation"; 4 | 5 | export default defineConfig({ 6 | plugins: [ 7 | vue(), 8 | federation({ 9 | name: "vue-cart", 10 | filename: "remoteEntry.js", 11 | exposes: { 12 | "./web-components": "./src/main.ts", 13 | }, 14 | }), 15 | ], 16 | server: { 17 | port: 4176, 18 | }, 19 | build: { 20 | target: "esnext", 21 | }, 22 | preview: { 23 | port: 4176, 24 | }, 25 | }); 26 | -------------------------------------------------------------------------------- /angular-contact/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 3 | "version": "0.2.0", 4 | "configurations": [ 5 | { 6 | "name": "ng serve", 7 | "type": "pwa-chrome", 8 | "request": "launch", 9 | "preLaunchTask": "npm: start", 10 | "url": "http://localhost:4200/" 11 | }, 12 | { 13 | "name": "ng test", 14 | "type": "chrome", 15 | "request": "launch", 16 | "preLaunchTask": "npm: test", 17 | "url": "http://localhost:9876/debug.html" 18 | } 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /react-home/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "vite"; 2 | import react from "@vitejs/plugin-react"; 3 | import federation from "@originjs/vite-plugin-federation"; 4 | 5 | export default defineConfig({ 6 | plugins: [ 7 | react(), 8 | federation({ 9 | name: "react_home", 10 | filename: "remoteEntry.js", 11 | exposes: { 12 | "./web-components": "./src/index.tsx", 13 | }, 14 | }), 15 | ], 16 | server: { 17 | port: 4174, 18 | }, 19 | build: { 20 | target: "esnext", 21 | }, 22 | preview: { 23 | port: 4174, 24 | }, 25 | }); 26 | -------------------------------------------------------------------------------- /solid-about/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "vite"; 2 | import solidPlugin from "vite-plugin-solid"; 3 | import federation from "@originjs/vite-plugin-federation"; 4 | 5 | export default defineConfig({ 6 | plugins: [ 7 | solidPlugin(), 8 | federation({ 9 | name: "solid-about", 10 | filename: "remoteEntry.js", 11 | exposes: { 12 | "./web-components": "./src/index.tsx", 13 | }, 14 | }), 15 | ], 16 | server: { 17 | port: 4173, 18 | }, 19 | build: { 20 | target: "esnext", 21 | }, 22 | preview: { 23 | port: 4173, 24 | }, 25 | }); 26 | -------------------------------------------------------------------------------- /share/utils/functions.ts: -------------------------------------------------------------------------------- 1 | import { ASSETS_BASE_URL } from "../config"; 2 | 3 | export const configuationBase = (appEndpoint: string) => { 4 | const imagesAssetsUrl = `${ASSETS_BASE_URL}/images/${appEndpoint}`; 5 | return { 6 | imagesAssetsUrl, 7 | resolveImagePath: function (endPoint: string) { 8 | if (endPoint === "vite.svg") { 9 | return resolveImagePath(`${ASSETS_BASE_URL}/images`, "vite.svg"); 10 | } 11 | return resolveImagePath(imagesAssetsUrl, endPoint); 12 | }, 13 | }; 14 | }; 15 | 16 | const resolveImagePath = (baseUrl: string, endPoint: string) => { 17 | return `${baseUrl}/${endPoint}`; 18 | }; 19 | -------------------------------------------------------------------------------- /svelte-product/src/main.ts: -------------------------------------------------------------------------------- 1 | import './app.css'; 2 | import styles from './app.css?inline'; 3 | import App from './App.svelte'; 4 | 5 | class Product extends HTMLElement { 6 | root: HTMLElement; 7 | 8 | constructor() { 9 | super(); 10 | this.root = document.createElement('div'); 11 | const styleTag = document.createElement('style'); 12 | styleTag.innerHTML = styles; 13 | this.root.prepend(styleTag); 14 | 15 | new App({ 16 | target: this.root, 17 | }); 18 | } 19 | 20 | connectedCallback() { 21 | this.appendChild(this.root); 22 | } 23 | } 24 | 25 | customElements.define('svelte-product-ce', Product); 26 | -------------------------------------------------------------------------------- /svelte-product/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite'; 2 | import { svelte } from '@sveltejs/vite-plugin-svelte'; 3 | import federation from '@originjs/vite-plugin-federation'; 4 | 5 | // https://vitejs.dev/config/ 6 | export default defineConfig({ 7 | plugins: [ 8 | svelte(), 9 | federation({ 10 | name: 'svelte-product', 11 | filename: 'remoteEntry.js', 12 | exposes: { 13 | './web-components': './src/main.ts', 14 | }, 15 | }), 16 | ], 17 | server: { 18 | port: 4177, 19 | }, 20 | build: { 21 | target: 'esnext', 22 | }, 23 | preview: { 24 | port: 4177, 25 | }, 26 | }); 27 | -------------------------------------------------------------------------------- /vue-cart/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue-cart", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "start": "vite", 8 | "build": "vite build", 9 | "serve": "vite build && vite preview" 10 | }, 11 | "dependencies": { 12 | "vue": "^3.2.45" 13 | }, 14 | "devDependencies": { 15 | "@originjs/vite-plugin-federation": "^1.1.12", 16 | "@vitejs/plugin-vue": "^4.0.0", 17 | "autoprefixer": "^10.4.13", 18 | "postcss": "^8.4.20", 19 | "tailwindcss": "^3.2.4", 20 | "typescript": "^4.9.3", 21 | "vite": "^4.0.0", 22 | "vue-tsc": "^1.0.11" 23 | }, 24 | "author": "quangnv13" 25 | } 26 | -------------------------------------------------------------------------------- /react-home/README.md: -------------------------------------------------------------------------------- 1 | # ReactJS - Micro frontend app 2 | 3 | ## Setup: 4 | 5 | - See **./src/index.tsx** i wrapped **ReactDOM.createRoot** into a class extends **HTMLElement** for define **CustomElementConstructor** and pass the class to `customElements.define` for register web component. 6 | 7 | ## State management: 8 | 9 | - In constructor of web component class i define **counterUpdater** for update state from global state. Because if i use **Rxjs** inner React App it will memory leak by rerender. 10 | - In **connectedCallback** function i subscribe **windowStore.counter$** observable. 11 | - In **disconnectedCallback** function i unsubscribe **windowStore.counter$** observable for avoid memory leak. 12 | -------------------------------------------------------------------------------- /svelte-product/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@tsconfig/svelte/tsconfig.json", 3 | "compilerOptions": { 4 | "target": "ESNext", 5 | "useDefineForClassFields": true, 6 | "module": "ESNext", 7 | "resolveJsonModule": true, 8 | /** 9 | * Typecheck JS in `.svelte` and `.js` files by default. 10 | * Disable checkJs if you'd like to use dynamic types in JS. 11 | * Note that setting allowJs false does not prevent the use 12 | * of JS in `.svelte` files. 13 | */ 14 | "allowJs": true, 15 | "checkJs": true, 16 | "isolatedModules": true 17 | }, 18 | "include": ["src/**/*.d.ts", "src/**/*.ts", "src/**/*.js", "src/**/*.svelte"], 19 | "references": [{ "path": "./tsconfig.node.json" }] 20 | } 21 | -------------------------------------------------------------------------------- /react-home/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-host-vite", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "start": "vite", 8 | "build": "vite build", 9 | "serve": "vite build && vite preview" 10 | }, 11 | "dependencies": { 12 | "react": "^18.2.0", 13 | "react-dom": "^18.2.0" 14 | }, 15 | "devDependencies": { 16 | "@originjs/vite-plugin-federation": "^1.1.12", 17 | "@types/react": "^18.0.26", 18 | "@types/react-dom": "^18.0.9", 19 | "@vitejs/plugin-react": "^3.0.0", 20 | "autoprefixer": "^10.4.13", 21 | "postcss": "^8.4.20", 22 | "tailwindcss": "^3.2.4", 23 | "typescript": "^4.9.3", 24 | "vite": "^4.0.0" 25 | }, 26 | "author": "quangnv13" 27 | } 28 | -------------------------------------------------------------------------------- /svelte-product/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "svelte-product", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "start": "vite", 8 | "build": "vite build", 9 | "serve": "vite build && vite preview", 10 | "check": "svelte-check --tsconfig ./tsconfig.json" 11 | }, 12 | "devDependencies": { 13 | "@originjs/vite-plugin-federation": "^1.1.12", 14 | "@sveltejs/vite-plugin-svelte": "^2.0.0", 15 | "@tsconfig/svelte": "^3.0.0", 16 | "autoprefixer": "^10.4.13", 17 | "postcss": "^8.4.20", 18 | "svelte": "^3.54.0", 19 | "svelte-check": "^2.10.0", 20 | "tailwindcss": "^3.2.4", 21 | "tslib": "^2.4.1", 22 | "typescript": "^4.9.3", 23 | "vite": "^4.0.0" 24 | }, 25 | "author": "quangnv13" 26 | } 27 | -------------------------------------------------------------------------------- /angular-contact/src/app/app.module.ts: -------------------------------------------------------------------------------- 1 | import { ApplicationRef, DoBootstrap, Injector, NgModule } from '@angular/core'; 2 | import { createCustomElement } from '@angular/elements'; 3 | import { BrowserModule } from '@angular/platform-browser'; 4 | 5 | import { AppComponent } from './app.component'; 6 | 7 | @NgModule({ 8 | declarations: [AppComponent], 9 | imports: [BrowserModule], 10 | providers: [], 11 | bootstrap: [], 12 | }) 13 | export class AppModule implements DoBootstrap { 14 | constructor(private injector: Injector) {} 15 | 16 | ngDoBootstrap(appRef: ApplicationRef): void { 17 | const angularContactCe = createCustomElement(AppComponent, { 18 | injector: this.injector, 19 | }); 20 | customElements.define('angular-contact-ce', angularContactCe); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "micro-fe-workspace", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "serve": "node tasks/serve.js", 8 | "build": "node tasks/build.js" 9 | }, 10 | "keywords": [ 11 | "micro frontend", 12 | "multi framework", 13 | "micro frontend distributed", 14 | "microfrontend", 15 | "micro frontend with shadow dom", 16 | "module federation", 17 | "micro frontend with module federation", 18 | "shadow dom" 19 | ], 20 | "author": "quangnv13", 21 | "license": "ISC", 22 | "devDependencies": { 23 | "cli-progress": "^3.11.2", 24 | "concurrently": "^7.6.0", 25 | "execa": "^6.1.0", 26 | "inquirer": "8.2.5", 27 | "listr": "^0.14.3" 28 | }, 29 | "dependencies": { 30 | "chalk": "4", 31 | "rxjs": "^7.8.0" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /solid-shell/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "solid-shell", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "vite", 8 | "build": "vite build", 9 | "serve": "vite build && vite preview", 10 | "test": "echo \"Error: no test specified\" && exit 1" 11 | }, 12 | "keywords": [], 13 | "author": "quangnv13", 14 | "license": "ISC", 15 | "devDependencies": { 16 | "@originjs/vite-plugin-federation": "^1.1.12", 17 | "@types/node": "^18.11.17", 18 | "autoprefixer": "^10.4.13", 19 | "postcss": "^8.4.20", 20 | "tailwindcss": "^3.2.4", 21 | "typescript": "^4.9.4", 22 | "vite": "^4.0.3", 23 | "vite-plugin-solid": "^2.5.0" 24 | }, 25 | "dependencies": { 26 | "@solidjs/router": "^0.8.2", 27 | "solid-element": "^1.6.3", 28 | "solid-js": "^1.6.6" 29 | } 30 | } -------------------------------------------------------------------------------- /solid-about/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "solid-about", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "vite", 8 | "build": "vite build", 9 | "serve": "vite build && vite preview", 10 | "test": "echo \"Error: no test specified\" && exit 1" 11 | }, 12 | "keywords": [], 13 | "author": "quangnv13", 14 | "license": "ISC", 15 | "devDependencies": { 16 | "@originjs/vite-plugin-federation": "^1.1.12", 17 | "@types/node": "^18.11.17", 18 | "autoprefixer": "^10.4.13", 19 | "postcss": "^8.4.20", 20 | "tailwindcss": "^3.2.4", 21 | "typescript": "^4.9.4", 22 | "vite": "^4.0.3", 23 | "vite-plugin-solid": "^2.5.0" 24 | }, 25 | "dependencies": { 26 | "@solidjs/router": "^0.6.0", 27 | "solid-element": "^1.6.3", 28 | "solid-js": "^1.6.6" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /angular-contact/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": false, 3 | "compilerOptions": { 4 | "baseUrl": "./", 5 | "outDir": "./dist/out-tsc", 6 | "forceConsistentCasingInFileNames": true, 7 | "strict": true, 8 | "noImplicitOverride": true, 9 | "noPropertyAccessFromIndexSignature": true, 10 | "noImplicitReturns": true, 11 | "noFallthroughCasesInSwitch": true, 12 | "sourceMap": true, 13 | "declaration": false, 14 | "downlevelIteration": true, 15 | "experimentalDecorators": true, 16 | "moduleResolution": "node", 17 | "importHelpers": true, 18 | "target": "ES2022", 19 | "module": "ES2022", 20 | "useDefineForClassFields": false, 21 | "lib": [ 22 | "ES2022", 23 | "dom" 24 | ] 25 | }, 26 | "angularCompilerOptions": { 27 | "enableI18nLegacyMessageIdFormat": false, 28 | "strictInjectionParameters": true, 29 | "strictInputAccessModifiers": true, 30 | "strictTemplates": true 31 | } 32 | } -------------------------------------------------------------------------------- /solid-shell/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "vite"; 2 | import solidPlugin from "vite-plugin-solid"; 3 | import federation from "@originjs/vite-plugin-federation"; 4 | 5 | export default defineConfig({ 6 | plugins: [ 7 | solidPlugin(), 8 | federation({ 9 | name: "solid-shell", 10 | remotes: { 11 | solid_about: "http://localhost:4173/assets/remoteEntry.js", 12 | react_home: "http://localhost:4174/assets/remoteEntry.js", 13 | angular_contact: { 14 | external: "http://localhost:4175/assets/remoteEntry.js", 15 | from: "webpack", 16 | externalType: "url", 17 | }, 18 | vue_cart: "http://localhost:4176/assets/remoteEntry.js", 19 | svelte_product: "http://localhost:4177/assets/remoteEntry.js", 20 | }, 21 | }), 22 | ], 23 | server: { 24 | port: 4172, 25 | }, 26 | build: { 27 | target: "esnext", 28 | }, 29 | preview: { 30 | port: 4172, 31 | }, 32 | }); 33 | -------------------------------------------------------------------------------- /angular-contact/src/app/app.component.html: -------------------------------------------------------------------------------- 1 | 17 |
18 | 24 | 30 |

{{ counter$ | async }}

31 |
32 | -------------------------------------------------------------------------------- /share/store/store.ts: -------------------------------------------------------------------------------- 1 | type TWindow = { 2 | counter$: Observable; 3 | increaseCounter: () => void; 4 | decreaseCounter: () => void; 5 | createSubscription: () => Subscription; 6 | tap: (value: T) => void; 7 | initedStore: boolean; 8 | } & globalThis.Window; 9 | 10 | import { BehaviorSubject, Observable, Subscription, tap } from "rxjs"; 11 | 12 | const windowStore = window as unknown as TWindow; 13 | 14 | if (!windowStore.initedStore) { 15 | windowStore.initedStore = true; 16 | const counterSubject = new BehaviorSubject(0); 17 | windowStore.counter$ = counterSubject.asObservable(); 18 | 19 | windowStore.increaseCounter = () => { 20 | const currentValue = counterSubject.value; 21 | counterSubject.next(currentValue + 1); 22 | }; 23 | 24 | windowStore.decreaseCounter = () => { 25 | const currentValue = counterSubject.value; 26 | counterSubject.next(currentValue - 1); 27 | }; 28 | 29 | windowStore.createSubscription = () => new Subscription(); 30 | 31 | windowStore.tap = () => tap; 32 | } 33 | 34 | export default windowStore; 35 | -------------------------------------------------------------------------------- /angular-contact/.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | // For more information, visit: https://go.microsoft.com/fwlink/?LinkId=733558 3 | "version": "2.0.0", 4 | "tasks": [ 5 | { 6 | "type": "npm", 7 | "script": "start", 8 | "isBackground": true, 9 | "problemMatcher": { 10 | "owner": "typescript", 11 | "pattern": "$tsc", 12 | "background": { 13 | "activeOnStart": true, 14 | "beginsPattern": { 15 | "regexp": "(.*?)" 16 | }, 17 | "endsPattern": { 18 | "regexp": "bundle generation complete" 19 | } 20 | } 21 | } 22 | }, 23 | { 24 | "type": "npm", 25 | "script": "test", 26 | "isBackground": true, 27 | "problemMatcher": { 28 | "owner": "typescript", 29 | "pattern": "$tsc", 30 | "background": { 31 | "activeOnStart": true, 32 | "beginsPattern": { 33 | "regexp": "(.*?)" 34 | }, 35 | "endsPattern": { 36 | "regexp": "bundle generation complete" 37 | } 38 | } 39 | } 40 | } 41 | ] 42 | } 43 | -------------------------------------------------------------------------------- /angular-contact/src/app/app.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | import { AppComponent } from './app.component'; 3 | 4 | describe('AppComponent', () => { 5 | beforeEach(async () => { 6 | await TestBed.configureTestingModule({ 7 | declarations: [ 8 | AppComponent 9 | ], 10 | }).compileComponents(); 11 | }); 12 | 13 | it('should create the app', () => { 14 | const fixture = TestBed.createComponent(AppComponent); 15 | const app = fixture.componentInstance; 16 | expect(app).toBeTruthy(); 17 | }); 18 | 19 | it(`should have as title 'angular-contact'`, () => { 20 | const fixture = TestBed.createComponent(AppComponent); 21 | const app = fixture.componentInstance; 22 | expect(app.title).toEqual('angular-contact'); 23 | }); 24 | 25 | it('should render title', () => { 26 | const fixture = TestBed.createComponent(AppComponent); 27 | fixture.detectChanges(); 28 | const compiled = fixture.nativeElement as HTMLElement; 29 | expect(compiled.querySelector('.content span')?.textContent).toContain('angular-contact app is running!'); 30 | }); 31 | }); 32 | -------------------------------------------------------------------------------- /react-home/src/index.tsx: -------------------------------------------------------------------------------- 1 | import ReactDOM from "react-dom/client"; 2 | import { debounceTime, tap } from "rxjs"; 3 | import windowStore from "../../share/store/store"; 4 | import App from "./App"; 5 | import "./index.css"; 6 | 7 | class Home extends HTMLElement { 8 | root: HTMLElement; 9 | counterSubscription = windowStore.createSubscription(); 10 | counterUpdater: { setValue: (value: number) => void } = { 11 | setValue: (value: number) => {}, 12 | }; 13 | 14 | constructor() { 15 | super(); 16 | this.root = document.createElement("div"); 17 | ReactDOM.createRoot(this.root).render( 18 | 19 | ); 20 | } 21 | 22 | connectedCallback() { 23 | this.appendChild(this.root); 24 | 25 | this.counterSubscription = windowStore.counter$ 26 | .pipe( 27 | debounceTime(1), 28 | tap((counter) => { 29 | this.counterUpdater.setValue(counter); 30 | }) 31 | ) 32 | .subscribe(); 33 | } 34 | 35 | disconnectedCallback() { 36 | this.counterSubscription.unsubscribe(); 37 | } 38 | } 39 | 40 | customElements.define("react-home-ce", Home); 41 | -------------------------------------------------------------------------------- /angular-contact/README.md: -------------------------------------------------------------------------------- 1 | # AngularContact 2 | 3 | This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 15.0.4. 4 | 5 | ## Development server 6 | 7 | Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The application will automatically reload if you change any of the source files. 8 | 9 | ## Code scaffolding 10 | 11 | Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`. 12 | 13 | ## Build 14 | 15 | Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. 16 | 17 | ## Running unit tests 18 | 19 | Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io). 20 | 21 | ## Running end-to-end tests 22 | 23 | Run `ng e2e` to execute the end-to-end tests via a platform of your choice. To use this command, you need to first add a package that implements end-to-end testing capabilities. 24 | 25 | ## Further help 26 | 27 | To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.io/cli) page. 28 | -------------------------------------------------------------------------------- /angular-contact/src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import { 2 | ChangeDetectionStrategy, 3 | ChangeDetectorRef, 4 | Component, 5 | OnDestroy, 6 | OnInit, 7 | } from '@angular/core'; 8 | import { Subscription } from 'rxjs'; 9 | import windowStore from '../../../share/store/store'; 10 | import { baseConfig } from './config'; 11 | @Component({ 12 | selector: 'app-root', 13 | templateUrl: './app.component.html', 14 | styleUrls: ['../styles.css'], 15 | changeDetection: ChangeDetectionStrategy.OnPush, 16 | }) 17 | export class AppComponent implements OnInit, OnDestroy { 18 | angularIcon = baseConfig.resolveImagePath('angular.png'); 19 | webpackIcon = baseConfig.resolveImagePath('webpack.png'); 20 | counter$ = windowStore.counter$; 21 | counterSubscription = new Subscription(); 22 | constructor(private cdr: ChangeDetectorRef) {} 23 | 24 | increase() { 25 | windowStore.increaseCounter(); 26 | } 27 | 28 | decrease() { 29 | windowStore.decreaseCounter(); 30 | } 31 | 32 | ngOnInit(): void { 33 | this.cdr.detectChanges(); 34 | this.counterSubscription.add( 35 | windowStore.counter$.subscribe(() => { 36 | this.cdr.detectChanges(); 37 | }) 38 | ); 39 | } 40 | ngOnDestroy(): void { 41 | this.counterSubscription.unsubscribe(); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /tasks/build.js: -------------------------------------------------------------------------------- 1 | const concurrently = require("concurrently"); 2 | const path = require("path"); 3 | const logger = require("../logger.js"); 4 | const runTask = require("./run"); 5 | 6 | function createBuildCommand(packageManager, name, pathName) { 7 | const pmRun = 8 | packageManager === "npm" ? `${packageManager} run` : packageManager; 9 | const command = `${packageManager} install && ${pmRun} build`; 10 | return { command, name, cwd: path.resolve(__dirname, `${pathName}`) }; 11 | } 12 | 13 | runTask((packageManager) => { 14 | logger.info(`*******Run with ${packageManager}********`); 15 | 16 | const commands = [ 17 | createBuildCommand(packageManager, "solid-shell", "../solid-shell"), 18 | createBuildCommand(packageManager, "solid-about", "../solid-about"), 19 | createBuildCommand(packageManager, "solid-home", "../solid-home"), 20 | createBuildCommand(packageManager, "angular-contact", "../angular-contact"), 21 | createBuildCommand(packageManager, "react-home", "../react-home"), 22 | createBuildCommand(packageManager, "svelte-product", "../svelte-product"), 23 | createBuildCommand(packageManager, "vue-cart", "../vue-cart"), 24 | ]; 25 | 26 | const { result } = concurrently(commands, { 27 | successCondition: "all", 28 | hide: true, 29 | }); 30 | result.then( 31 | () => logger.success("******* Build all projects successed *******"), 32 | (err) => console.error(err) 33 | ); 34 | }); 35 | -------------------------------------------------------------------------------- /vue-cart/public/vite.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /share/assets/images/vite.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /svelte-product/public/vite.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /share/assets/images/react-home/vite.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /share/assets/images/solid-shell/vite.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /share/assets/images/vue-cart/vite.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tasks/serve.js: -------------------------------------------------------------------------------- 1 | const concurrently = require("concurrently"); 2 | const path = require("path"); 3 | const logger = require("../logger.js"); 4 | const runTask = require("./run"); 5 | 6 | function createStartCommand(packageManager, name, pathName) { 7 | const pmRun = 8 | packageManager === "npm" ? `${packageManager} run` : packageManager; 9 | const command = `${packageManager} install && ${pmRun} serve`; 10 | return { command, name, cwd: path.resolve(__dirname, `${pathName}`) }; 11 | } 12 | 13 | runTask((packageManager) => { 14 | logger.info(`******* Run script with ${packageManager} ********`); 15 | 16 | const commands = [ 17 | { 18 | command: `${packageManager} install && ${packageManager} start`, 19 | name: "assets-server", 20 | cwd: path.resolve(__dirname, "../share/assets"), 21 | }, 22 | createStartCommand(packageManager, "solid-shell", "../solid-shell"), 23 | createStartCommand(packageManager, "solid-about", "../solid-about"), 24 | createStartCommand(packageManager, "angular-contact", "../angular-contact"), 25 | createStartCommand(packageManager, "react-home", "../react-home"), 26 | createStartCommand(packageManager, "svelte-product", "../svelte-product"), 27 | createStartCommand(packageManager, "vue-cart", "../vue-cart"), 28 | ]; 29 | 30 | const { result } = concurrently(commands, { 31 | successCondition: "first", 32 | hide: true, 33 | }); 34 | result.then( 35 | () => logger.success("******* Start all projects successed *******"), 36 | (err) => console.error(err) 37 | ); 38 | }); 39 | -------------------------------------------------------------------------------- /svelte-product/src/App.svelte: -------------------------------------------------------------------------------- 1 | 16 | 17 | 33 |
34 | 40 | 46 |

{counter}

47 |
48 | -------------------------------------------------------------------------------- /vue-cart/README.md: -------------------------------------------------------------------------------- 1 | # Vue 3 + TypeScript + Vite 2 | 3 | This template should help get you started developing with Vue 3 and TypeScript in Vite. The template uses Vue 3 ` 7 | 8 | 40 | 41 | 74 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Micro frontend app boilerplate 2 | 3 | ![Logo](https://s3.amazonaws.com/oodles-blogs/blog-images/8beaf2c4-fe6f-494c-b523-a963cc327043.jpeg) 4 | 5 | ## Key concepts: 6 | 7 | - Web component 8 | - Shadow root 9 | - Module federation 10 | 11 | ## How to use: 12 | 13 | ### Start each micro frontend projects: 14 | 15 | Go to folder of each project you can run 16 | 17 | ``` 18 | pnpm install && pnpm start 19 | yarn install && yarn start 20 | npm install && npm start 21 | ``` 22 | 23 | ### Start or build all micro frontend projects: 24 | 25 | Project use [**concurrently**](https://www.npmjs.com/package/concurrently) to run many script. You can check config in **./concurrently.js** 26 | From root path you can run 27 | 28 | ``` 29 | pnpm serve 30 | yarn serve 31 | npm run serve 32 | ``` 33 | 34 | ``` 35 | pnpm build 36 | yarn build 37 | npm run build 38 | ``` 39 | 40 | ### Assets: 41 | 42 | I setup a **Nodejs/Express** project at **./share/assets/app.js**. You need add your asset files of each project in specify folder 43 | **Example: ./share/assets/images/solid-about**. 44 | 45 | **Why we can not use asset files directly from project?** 46 | 47 | Because if we expose a web component and use it from another shell project. 48 | The shell project can not accessible to the asset files from micro frontend project by other origin url like below: 49 | 50 | **micro_url/assets/image.png => shell/assets/image.png** 51 | 52 | ### Frameworks supported & default projects: 53 | 54 | I config/setup default projects for each supported framework. You need follow config/setup from specify project folder.## Supported frameworks: 55 | 56 | - [SolidJS](https://www.solidjs.com) 57 | - [ReactJS](https://www.reactjs.org) 58 | - [Vuejs](https://www.vuejs.org) 59 | - [Angular](https://www.angular.io) 60 | - [Svelte](https://www.svelte.dev) 61 | 62 | ## Support frameworks(future): 63 | 64 | - [Lit](https://www.lit.dev) 65 | - [Nextjs](https://nextjs.org) 66 | 67 | ## Features(future): 68 | 69 | - [Monorepo with pnpm](https://pnpm.io/workspaces) 70 | - [Shared package module federation](https://webpack.js.org/plugins/module-federation-plugin) 71 | - Generate project with built-in CLI 72 | 73 | ## Store management: 74 | 75 | - [Rxjs](https://rxjs.dev/guide/overview) 76 | - Setup in **./share/store** 77 | 78 | ## Design architecture: 79 | 80 | ![Logo](https://i.ibb.co/ns03rLg/micro-fe-architect.jpg) 81 | 82 | ## Support 83 | 84 | For support, email quangnv1311@gmail.com or create an issue in this repo. 85 | -------------------------------------------------------------------------------- /svelte-product/README.md: -------------------------------------------------------------------------------- 1 | # Svelte + TS + Vite 2 | 3 | This template should help get you started developing with Svelte and TypeScript in Vite. 4 | 5 | ## Recommended IDE Setup 6 | 7 | [VS Code](https://code.visualstudio.com/) + [Svelte](https://marketplace.visualstudio.com/items?itemName=svelte.svelte-vscode). 8 | 9 | ## Need an official Svelte framework? 10 | 11 | Check out [SvelteKit](https://github.com/sveltejs/kit#readme), which is also powered by Vite. Deploy anywhere with its serverless-first approach and adapt to various platforms, with out of the box support for TypeScript, SCSS, and Less, and easily-added support for mdsvex, GraphQL, PostCSS, Tailwind CSS, and more. 12 | 13 | ## Technical considerations 14 | 15 | **Why use this over SvelteKit?** 16 | 17 | - It brings its own routing solution which might not be preferable for some users. 18 | - It is first and foremost a framework that just happens to use Vite under the hood, not a Vite app. 19 | 20 | This template contains as little as possible to get started with Vite + TypeScript + Svelte, while taking into account the developer experience with regards to HMR and intellisense. It demonstrates capabilities on par with the other `create-vite` templates and is a good starting point for beginners dipping their toes into a Vite + Svelte project. 21 | 22 | Should you later need the extended capabilities and extensibility provided by SvelteKit, the template has been structured similarly to SvelteKit so that it is easy to migrate. 23 | 24 | **Why `global.d.ts` instead of `compilerOptions.types` inside `jsconfig.json` or `tsconfig.json`?** 25 | 26 | Setting `compilerOptions.types` shuts out all other types not explicitly listed in the configuration. Using triple-slash references keeps the default TypeScript setting of accepting type information from the entire workspace, while also adding `svelte` and `vite/client` type information. 27 | 28 | **Why include `.vscode/extensions.json`?** 29 | 30 | Other templates indirectly recommend extensions via the README, but this file allows VS Code to prompt the user to install the recommended extension upon opening the project. 31 | 32 | **Why enable `allowJs` in the TS template?** 33 | 34 | While `allowJs: false` would indeed prevent the use of `.js` files in the project, it does not prevent the use of JavaScript syntax in `.svelte` files. In addition, it would force `checkJs: false`, bringing the worst of both worlds: not being able to guarantee the entire codebase is TypeScript, and also having worse typechecking for the existing JavaScript. In addition, there are valid use cases in which a mixed codebase may be relevant. 35 | 36 | **Why is HMR not preserving my local component state?** 37 | 38 | HMR state preservation comes with a number of gotchas! It has been disabled by default in both `svelte-hmr` and `@sveltejs/vite-plugin-svelte` due to its often surprising behavior. You can read the details [here](https://github.com/rixo/svelte-hmr#svelte-hmr). 39 | 40 | If you have state that's important to retain within a component, consider creating an external store which would not be replaced by HMR. 41 | 42 | ```ts 43 | // store.ts 44 | // An extremely simple external store 45 | import { writable } from 'svelte/store' 46 | export default writable(0) 47 | ``` 48 | -------------------------------------------------------------------------------- /angular-contact/angular.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "./node_modules/@angular/cli/lib/config/schema.json", 3 | "version": 1, 4 | "newProjectRoot": "projects", 5 | "projects": { 6 | "angular-contact": { 7 | "projectType": "application", 8 | "schematics": {}, 9 | "root": "", 10 | "sourceRoot": "src", 11 | "prefix": "app", 12 | "architect": { 13 | "build": { 14 | "builder": "ngx-build-plus:browser", 15 | "options": { 16 | "outputPath": "dist/angular-contact", 17 | "index": "src/index.html", 18 | "main": "src/main.ts", 19 | "polyfills": ["zone.js"], 20 | "tsConfig": "tsconfig.app.json", 21 | "assets": ["src/assets"], 22 | "styles": ["src/styles.css"], 23 | "scripts": [], 24 | "extraWebpackConfig": "webpack.config.js", 25 | "commonChunk": false 26 | }, 27 | "configurations": { 28 | "production": { 29 | "budgets": [ 30 | { 31 | "type": "initial", 32 | "maximumWarning": "5mb", 33 | "maximumError": "10mb" 34 | }, 35 | { 36 | "type": "anyComponentStyle", 37 | "maximumWarning": "2kb", 38 | "maximumError": "4kb" 39 | } 40 | ], 41 | "outputHashing": "all", 42 | "extraWebpackConfig": "webpack.prod.config.js" 43 | }, 44 | "development": { 45 | "buildOptimizer": false, 46 | "optimization": false, 47 | "vendorChunk": true, 48 | "extractLicenses": false, 49 | "sourceMap": true, 50 | "namedChunks": true 51 | } 52 | }, 53 | "defaultConfiguration": "production" 54 | }, 55 | "serve": { 56 | "builder": "ngx-build-plus:dev-server", 57 | "configurations": { 58 | "production": { 59 | "browserTarget": "angular-contact:build:production", 60 | "extraWebpackConfig": "webpack.prod.config.js" 61 | }, 62 | "development": { 63 | "browserTarget": "angular-contact:build:development" 64 | } 65 | }, 66 | "defaultConfiguration": "development", 67 | "options": { 68 | "port": 4175, 69 | "publicHost": "http://localhost:4175", 70 | "extraWebpackConfig": "webpack.config.js" 71 | } 72 | }, 73 | "extract-i18n": { 74 | "builder": "ngx-build-plus:extract-i18n", 75 | "options": { 76 | "browserTarget": "angular-contact:build", 77 | "extraWebpackConfig": "webpack.config.js" 78 | } 79 | }, 80 | "test": { 81 | "builder": "@angular-devkit/build-angular:karma", 82 | "options": { 83 | "polyfills": ["zone.js", "zone.js/testing"], 84 | "tsConfig": "tsconfig.spec.json", 85 | "assets": ["src/assets"], 86 | "styles": ["src/styles.css"], 87 | "scripts": [] 88 | } 89 | } 90 | } 91 | } 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /share/assets/images/react-home/react.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /solid-shell/src/App.tsx: -------------------------------------------------------------------------------- 1 | import { A, Route, Routes } from "@solidjs/router"; 2 | import { Component, createSignal, lazy, onCleanup } from "solid-js"; 3 | import { baseConfig } from "./config"; 4 | import windowStore from "../../share/store/store"; 5 | import { tap } from "rxjs"; 6 | 7 | const menus: { name: string; url: string }[] = [ 8 | { name: "Home", url: "/" }, 9 | { name: "Product", url: "/product" }, 10 | { name: "Cart", url: "/cart" }, 11 | { name: "Contact", url: "/contact" }, 12 | { name: "About", url: "/about" }, 13 | ]; 14 | 15 | const ReactHome = lazy(() => import("./web-components/react-home")); 16 | const SvelteProduct = lazy(() => import("./web-components/svelte-product")); 17 | const VueCart = lazy(() => import("./web-components/vue-cart")); 18 | const AngularContact = lazy(() => import("./web-components/angular-contact")); 19 | const SolidAbout = lazy(() => import("./web-components/solid-about")); 20 | 21 | const App: Component = () => { 22 | const [counter, setCounter] = createSignal(0); 23 | const storeSubscription = windowStore.counter$ 24 | .pipe(tap(setCounter)) 25 | .subscribe(); 26 | onCleanup(() => { 27 | storeSubscription.unsubscribe(); 28 | }); 29 | return ( 30 | <> 31 | 86 |
87 |
88 | 94 | 100 |

101 | Current counter: {counter()} 102 |

103 |
104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 |
112 | 113 | ); 114 | }; 115 | 116 | export default App; 117 | --------------------------------------------------------------------------------