This commit is contained in:
vutpov 2022-09-23 16:43:30 +07:00
commit 9f3a623c73
48 changed files with 13494 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
node_modules

10
package.json Normal file
View File

@ -0,0 +1,10 @@
{
"name": "test-mfe",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"private": true,
"workspaces": [
"packages/*"
]
}

6
packages/host/.babelrc Normal file
View File

@ -0,0 +1,6 @@
{
"presets": ["@babel/preset-typescript", "@babel/preset-react", "@babel/preset-env"],
"plugins": [
["@babel/transform-runtime"]
]
}

116
packages/host/.gitignore vendored Normal file
View File

@ -0,0 +1,116 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
*.lcov
# nyc test coverage
.nyc_output
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# Snowpack dependency directory (https://snowpack.dev/)
web_modules/
# TypeScript cache
*.tsbuildinfo
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Microbundle cache
.rpt2_cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variables file
.env
.env.test
# parcel-bundler cache (https://parceljs.org/)
.cache
.parcel-cache
# Next.js build output
.next
out
# Nuxt.js build / generate output
.nuxt
dist
# Gatsby files
.cache/
# Comment in the public line in if your project uses Gatsby and not Next.js
# https://nextjs.org/blog/next-9-1#public-directory-support
# public
# vuepress build output
.vuepress/dist
# Serverless directories
.serverless/
# FuseBox cache
.fusebox/
# DynamoDB Local files
.dynamodb/
# TernJS port file
.tern-port
# Stores VSCode versions used for testing VSCode extensions
.vscode-test
# yarn v2
.yarn/cache
.yarn/unplugged
.yarn/build-state.yml
.yarn/install-state.gz
.pnp.*

View File

@ -0,0 +1,43 @@
{
"name": "host",
"version": "1.0.0",
"scripts": {
"build": "webpack --mode production",
"build:dev": "webpack --mode development",
"build:start": "cd dist && PORT=8080 npx serve",
"start": "webpack serve --open --mode development",
"start:live": "webpack serve --open --mode development --live-reload --hot"
},
"license": "MIT",
"author": {
"name": "Jack Herrington",
"email": "jherr@pobox.com"
},
"devDependencies": {
"@babel/core": "^7.15.8",
"@babel/plugin-transform-runtime": "^7.15.8",
"@babel/preset-env": "^7.15.8",
"@babel/preset-react": "^7.14.5",
"@babel/preset-typescript": "^7.10.4",
"@types/react": "^17.0.2",
"@types/react-dom": "^17.0.2",
"autoprefixer": "^10.1.0",
"babel-loader": "^8.2.2",
"css-loader": "^6.3.0",
"html-webpack-plugin": "^5.3.2",
"postcss": "^8.2.1",
"postcss-loader": "^4.1.0",
"shared-types": "1.0.0",
"style-loader": "^3.3.0",
"typescript": "^4.5.2",
"webpack": "^5.57.1",
"webpack-cli": "^4.9.0",
"webpack-dev-server": "^4.3.1"
},
"dependencies": {
"@reduxjs/toolkit": "^1.8.5",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-redux": "^8.0.4"
}
}

32
packages/host/src/App.tsx Normal file
View File

@ -0,0 +1,32 @@
import React, { useEffect } from 'react'
import ReactDOM from 'react-dom'
import Counter from 'remote/Counter'
import './index.css'
import { Counter as CounterComponentType } from 'shared-types'
import SvelteCounter from 'remoteSvelte/Counter'
import { StoreProvider } from 'store/store'
const CounterComp = Counter as CounterComponentType
const App = () => {
useEffect(() => {
new SvelteCounter({
target: document.getElementById('svelteApp'),
})
}, [])
return (
<div className="container">
<CounterComp initialValue={2} />
<div id={'svelteApp'}></div>
</div>
)
}
ReactDOM.render(
<StoreProvider>
<App />
</StoreProvider>,
document.getElementById('app'),
)

View File

@ -0,0 +1,10 @@
body {
font-family: Arial, Helvetica, sans-serif;
}
.container {
font-size: 3rem;
margin: auto;
max-width: 800px;
margin-top: 20px;
}

