前言
- weback的模块联邦原理和import相似,也是做成了预留的promise坑位,通过webpackjsonp加载,获取变成发请求获取而已。
- 下面来实战一下。
安装
- webpack最新做了个init脚手架,首先安装以下包:
yarn add @webpack-cli/init webpack-cli webpack webpack-dev-server -D
- 初始化脚手架:
npx webpack-cli init
- 注意!如果总是提示你找不到webpack,但你已经安装,很可能是因为你没有装webpack-cli。
- 经过一系列选项即可生成项目
- 编写执行脚本:
"start": "webpack serve",
"build": "webpack"
-
我一开始以为start是webpack-dev-server,现在是webpack serve启动,且webpack-dev-server无法独立启动并且必须安装。
-
我们模拟2个团队,团队A开发组件部署到线上给团队B使用,团队B使用远程组件。
TeamA
- 首先做teamA的设置,新建webpack.config.js:
const path = require("path");
const webpack = require("webpack");
const ModuleFederationPlugin = require("webpack/lib/container/ModuleFederationPlugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");
module.exports = {
mode: "development",
entry: "./src/index.ts",
output: {
publicPath: "http://localhost:3000/", //部署后的资源地址
},
experiments: {
topLevelAwait: true, // 试验性质顶级作用域允许await
},
plugins: [
new webpack.ProgressPlugin(),
new HtmlWebpackPlugin({
template: "index.html",
}),
// name string 必传值,即输出的模块名,被远程引用时路径为${name}/${expose}
// library object 声明全局变量的方式,name为umd的name
// filename string 构建输出的文件名
// remotes object 远程引用的应用名及其别名的映射,使用时以key值作为name
// exposes object 被远程引用时可暴露的资源路径及其别名
// shared object 与其他应用之间可以共享的第三方依赖,使你的代码中不用重复加载同一份依赖
new ModuleFederationPlugin({
filename: "teamA.js",
name: "teamA",
exposes: {
"./componentA": "./src/componentA", // 这个键名是拿到teamA.js后用o函数取的位置,因为远程调用是import(teamA/XXX),切了路径所以是个路径
"./componentB": "./src/componentB",
},
}),
],
module: {
rules: [
{
test: /\.(ts|tsx)$/,
loader: "ts-loader",
include: [path.resolve(__dirname, "src")],
exclude: [/node_modules/],
},
{
test: /.(less|css)$/,
use: [
{
loader: "style-loader",
},
{
loader: "css-loader",
options: {
sourceMap: true,
},
},
{
loader: "less-loader",
options: {
sourceMap: true,
},
},
],
},
],
},
resolve: {
extensions: [".tsx", ".ts", ".js"],
},
devServer: {
open: true,
host: "localhost",
port: 3000, //本地调试
},
};
- 我们会导出2个组件,componentA与componentB,自己对应位置新建a和b:
function AAA() {
console.log("i am componentA");
}
export default AAA;
function BBB() {
console.log("i am componentB");
}
export default BBB;
- teamA部分完成,启动teamA项目
teamB
- 同理,teamB也编写webpack.config.js:
/*
* @Author: yehuozhili
* @Date: 2021-03-05 13:03:13
* @LastEditors: yehuozhili
* @LastEditTime: 2021-03-06 16:16:04
*/
const path = require("path");
const webpack = require("webpack");
const ModuleFederationPlugin = require("webpack/lib/container/ModuleFederationPlugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");
module.exports = {
mode: "development",
entry: "./src/index.ts",
output: {
publicPath: "http://localhost:3001/", //部署后的资源地址
},
devServer: {
open: true,
host: "localhost",
port: 3001, //本地调试
},
experiments: {
topLevelAwait: true, // 试验性质顶级作用域允许await
},
plugins: [
new webpack.ProgressPlugin(),
new HtmlWebpackPlugin({
template: "index.html",
}),
// name string 必传值,即输出的模块名,被远程引用时路径为${name}/${expose}
// library object 声明全局变量的方式,name为umd的name
// filename string 构建输出的文件名
// remotes object 远程引用的应用名及其别名的映射,使用时以key值作为name
// exposes object 被远程引用时可暴露的资源路径及其别名
// shared object 与其他应用之间可以共享的第三方依赖,使你的代码中不用重复加载同一份依赖
new ModuleFederationPlugin({
filename: "teamB.js",
name: "teamB",
remotes: {
teamA: "teamA@http://localhost:3000/teamA.js",
},
}),
],
module: {
rules: [
{
test: /\.(ts|tsx)$/,
loader: "ts-loader",
include: [path.resolve(__dirname, "src")],
exclude: [/node_modules/],
},
{
test: /.(less|css)$/,
use: [
{
loader: "style-loader",
},
{
loader: "css-loader",
options: {
sourceMap: true,
},
},
{
loader: "less-loader",
options: {
sourceMap: true,
},
},
],
},
],
},
resolve: {
extensions: [".tsx", ".ts", ".js"],
},
};
- 我们使用remote加载teamA的资源。
- 在teamB的index中,使用webpackimport导入:
/*
* @Author: yehuozhili
* @Date: 2021-03-05 18:04:47
* @LastEditors: yehuozhili
* @LastEditTime: 2021-03-06 17:25:56
*/
//@ts-ignore
import("teamA/componentA").then((res) => {
const componentA = res.default;
componentA();
});
//@ts-ignore
import("teamA/componentB").then((res) => {
const componentA = res.default;
componentA();
});
- 即可在teamB中获取到teamA的资源。