remote
, 引用者被称为host
,remote
暴露模块给host
, host
则可以使用这些暴露的模块,这些模块被成为remote
模块字段 | 类型 | 含义 |
---|---|---|
name | string | 必传值,即输出的模块名,被远程引用时路径为${name}/${expose} |
library | object | 声明全局变量的方式,name为umd的name |
filename | string | 构建输出的文件名 |
remotes | object | 远程引用的应用名及其别名的映射,使用时以key值作为name |
exposes | object | 被远程引用时可暴露的资源路径及其别名 |
shared | object | 与其他应用之间可以共享的第三方依赖,使你的代码中不用重复加载同一份依赖 |
cnpm i webpack webpack-cli webpack-dev-server babel-loader @babel/core @babel/preset-env -D
let path = require("path");
let webpack = require("webpack");
let HtmlWebpackPlugin = require("html-webpack-plugin");
const ModuleFederationPlugin = require("webpack/lib/container/ModuleFederationPlugin");
module.exports = {
mode: "development",
entry: "./src/index.js",
output: {
publicPath: "http://localhost:3000/",
},
devServer: {
port: 3000
},
module: {
rules: [
{
test: /\.jsx?$/,
use: {
loader: 'babel-loader',
options: {
presets: ["@babel/preset-react"]
},
},
exclude: /node_modules/,
},
]
},
plugins: [
new HtmlWebpackPlugin({
template:'./public/index.html'
}),
new ModuleFederationPlugin({
filename: "remoteEntry.js",
name: "remote",
exposes: {
"./NewsList": "./src/NewsList",
}
})
]
}
remote\src\index.js
import("./bootstrap");
remote\src\bootstrap.js
import React from "react";
import ReactDOM from "react-dom";
import App from "./App";
ReactDOM.render(<App />, document.getElementById("root"));
remote\src\App.js
import React from "react";
import NewsList from './NewsList';
const App = () => (
<div>
<h2>本地组件NewsList</h2>
<NewsList />
</div>
);
export default App;
remote\src\NewsList.js
import React from "react";
export default ()=>(
<div>新闻列表</div>
)
host\webpack.config.js
let path = require("path");
let webpack = require("webpack");
let HtmlWebpackPlugin = require("html-webpack-plugin");
const ModuleFederationPlugin = require("webpack/lib/container/ModuleFederationPlugin");
module.exports = {
mode: "development",
entry: "./src/index.js",
output: {
publicPath: "http://localhost:8000/",
},
devServer: {
port: 8000
},
module: {
rules: [
{
test: /\.jsx?$/,
use: {
loader: 'babel-loader',
options: {
presets: ["@babel/preset-react"]
},
},
exclude: /node_modules/,
},
]
},
plugins: [
new HtmlWebpackPlugin({
template: './public/index.html'
}),
new ModuleFederationPlugin({
filename: "remoteEntry.js",
name: "host",
remotes: {
remote: "remote@http://localhost:3000/remoteEntry.js"
}
})
]
}
host\src\index.js
import("./bootstrap");
host\src\bootstrap.js
import React from "react";
import ReactDOM from "react-dom";
import App from "./App";
ReactDOM.render(<App />, document.getElementById("root"));
host\src\App.js
import React from "react";
import Slides from './Slides';
const RemoteNewsList = React.lazy(() => import("remote/NewsList"));
const App = () => (
<div>
<h2 >本地组件Slides, 远程组件NewsList</h2>
<Slides />
<React.Suspense fallback="Loading NewsList">
<RemoteNewsList />
</React.Suspense>
</div>
);
export default App;
host\src\Slides.js
import React from "react";
export default ()=>(
<div>轮播图</div>
)
shared
配置主要是用来避免项目出现多个公共依赖 plugins: [
new HtmlWebpackPlugin({
template:'./public/index.html'
}),
new ModuleFederationPlugin({
filename: "remoteEntry.js",
name: "remote",
exposes: {
"./NewsList": "./src/NewsList",
},
+ shared:{
+ react: { singleton: true },
+ "react-dom": { singleton: true }
+ }
})
]
plugins: [
new HtmlWebpackPlugin({
template: './public/index.html'
}),
new ModuleFederationPlugin({
filename: "remoteEntry.js",
name: "host",
remotes: {
remote: "remote@http://localhost:3000/remoteEntry.js"
},
+ shared:{
+ react: { singleton: true },
+ "react-dom": { singleton: true }
+ }
})
]
plugins: [
new HtmlWebpackPlugin({
template:'./public/index.html'
}),
new ModuleFederationPlugin({
filename: "remoteEntry.js",
name: "remote",
+ remotes: {
+ host: "host@http://localhost:8000/remoteEntry.js"
+ },
exposes: {
"./NewsList": "./src/NewsList",
},
shared:{
react: { singleton: true },
"react-dom": { singleton: true }
}
})
]
plugins: [
new HtmlWebpackPlugin({
template: './public/index.html'
}),
new ModuleFederationPlugin({
filename: "remoteEntry.js",
name: "host",
remotes: {
remote: "remote@http://localhost:3000/remoteEntry.js"
},
+ exposes: {
+ "./Slides": "./src/Slides",
+ },
shared:{
react: { singleton: true },
"react-dom": { singleton: true }
}
})
]
remote\src\App.js
import React from "react";
import NewsList from './NewsList';
+const RemoteSlides = React.lazy(() => import("host/Slides"));
const App = () => (
<div>
+ <h2>本地组件NewsList,远程组件Slides</h2>
<NewsList />
+ <React.Suspense fallback="Loading Slides">
+ <RemoteSlides />
+ </React.Suspense>
</div>
);
export default App;
let path = require("path");
let webpack = require("webpack");
let HtmlWebpackPlugin = require("html-webpack-plugin");
const ModuleFederationPlugin = require("webpack/lib/container/ModuleFederationPlugin");
module.exports = {
mode: "development",
entry: "./src/index.js",
output: {
publicPath: "http://localhost:3000/",
},
devServer: {
port: 5000
},
module: {
rules: [
{
test: /\.jsx?$/,
use: {
loader: 'babel-loader',
options: {
presets: ["@babel/preset-react"]
},
},
exclude: /node_modules/,
},
]
},
plugins: [
new HtmlWebpackPlugin({
template:'./public/index.html'
}),
new ModuleFederationPlugin({
filename: "remoteEntry.js",
name: "all",
remotes: {
remote: "remote@http://localhost:3000/remoteEntry.js",
host: "host@http://localhost:8000/remoteEntry.js",
},
shared:{
react: { singleton: true },
"react-dom": { singleton: true }
}
})
]
}
remote\src\index.js
import("./bootstrap");
remote\src\bootstrap.js
import React from "react";
import ReactDOM from "react-dom";
import App from "./App";
ReactDOM.render(<App />, document.getElementById("root"));
remote\src\App.js
import React from "react";
const RemoteSlides = React.lazy(() => import("host/Slides"));
const RemoteNewsList = React.lazy(() => import("remote/NewsList"));
const App = () => (
<div>
<h2>远程组件Slides,远程组件NewsList</h2>
<React.Suspense fallback="Loading Slides">
<RemoteSlides />
</React.Suspense>
<React.Suspense fallback="Loading NewsList">
<RemoteNewsList />
</React.Suspense>
</div>
);
export default App;
Remote\webpack.config.js
let path = require("path");
let webpack = require("webpack");
let HtmlWebpackPlugin = require("html-webpack-plugin");
const ModuleFederationPlugin = require("webpack/lib/container/ModuleFederationPlugin");
module.exports = {
mode: "development",
devtool:false,
entry: "./src/index.js",
output: {
publicPath: "http://localhost:8080/",
//hotUpdateGlobal:'webpackHotUpdate',
//chunkLoadingGlobal: 'webpackChunk'
},
devServer: {
port: 3000
},
module: {
rules: [
{
test: /\.jsx?$/,
use: {
loader: 'babel-loader',
options: {
presets: ["@babel/preset-react"]
},
},
exclude: /node_modules/,
},
]
},
plugins: [
new HtmlWebpackPlugin({
template:'./public/index.html'
}),
new ModuleFederationPlugin({
filename: "remoteEntry.js",
name: "remote",
exposes: {
"./title": "./src/title",
}
})
]
}
Remote\src\index.js
import("./bootstrap");
Remote\src\bootstrap.js
import title from "./title";
console.log(title);
Remote\src\title.js
module.exports = 'title';
Host\webpack.config.js
let path = require("path");
let webpack = require("webpack");
let HtmlWebpackPlugin = require("html-webpack-plugin");
const ModuleFederationPlugin = require("webpack/lib/container/ModuleFederationPlugin");
module.exports = {
mode: "development",
entry: "./src/index.js",
devtool:false,
output: {
publicPath: "http://localhost:8081/",
hotUpdateGlobal:'webpackHotUpdate'
},
devServer: {
port: 8000
},
module: {
rules: [
{
test: /\.jsx?$/,
use: {
loader: 'babel-loader',
options: {
presets: ["@babel/preset-react"]
},
},
exclude: /node_modules/,
},
]
},
plugins: [
new HtmlWebpackPlugin({
template: './public/index.html'
}),
new ModuleFederationPlugin({
filename: "remoteEntry.js",
name: "host",
remotes: {
remote: "remoteVar@http://localhost:3000/remoteEntry.js"
}
})
]
}
Host\src\index.js
import("./bootstrap");
Host\src\bootstrap.js
import("remote/title").then(result=>{
console.log(result.default);
});
Remote\dist\src_title_js.js
(self["webpackChunkRemote"] = self["webpackChunkRemote"] || []).push([["src_title_js"], {
"./src/title.js":
((module) => {
module.exports = 'title';
})
}]);
Remote\dist\src_bootstrap_js.js
(self["webpackChunkRemote"] = self["webpackChunkRemote"] || []).push([["src_bootstrap_js"], {
"./src/bootstrap.js":
((module, exports, require) => {
require.r(exports);
var title = require("./src/title.js");
var title_default = require.n(title);
console.log((title_default()));
}),
"./src/title.js":
((module) => {
module.exports = 'title';
})
}]);
Remote\dist\remoteEntry.js
window.remote =
(() => {
var modules = ({
"webpack/container/entry/remote":
((module, exports, require) => {
var moduleMap = {
"./title": () => {
return require.e("src_title_js").then(() => () => require("./src/title.js"));
}
};
var get = (module) => {
return moduleMap[module]();
};
var init = () => {
return Promise.resolve();
};
require.d(exports, {
get: () => get,
init: () => init
});
})
});
var cache = {};
function require(moduleId) {
if (cache[moduleId]) {
return cache[moduleId].exports;
}
var module = cache[moduleId] = {
exports: {}
};
modules[moduleId](module, module.exports, require);
return module.exports;
}
require.m = modules;
require.d = (exports, definition) => {
for (var key in definition) {
Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
}
};
require.f = {};
require.e = (chunkId) => {
return Promise.all(Object.keys(require.f).reduce((promises, key) => {
require.f[key](chunkId, promises);
return promises;
}, []));
};
require.u = (chunkId) => {
return "" + chunkId + ".js";
};
require.o = (obj, prop) => Object.prototype.hasOwnProperty.call(obj, prop)
require.l = (url) => {
var script = document.createElement('script');
script.src = url;
document.head.appendChild(script);
};
require.p = "http://localhost:8080/";
var installedChunks = {
"remote": 0
};
require.f.j = (chunkId, promises) => {
var installedChunkData = installedChunks[chunkId];
if (installedChunkData !== 0) {
if (installedChunkData) {
promises.push(installedChunkData[2]);
} else {
var promise = new Promise((resolve, reject) => {
installedChunkData = installedChunks[chunkId] = [resolve, reject];
});
promises.push(installedChunkData[2] = promise);
var url = require.p + require.u(chunkId);
require.l(url);
}
}
};
var webpackJsonpCallback = (parentChunkLoadingFunction,data) => {
var [chunkIds, moreModules] = data;
var moduleId, chunkId, i = 0, resolves = [];
for (; i < chunkIds.length; i++) {
chunkId = chunkIds[i];
if (installedChunks[chunkId]) {
resolves.push(installedChunks[chunkId][0]);
}
installedChunks[chunkId] = 0;
}
for (moduleId in moreModules) {
require.m[moduleId] = moreModules[moduleId];
}
if (parentChunkLoadingFunction) parentChunkLoadingFunction(data);
while (resolves.length) {
resolves.shift()();
}
}
var chunkLoadingGlobal = self["webpackChunkRemote"] = self["webpackChunkRemote"] || [];
chunkLoadingGlobal.forEach(webpackJsonpCallback.bind(null, 0));
chunkLoadingGlobal.push = webpackJsonpCallback.bind(null, chunkLoadingGlobal.push.bind(chunkLoadingGlobal));
return require("webpack/container/entry/remote");
})();
Remote\dist\main.js
(() => {
var modules = ({});
var cache = {};
function require(moduleId) {
if (cache[moduleId]) {
return cache[moduleId].exports;
}
var module = cache[moduleId] = {
exports: {}
};
modules[moduleId](module, module.exports, require);
return module.exports;
}
require.m = modules;
require.n = (module) => {
var getter = module && module.__esModule ?
() => module['default'] :
() => module;
require.d(getter, { a: getter });
return getter;
};
require.d = (exports, definition) => {
for (var key in definition) {
Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
}
};
require.f = {};
require.e = (chunkId) => {
return Promise.all(Object.keys(require.f).reduce((promises, key) => {
require.f[key](chunkId, promises);
return promises;
}, []));
};
require.u = (chunkId) => {
return "" + chunkId + ".js";
};
require.l = (url) => {
var script = document.createElement('script');
script.src = url;
document.head.appendChild(script);
};
require.r = (exports) => {
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
Object.defineProperty(exports, '__esModule', { value: true });
};
require.p = "http://localhost:8080/";
var installedChunks = {
"main": 0
};
require.f.j = (chunkId, promises) => {
var installedChunkData = installedChunks[chunkId];
if (installedChunkData !== 0) {
if (installedChunkData) {
promises.push(installedChunkData[2]);
} else {
var promise = new Promise((resolve, reject) => {
installedChunkData = installedChunks[chunkId] = [resolve, reject];
});
promises.push(installedChunkData[2] = promise);
var url = require.p + require.u(chunkId);
require.l(url);
}
}
};
var webpackJsonpCallback = (parentChunkLoadingFunction,data) => {
var [chunkIds, moreModules] = data;
var moduleId, chunkId, i = 0, resolves = [];
for (; i < chunkIds.length; i++) {
chunkId = chunkIds[i];
if (installedChunks[chunkId]) {
resolves.push(installedChunks[chunkId][0]);
}
installedChunks[chunkId] = 0;
}
for (moduleId in moreModules) {
require.m[moduleId] = moreModules[moduleId];
}
if (parentChunkLoadingFunction) parentChunkLoadingFunction(data);
while (resolves.length) {
resolves.shift()();
}
}
var chunkLoadingGlobal = self["webpackChunkRemote"] = self["webpackChunkRemote"] || [];
chunkLoadingGlobal.forEach(webpackJsonpCallback.bind(null, 0));
chunkLoadingGlobal.push = webpackJsonpCallback.bind(null, chunkLoadingGlobal.push.bind(chunkLoadingGlobal));
require.e("src_bootstrap_js").then(require.bind(require, "./src/bootstrap.js"));
})();
Remote\dist\index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="root"></div>
<script src="http://localhost:8080/main.js"></script>
<script src="http://localhost:8080/remoteEntry.js"></script></body>
</html>
Host\dist\src_bootstrap_js.js
(self["webpackChunkHost"] = self["webpackChunkHost"] || []).push([["src_bootstrap_js"], {
"./src/bootstrap.js":
((module, exports, require) => {
require.e("webpack_container_remote_remote_title").then(require.t.bind(require, "webpack/container/remote/remote/title")).then(result => {
console.log(result.default);
});
})
}]);
Host\dist\main.js
(() => {
var modules = ({
"webpack/container/reference/remote":
((module, exports, require) => {
module.exports = new Promise((resolve) => {
require.l("http://localhost:8080/remoteEntry.js",resolve);
}).then(() => remote);
})
});
var cache = {};
function require(moduleId) {
if (cache[moduleId]) {
return cache[moduleId].exports;
}
var module = cache[moduleId] = {
exports: {}
};
modules[moduleId](module, module.exports, require);
return module.exports;
}
require.m = modules;
require.t = function (value) {
value = this(value);
var ns = Object.create(null);
require.r(ns);
var def = { 'default': () => value };
require.d(ns, def);
return ns;
};
require.d = (exports, definition) => {
for (var key in definition) {
Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
}
};
require.f = {};
require.e = (chunkId) => {
return Promise.all(Object.keys(require.f).reduce((promises, key) => {
require.f[key](chunkId, promises);
return promises;
}, []));
};
require.u = (chunkId) => {
return "" + chunkId + ".js";
};
require.l = (url, done) => {
var script = document.createElement('script');
script.src = url;
script.onload = done
document.head.appendChild(script);
};
require.r = (exports) => {
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
Object.defineProperty(exports, '__esModule', { value: true });
};
var chunkMapping = {
"webpack_container_remote_remote_title": [
"webpack/container/remote/remote/title"
]
};
var idToExternalAndNameMapping = {
"webpack/container/remote/remote/title": [
"./title",
"webpack/container/reference/remote"
]
};
require.f.remotes = (chunkId,promises) => {
chunkMapping[chunkId] && chunkMapping[chunkId].forEach((id) => {
var [remoteModuleName,moduleId] = idToExternalAndNameMapping[id];
let promise = require(moduleId).then(external=>{
return external.init().then(()=>{
return external.get(remoteModuleName).then((factory)=>{
return modules[id] = (module) => {
module.exports = factory();
}
});
});
})
promises.push(promise);
});
}
require.p = "http://localhost:8081/";
var installedChunks = {
"main": 0
};
require.f.j = (chunkId, promises) => {
var installedChunkData;
if ("src_bootstrap_js" == chunkId) {
var promise = new Promise((resolve, reject) => {
installedChunkData = installedChunks[chunkId] = [resolve, reject];
});
promises.push(installedChunkData[2] = promise);
var url = require.p + require.u(chunkId);
require.l(url);
} else {
installedChunks[chunkId] = 0;
}
};
var webpackJsonpCallback = (data) => {
var [chunkIds, moreModules] = data;
var moduleId, chunkId, i = 0, resolves = [];
for (; i < chunkIds.length; i++) {
chunkId = chunkIds[i];
if (installedChunks[chunkId]) {
resolves.push(installedChunks[chunkId][0]);
}
installedChunks[chunkId] = 0;
}
for (moduleId in moreModules) {
require.m[moduleId] = moreModules[moduleId];
}
while (resolves.length) {
resolves.shift()();
}
}
var chunkLoadingGlobal = self["webpackChunkHost"] = self["webpackChunkHost"] || [];
chunkLoadingGlobal.push = webpackJsonpCallback;
require.e("src_bootstrap_js").then(require.t.bind(require, "./src/bootstrap.js"));
})();
Host\dist\index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="root"></div>
<script src="http://localhost:8081/main.js"></script>
</body>
</html>