View File

@ -0,0 +1,15 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>host</title>
</head>
<body>
<div id="app"></div>
</body>
</html>

View File

@ -0,0 +1,3 @@
import("./App");
export {};

2
packages/host/src/remote.d.ts vendored Normal file
View File

@ -0,0 +1,2 @@
declare module "remote/Counter";
declare module "remoteSvelte/Counter";

View File

@ -0,0 +1,35 @@
{
"compilerOptions": {
"target": "es5",
"lib": [
"dom",
"dom.iterable",
"esnext"
],
"allowJs": true,
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"strict": false,
"forceConsistentCasingInFileNames": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react",
"baseUrl": "./src",
"rootDir": ".",
"suppressImplicitAnyIndexErrors": true,
"strictNullChecks": false,
"noImplicitAny": false,
"noFallthroughCasesInSwitch": true
},
"include": [
"src"
],
"exclude": [
"src/test/**",
"node_modules"
]
}

View File

@ -0,0 +1,67 @@
const HtmlWebPackPlugin = require("html-webpack-plugin");
const ModuleFederationPlugin = require("webpack/lib/container/ModuleFederationPlugin");
const deps = require("./package.json").dependencies;
module.exports = {
output: {
publicPath: "http://localhost:8080/",
},
resolve: {
extensions: [".tsx", ".ts", ".jsx", ".js", ".json"],
},
devServer: {
port: 8080,
historyApiFallback: true,
},
module: {
rules: [
{
test: /\.m?js/,
type: "javascript/auto",
resolve: {
fullySpecified: false,
},
},
{
test: /\.(css|s[ac]ss)$/i,
use: ["style-loader", "css-loader", "postcss-loader"],
},
{
test: /\.(ts|tsx|js|jsx)$/,
exclude: /node_modules/,
use: {
loader: "babel-loader",
},
},
],
},
plugins: [
new ModuleFederationPlugin({
name: "host",
filename: "remoteEntry.js",
remotes: {
remote: "remote@http://localhost:3000/remoteEntry.js",
remoteSvelte: "remoteSvelte@http://localhost:3001/remoteEntry.js",
store: "store@http://localhost:7070/remoteEntry.js",
},
shared: {
...deps,
react: {
singleton: true,
requiredVersion: deps.react,
},
"react-dom": {
singleton: true,
requiredVersion: deps["react-dom"],
},
},
}),
new HtmlWebPackPlugin({
template: "./src/index.html",
}),
],
};

3867
packages/host/yarn.lock Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,5 @@
{
"presets": [
"@babel/preset-env"
]
}

View File

@ -0,0 +1,31 @@
{
"name": "remote-svelte",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"devDependencies": {
"@babel/core": "^7.19.1",
"@babel/polyfill": "^7.12.1",
"@babel/preset-env": "^7.19.1",
"babel-loader": "^8.2.5",
"css-loader": "^6.7.1",
"dotenv-webpack": "^8.0.1",
"file-loader": "^6.2.0",
"html-webpack-plugin": "^5.5.0",
"mini-css-extract-plugin": "^2.6.1",
"svelte-check": "^2.9.0",
"svelte-loader": "^3.1.3",
"svelte-preprocess": "^4.10.7",
"webpack": "^5.74.0",
"webpack-cli": "^4.10.0",
"webpack-dev-server": "^4.11.1"
},
"dependencies": {
"svelte": "^3.50.1"
},
"scripts": {
"serve": "http-server ./dist/ --cors -o -c-1 --proxy",
"build": "webpack --mode production",
"start": "webpack serve --open chrome"
}
}

View File

@ -0,0 +1,33 @@
<script lang="ts">
import {store, increment, decrement, useSvelteSelector} from 'store/store';
$: counter = useSvelteSelector((state)=> state.counter.value, newCounter => (counter = newCounter));
function incrementCount() {
store.dispatch(increment())
}
function decrementCount() {
store.dispatch(decrement())
}
</script>
<style>
.container{
display: flex;
font-size: 3rem;
margin: auto;
max-width: 800px;
margin-top: 20px;
font-family: Arial, Helvetica, sans-serif;
}
</style>
<div class="container">
<div> Svelt Counter:{counter}</div>
<button on:click={incrementCount}>+</button>
<button on:click={decrementCount}>-</button>
</div>

