├── 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 | You need to enable JavaScript to run this app.
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/solid-about/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Solid App
8 |
9 |
10 | You need to enable JavaScript to run this app.
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 |
22 | Increase
23 |
24 |
28 | Decrease
29 |
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 |
windowStore.increaseCounter()}
37 | >
38 | Increase
39 |
40 |
windowStore.decreaseCounter()}
43 | >
44 | Decrease
45 |
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 |
42 |
58 |
59 |
63 | Increase
64 |
65 |
69 | Decrease
70 |
71 |
{{ counter }}
72 |
73 |
74 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Micro frontend app boilerplate
2 |
3 | 
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 | 
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 |
32 |
85 |
86 |
87 |
88 |
windowStore.increaseCounter()}
91 | >
92 | Increase
93 |
94 |
windowStore.decreaseCounter()}
97 | >
98 | Decrease
99 |
100 |
101 | Current counter: {counter()}
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 | >
113 | );
114 | };
115 |
116 | export default App;
117 |
--------------------------------------------------------------------------------