View File

@ -0,0 +1,13 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<!--This is the node that svelte is going to take to make the magic-->
<div id="root"></div>
</body>
</html>

View File

@ -0,0 +1,7 @@
import App from "./App.svelte";
// const app = new App({
// target: document.getElementById("root"), // entry point in ../public/index.html
// });
export default App;

View File

@ -0,0 +1,87 @@
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const Dotenv = require("dotenv-webpack");
const sveltePreprocess = require("svelte-preprocess");
const ModuleFederationPlugin = require("webpack/lib/container/ModuleFederationPlugin");
const deps = require("./package.json").dependencies;
module.exports = {
// This says to webpack that we are in development mode and write the code in webpack file in different way
mode: "development",
//Our index file
entry: "./src/index.js",
//Where we put the production code
output: {
path: path.resolve(__dirname, "dist"),
filename: "bundle.js",
publicPath: "http://localhost:3001/",
},
module: {
rules: [
//Allows use of modern javascript
{
test: /\.js?$/,
exclude: /node_modules/, //don't test node_modules folder
use: {
loader: "babel-loader",
},
},
//Allows use of svelte
{
test: /\.svelte$/,
use: {
loader: "svelte-loader",
options: {
preprocess: sveltePreprocess({}),
},
},
},
//Allows use of CSS
{
test: /\.css$/,
use: [MiniCssExtractPlugin.loader, "css-loader"],
},
//Allows use of images
{
test: /\.(jpg|jpeg|png|svg)$/,
use: "file-loader",
},
],
},
//this is what enables users to leave off the extension when importing
resolve: {
extensions: [".mjs", ".js", ".svelte"],
},
plugins: [
//Allows to create an index.html in our build folder
new HtmlWebpackPlugin({
template: path.resolve(__dirname, "src/index.html"),
}),
//This gets all our css and put in a unique file
new MiniCssExtractPlugin(),
//take our environment variable in .env file
//And it does a text replace in the resulting bundle for any instances of process.env.
new Dotenv(),
new ModuleFederationPlugin({
name: "remoteSvelte",
filename: "remoteEntry.js",
remotes: {
store: "store@http://localhost:7070/remoteEntry.js",
},
exposes: {
"./Counter": "./src/index.js",
},
shared: {
...deps,
},
}),
],
////Config for webpack-dev-server module
devServer: {
historyApiFallback: true,
hot: true,
port: 3001,
},
};

View File

@ -0,0 +1,59 @@
Arguments:
C:\Program Files\nodejs\node.exe C:\Users\Thary\AppData\Roaming\npm\node_modules\yarn\bin\yarn.js dev
PATH:
C:\Users\Thary\bin;C:\Program Files\Git\mingw64\bin;C:\Program Files\Git\usr\local\bin;C:\Program Files\Git\usr\bin;C:\Program Files\Git\usr\bin;C:\Program Files\Git\mingw64\bin;C:\Program Files\Git\usr\bin;C:\Users\Thary\bin;C:\Program Files (x86)\Common Files\Oracle\Java\javapath;C:\ProgramData\Oracle\Java\javapath;C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;C:\WINDOWS\System32\WindowsPowerShell\v1.0;C:\WINDOWS\System32\OpenSSH;C:\Program Files\Git\cmd;C:\xampp\php;C:\Program Files\Microsoft VS Code\bin;C:\Program Files\Dart\dart-sdk\bin;C:\apache-maven\bin;C:\Program Files\PuTTY;C:\Program Files\Docker\Docker\resources\bin;C:\ProgramData\DockerDesktop\version-bin;C:\Program Files\Kubernetes\Minikube;C:\minikube;C:\Program Files\nodejs;D:\software\kompose;C:\Program Files\MySQL\MySQL Shell 8.0\bin;C:\Users\Thary\AppData\Local\Microsoft\WindowsApps;C:\Program Files\Microsoft VS Code\bin;C:\Program Files\heroku\bin;C:\flutter\bin;C:\Users\Thary\AppData\Local\Android\Sdk\platform-tools;C:\Users\Thary\AppData\Local\Android\Sdk\tools;C:\Users\Thary\AppData\Local\Android\Sdk\tools\bin;C:\Users\Thary\.dotnet\tools;C:\Users\Thary\AppData\Local\Programs\Python\Python39;C:\Users\Thary\AppData\Local\Programs\Python\Python39\Scripts;C:\Users\Thary\AppData\Local\Microsoft\WindowsApps;C:\Program Files\PostgreSQL\12\bin;D:\flutter\flutter_windows_3.3.1-stable\bin;C:\Users\Thary\AppData\Local\Programs\Microsoft VS Code\bin;C:\Program Files\JetBrains\IntelliJ IDEA 2022.1\bin;C:\Program Files\Git\mingw64\bin;C:\Users\Thary\AppData\Roaming\npm;D:\web\kompose.exe;C:\Program Files\Git\usr\bin\vendor_perl;C:\Program Files\Git\usr\bin\core_perl
Yarn version:
1.22.19
Node version:
16.17.0
Platform:
win32 x64
Trace:
SyntaxError: D:\web\test-mfe\packages\remote-svelte\package.json: Unexpected token } in JSON at position 752
at JSON.parse (<anonymous>)
at C:\Users\Thary\AppData\Roaming\npm\node_modules\yarn\lib\cli.js:1629:59
at Generator.next (<anonymous>)
at step (C:\Users\Thary\AppData\Roaming\npm\node_modules\yarn\lib\cli.js:310:30)
at C:\Users\Thary\AppData\Roaming\npm\node_modules\yarn\lib\cli.js:321:13
npm manifest:
{
"name": "remote-svelte",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"devDependencies": {
"@babel/core": "^7.19.1",
"@babel/polyfill": "^7.12.1",
"@babel/preset-env": "^7.19.1",
"babel-loader": "^8.2.5",
"css-loader": "^6.7.1",
"dotenv-webpack": "^8.0.1",
"file-loader": "^6.2.0",
"html-webpack-plugin": "^5.5.0",
"mini-css-extract-plugin": "^2.6.1",
"svelte-loader": "^3.1.3",
"webpack": "^5.74.0",
"webpack-cli": "^4.10.0",
"webpack-dev-server": "^4.11.1"
},
"dependencies": {
"svelte": "^3.50.1"
},
"scripts": {
"start": "http-server ./dist/ --cors -o -c-1 --proxy",
"build": "webpack --mode production",
"dev": "webpack serve --open chrome"
},
}
yarn manifest:
No manifest
Lockfile:
No lockfile

6
packages/remote/.babelrc Normal file
View File

@ -0,0 +1,6 @@
{
"presets": ["@babel/preset-typescript", "@babel/preset-react", "@babel/preset-env"],
"plugins": [
["@babel/transform-runtime"]
]
}

116
packages/remote/.gitignore vendored Normal file
View File

@ -0,0 +1,116 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
*.lcov
# nyc test coverage
.nyc_output
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# Snowpack dependency directory (https://snowpack.dev/)
web_modules/
# TypeScript cache
*.tsbuildinfo
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Microbundle cache
.rpt2_cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variables file
.env
.env.test
# parcel-bundler cache (https://parceljs.org/)
.cache
.parcel-cache
# Next.js build output
.next
out
# Nuxt.js build / generate output
.nuxt
dist
# Gatsby files
.cache/
# Comment in the public line in if your project uses Gatsby and not Next.js
# https://nextjs.org/blog/next-9-1#public-directory-support
# public
# vuepress build output
.vuepress/dist
# Serverless directories
.serverless/
# FuseBox cache
.fusebox/
# DynamoDB Local files
.dynamodb/
# TernJS port file
.tern-port
# Stores VSCode versions used for testing VSCode extensions
.vscode-test
# yarn v2
.yarn/cache
.yarn/unplugged
.yarn/build-state.yml
.yarn/install-state.gz
.pnp.*

View File

@ -0,0 +1,41 @@
{
"name": "remote",
"version": "1.0.0",
"scripts": {
"build": "webpack --mode production",
"build:dev": "webpack --mode development",
"build:start": "cd dist && PORT={{PORT}} npx serve",
"start": "webpack serve --open --mode development",
"start:live": "webpack serve --open --mode development --live-reload --hot"
},
"license": "MIT",
"author": {
"name": "Jack Herrington",
"email": "jherr@pobox.com"
},
"devDependencies": {
"@babel/core": "^7.15.8",
"@babel/plugin-transform-runtime": "^7.15.8",
"@babel/preset-env": "^7.15.8",
"@babel/preset-react": "^7.14.5",
"@babel/preset-typescript": "^7.10.4",
"@types/react": "^17.0.2",
"@types/react-dom": "^17.0.2",
"autoprefixer": "^10.1.0",
"babel-loader": "^8.2.2",
"css-loader": "^6.3.0",
"html-webpack-plugin": "^5.3.2",
"postcss": "^8.2.1",
"postcss-loader": "^4.1.0",
"style-loader": "^3.3.0",
"typescript": "^4.5.2",
"webpack": "^5.57.1",
"webpack-cli": "^4.9.0",
"webpack-dev-server": "^4.3.1"
},
"dependencies": {
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-redux": "^8.0.4"
}
}

View File

@ -0,0 +1,36 @@
import React from 'react'
import { useStore } from 'store/store'
const Counter: React.FC<{
initialValue?: number
}> = (props) => {
//@ts-ignore
const { increment, decrement, count: counter } = useStore()
return (
<div
style={{
display: 'flex',
}}
>
<div>React counter: {counter}</div>
<button
onClick={() => {
increment()
}}
>
+
</button>
<button
onClick={() => {
decrement()
}}
>
-
</button>
</div>
)
}
export default Counter

View File

@ -0,0 +1,10 @@
body {
font-family: Arial, Helvetica, sans-serif;
}
.container {
font-size: 3rem;
margin: auto;
max-width: 800px;
margin-top: 20px;
}

View File

@ -0,0 +1,14 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>remote</title>
</head>
<body>
<div id="app"></div>
</body>
</html>

View File

View File

@ -0,0 +1,35 @@
{
"compilerOptions": {
"target": "es5",
"lib": [
"dom",
"dom.iterable",
"esnext"
],
"allowJs": true,
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"strict": false,
"forceConsistentCasingInFileNames": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react",
"baseUrl": "./src",
"rootDir": ".",
"suppressImplicitAnyIndexErrors": true,
"strictNullChecks": false,
"noImplicitAny": false,
"noFallthroughCasesInSwitch": true
},
"include": [
"src"
],
"exclude": [
"src/test/**",
"node_modules"
]
}

View File

@ -0,0 +1,68 @@
const HtmlWebPackPlugin = require("html-webpack-plugin");
const ModuleFederationPlugin = require("webpack/lib/container/ModuleFederationPlugin");
const deps = require("./package.json").dependencies;
module.exports = {
output: {
publicPath: "http://localhost:3000/",
},
resolve: {
extensions: [".tsx", ".ts", ".jsx", ".js", ".json"],
},
devServer: {
port: 3000,
historyApiFallback: true,
},
module: {
rules: [
{
test: /\.m?js/,
type: "javascript/auto",
resolve: {
fullySpecified: false,
},
},
{
test: /\.(css|s[ac]ss)$/i,
use: ["style-loader", "css-loader", "postcss-loader"],
},
{
test: /\.(ts|tsx|js|jsx)$/,
exclude: /node_modules/,
use: {
loader: "babel-loader",
},
},
],
},
plugins: [
new ModuleFederationPlugin({
name: "remote",
filename: "remoteEntry.js",
remotes: {
store: "store@http://localhost:7070/remoteEntry.js",
},
exposes: {
"./Counter": "./src/Counter.tsx",
},
shared: {
...deps,
react: {
singleton: true,
requiredVersion: deps.react,
},
"react-dom": {
singleton: true,
requiredVersion: deps["react-dom"],
},
},
}),
new HtmlWebPackPlugin({
template: "./src/index.html",
}),
],
};

3867
packages/remote/yarn.lock Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,6 @@
{
"presets": ["@babel/preset-typescript", "@babel/preset-react", "@babel/preset-env"],
"plugins": [
["@babel/transform-runtime"]
]
}

116
packages/shared-types/.gitignore vendored Normal file
View File

@ -0,0 +1,116 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
*.lcov
# nyc test coverage
.nyc_output
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# Snowpack dependency directory (https://snowpack.dev/)
web_modules/
# TypeScript cache
*.tsbuildinfo
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Microbundle cache
.rpt2_cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variables file
.env
.env.test
# parcel-bundler cache (https://parceljs.org/)
.cache
.parcel-cache
# Next.js build output
.next
out
# Nuxt.js build / generate output
.nuxt
dist
# Gatsby files
.cache/
# Comment in the public line in if your project uses Gatsby and not Next.js
# https://nextjs.org/blog/next-9-1#public-directory-support
# public
# vuepress build output
.vuepress/dist
# Serverless directories
.serverless/
# FuseBox cache
.fusebox/
# DynamoDB Local files
.dynamodb/
# TernJS port file
.tern-port
# Stores VSCode versions used for testing VSCode extensions
.vscode-test
# yarn v2
.yarn/cache
.yarn/unplugged
.yarn/build-state.yml
.yarn/install-state.gz
.pnp.*

View File

@ -0,0 +1,42 @@
{
"name": "shared-types",
"version": "1.0.0",
"scripts": {
"build": "webpack --mode production",
"build:dev": "webpack --mode development",
"build:start": "cd dist && PORT=8080 npx serve",
"start": "webpack serve --open --mode development",
"start:live": "webpack serve --open --mode development --live-reload --hot"
},
"main": "./src/types.ts",
"license": "MIT",
"author": {
"name": "Jack Herrington",
"email": "jherr@pobox.com"
},
"devDependencies": {
"@babel/core": "^7.15.8",
"@babel/plugin-transform-runtime": "^7.15.8",
"@babel/preset-env": "^7.15.8",
"@babel/preset-react": "^7.14.5",
"@babel/preset-typescript": "^7.10.4",
"@types/react": "^17.0.2",
"@types/react-dom": "^17.0.2",
"autoprefixer": "^10.1.0",
"babel-loader": "^8.2.2",
"css-loader": "^6.3.0",
"html-webpack-plugin": "^5.3.2",
"postcss": "^8.2.1",
"postcss-loader": "^4.1.0",
"style-loader": "^3.3.0",
"typescript": "^4.5.2",
"webpack": "^5.57.1",
"webpack-cli": "^4.9.0",
"webpack-dev-server": "^4.3.1",
"shared-types": "1.0.0"
},
"dependencies": {
"react": "^17.0.2",
"react-dom": "^17.0.2"
}
}

View File

@ -0,0 +1,4 @@
import React from "react";
export type Counter = React.FC<{
initialValue?: number;
}>;

View File

@ -0,0 +1,35 @@
{
"compilerOptions": {
"target": "es5",
"lib": [
"dom",
"dom.iterable",
"esnext"
],
"allowJs": true,
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"strict": false,
"forceConsistentCasingInFileNames": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react",
"baseUrl": "./src",
"rootDir": ".",
"suppressImplicitAnyIndexErrors": true,
"strictNullChecks": false,
"noImplicitAny": false,
"noFallthroughCasesInSwitch": true
},
"include": [
"src"
],
"exclude": [
"src/test/**",
"node_modules"
]
}

View File

@ -0,0 +1,64 @@
const HtmlWebPackPlugin = require("html-webpack-plugin");
const ModuleFederationPlugin = require("webpack/lib/container/ModuleFederationPlugin");
const deps = require("./package.json").dependencies;
module.exports = {
output: {
publicPath: "http://localhost:8080/",
},
resolve: {
extensions: [".tsx", ".ts", ".jsx", ".js", ".json"],
},
devServer: {
port: 8080,
historyApiFallback: true,
},
module: {
rules: [
{
test: /\.m?js/,
type: "javascript/auto",
resolve: {
fullySpecified: false,
},
},
{
test: /\.(css|s[ac]ss)$/i,
use: ["style-loader", "css-loader", "postcss-loader"],
},
{
test: /\.(ts|tsx|js|jsx)$/,
exclude: /node_modules/,
use: {
loader: "babel-loader",
},
},
],
},
plugins: [
new ModuleFederationPlugin({
name: "remote",
filename: "remoteEntry.js",
remotes: {},
exposes: {},
shared: {
...deps,
react: {
singleton: true,
requiredVersion: deps.react,
},
"react-dom": {
singleton: true,
requiredVersion: deps["react-dom"],
},
},
}),
new HtmlWebPackPlugin({
template: "./src/index.html",
}),
],
};

6
packages/store/.babelrc Normal file
View File

@ -0,0 +1,6 @@
{
"presets": ["@babel/preset-typescript", "@babel/preset-react", "@babel/preset-env"],
"plugins": [
["@babel/transform-runtime"]
]
}

116
packages/store/.gitignore vendored Normal file
View File

@ -0,0 +1,116 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
*.lcov
# nyc test coverage
.nyc_output
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# Snowpack dependency directory (https://snowpack.dev/)
web_modules/
# TypeScript cache
*.tsbuildinfo
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Microbundle cache
.rpt2_cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variables file
.env
.env.test
# parcel-bundler cache (https://parceljs.org/)
.cache
.parcel-cache
# Next.js build output
.next
out
# Nuxt.js build / generate output
.nuxt
dist
# Gatsby files
.cache/
# Comment in the public line in if your project uses Gatsby and not Next.js
# https://nextjs.org/blog/next-9-1#public-directory-support
# public
# vuepress build output
.vuepress/dist
# Serverless directories
.serverless/
# FuseBox cache
.fusebox/
# DynamoDB Local files
.dynamodb/
# TernJS port file
.tern-port
# Stores VSCode versions used for testing VSCode extensions
.vscode-test
# yarn v2
.yarn/cache
.yarn/unplugged
.yarn/build-state.yml
.yarn/install-state.gz
.pnp.*

View File

@ -0,0 +1,42 @@
{
"name": "store",
"version": "1.0.0",
"scripts": {
"build": "webpack --mode production",
"build:dev": "webpack --mode development",
"build:start": "cd dist && PORT=7070 npx serve",
"start": "webpack serve --open --mode development",
"start:live": "webpack serve --open --mode development --live-reload --hot"
},
"license": "MIT",
"author": {
"name": "Jack Herrington",
"email": "jherr@pobox.com"
},
"devDependencies": {
"@babel/core": "^7.15.8",
"@babel/plugin-transform-runtime": "^7.15.8",
"@babel/preset-env": "^7.15.8",
"@babel/preset-react": "^7.14.5",
"@babel/preset-typescript": "^7.10.4",
"@types/react": "^17.0.2",
"@types/react-dom": "^17.0.2",
"autoprefixer": "^10.1.0",
"babel-loader": "^8.2.2",
"css-loader": "^6.3.0",
"html-webpack-plugin": "^5.3.2",
"postcss": "^8.2.1",
"postcss-loader": "^4.1.0",
"style-loader": "^3.3.0",
"typescript": "^4.5.2",
"webpack": "^5.57.1",
"webpack-cli": "^4.9.0",
"webpack-dev-server": "^4.3.1"
},
"dependencies": {
"@reduxjs/toolkit": "^1.8.5",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-redux": "^8.0.4"
}
}

View File

@ -0,0 +1,14 @@
import React from "react";
import ReactDOM from "react-dom";
import "./index.css";
const App = () => (
<div className="container">
<div>Name: store</div>
<div>Framework: react</div>
<div>Language: TypeScript</div>
<div>CSS: Empty CSS</div>
</div>
);
ReactDOM.render(<App />, document.getElementById("app"));

View File

@ -0,0 +1,10 @@
body {
font-family: Arial, Helvetica, sans-serif;
}
.container {
font-size: 3rem;
margin: auto;
max-width: 800px;
margin-top: 20px;
}

View File

@ -0,0 +1,14 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>store</title>
</head>
<body>
<div id="app"></div>
</body>
</html>

View File

@ -0,0 +1 @@
import("./App");

View File

@ -0,0 +1,61 @@
import React from 'react'
import { configureStore, createSlice } from '@reduxjs/toolkit'
import { Provider, useSelector } from 'react-redux'
const counterSlice = createSlice({
name: 'counter',
initialState: {
value: 0,
},
reducers: {
increment: (state) => {
state.value += 1
},
decrement: (state) => {
state.value -= 1
},
incrementByAmount: (state, action) => {
state.value += action.payload
},
},
})
export const { increment, decrement, incrementByAmount } = counterSlice.actions
export const store = configureStore({
reducer: {
counter: counterSlice.reducer,
},
})
export const StoreProvider: React.FC = (props) => {
return <Provider store={store}>{props.children}</Provider>
}
export const useStore = () => {
//@ts-ignore
const count = useSelector((state) => state.counter.value)
return {
count,
increment: () => store.dispatch(increment()),
decrement: () => store.dispatch(decrement()),
incrementByAmount: (value) => store.dispatch(incrementByAmount(value)),
}
}
export const useSvelteSelector = (select, onChange) => {
let currentState
function handleChange() {
let nextState = select(store.getState())
if (nextState !== currentState) {
currentState = nextState
onChange(currentState)
}
}
store.subscribe(handleChange)
handleChange()
return currentState
}

View File

@ -0,0 +1,35 @@
{
"compilerOptions": {
"target": "es5",
"lib": [
"dom",
"dom.iterable",
"esnext"
],
"allowJs": true,
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"strict": false,
"forceConsistentCasingInFileNames": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react",
"baseUrl": "./src",
"rootDir": ".",
"suppressImplicitAnyIndexErrors": true,
"strictNullChecks": false,
"noImplicitAny": false,
"noFallthroughCasesInSwitch": true
},
"include": [
"src"
],
"exclude": [
"src/test/**",
"node_modules"
]
}

View File

@ -0,0 +1,66 @@
const HtmlWebPackPlugin = require("html-webpack-plugin");
const ModuleFederationPlugin = require("webpack/lib/container/ModuleFederationPlugin");
const deps = require("./package.json").dependencies;
module.exports = {
output: {
publicPath: "http://localhost:7070/",
},
resolve: {
extensions: [".tsx", ".ts", ".jsx", ".js", ".json"],
},
devServer: {
port: 7070,
historyApiFallback: true,
},
module: {
rules: [
{
test: /\.m?js/,
type: "javascript/auto",
resolve: {
fullySpecified: false,
},
},
{
test: /\.(css|s[ac]ss)$/i,
use: ["style-loader", "css-loader", "postcss-loader"],
},
{
test: /\.(ts|tsx|js|jsx)$/,
exclude: /node_modules/,
use: {
loader: "babel-loader",
},
},
],
},
plugins: [
new ModuleFederationPlugin({
name: "store",
filename: "remoteEntry.js",
remotes: {},
exposes: {
"./store": "./src/store/index.tsx",
},
shared: {
...deps,
react: {
singleton: true,
requiredVersion: deps.react,
},
"react-dom": {
singleton: true,
requiredVersion: deps["react-dom"],
},
},
}),
new HtmlWebPackPlugin({
template: "./src/index.html",
}),
],
};

12
readme.md Normal file
View File

@ -0,0 +1,12 @@
# Micro Front End Example
## Mircro frontend with React as Host and React, Svelte as child and Redux as global state
[Micro-Frontends in Just 10 Minutes](https://www.youtube.com/watch?v=s_Fs4AXsTnA&t=540s)
[State Management for Module Federation Four Ways](https://www.youtube.com/watch?v=njXeMeAu4Sg)
## How to run
* yarn
* go to each folder in packages and yarn
* yarn start on host, remote, store

4215
yarn.lock Normal file

File diff suppressed because it is too large Load Diff