欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Single-Spa 实践-- 拆分子应用不同目录

程序员文章站 2022-03-03 09:40:41
Single-Spa 实践(下)-- 拆分子应用不同目录在上篇中讲到了,在同一个目录下创建主应用以及子应用,但是这样的话其实还是感觉像一个大应用,并且别的模块在维护的时候还需要把整个项目 clone 下来,感觉还是欠缺了点什么。在这篇中大致上还是基于上看的结构,接着把上面的结构完全拆开来,拆分到单独的 repo,可以分为如下几个结构:1. 根(主)应用: root-config2. 子应用1: app13. 子应用2: app2接着一步步来Step 1把 app1 和 app2 从 mi...

Single-Spa 实践(下)-- 拆分子应用不同目录

在上篇中讲到了,在同一个目录下创建主应用以及子应用,但是这样的话其实还是感觉像一个大应用,并且别的模块在维护的时候还需要把整个项目 clone 下来,感觉还是欠缺了点什么。

在这篇中大致上还是基于上看的结构,接着把上面的结构完全拆开来,拆分到单独的 repo,可以分为如下几个结构:
1. 根(主)应用: root-config
2. 子应用1: app1
3. 子应用2: app2

接着一步步来

Step 1

把 app1 和 app2 从 micro-front 文件下拆分出来,与 micro-front 同级,基本需要包含如下的文件

|—— micro-front
	|——— index.ejs // 页面
	|——— package.json 
	|——— webpack.config.config
	|——— single-spa.config.js // 主应用的的 single-spa 配置
|—— app1
	|——— src
		|——— App.js // 子应用
		|——— react-mf-app1.js // 子应用的 single-spa 配置
		|——— set-public-path.js // 暴露子应用
	|——— package.json
	|——— webpack.config.config
|—— app2
	|——— src
		|——— App.js
		|——— react-mf-app2.js
		|——— set-public-path.js
	|——— package.json
	|——— webpack.config.config

Step 2

修改 mirco-front 的 webpack 配置

const path = require("path");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");

module.exports = () => {
    const result = {
        entry: path.resolve(__dirname, "./single-spa.config"),
        output: {
            filename: "single-spa.config.js",
            libraryTarget: "system",
            path: path.resolve(__dirname, "dist"),
        },
        devtool: "sourcemap",
        module: {
            rules: [
                { parser: { system: false } },
                {
                    test: /\.js$/,
                    exclude: /node_modules/,
                    use: [{ loader: "babel-loader" }],
                },
            ],
        },
        devServer: {
            historyApiFallback: true,
            disableHostCheck: true,
            headers: {
                "Access-Control-Allow-Origin": "*",
            },
            https: true,
        },
        plugins: [
            new HtmlWebpackPlugin({
                template: "./index.ejs",
            }),
            new CleanWebpackPlugin(),
        ],
        externals: ["single-spa", /^@react-mf\/.+$/],
    };

    return result;
};

修改 index.ejs

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>React Microfrontends</title>
  <meta name="importmap-type" content="systemjs-importmap" />
  <script type="systemjs-importmap">
    {
      "imports": {
        "@react-mf/root-config": "//localhost:9000/single-spa.config.js"
      }
    }
  </script>
  <script src="https://cdn.jsdelivr.net/npm/import-map-overrides@2.1.0/dist/import-map-overrides.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/systemjs@6.7.1/dist/system.min.js"></script>
  <template id="single-spa-layout">
    <single-spa-router>
      <div class="main-content mt-16">
        <route path="app1">
          <application name="@react-mf/app1"></application>
        </route>
        <route path="app2">
          <application name="@react-mf/app2"></application>
        </route>
        <route default>
          <h1 class="flex flex-row justify-center p-16">
            <p class="max-w-md">This example project shows independently built and deployed microfrontends that use React and single-spa. Each nav link above takes you to a different microfrontend.</p>
          </h1>
        </route>
      </div>
    </single-spa-router>
  </template>
</head>
<body>
  <a href="/app1">app1</a>
  <br>
  <a href="/app2">app2</a>
  <script>
    System.import('@react-mf/root-config');
  </script>
</body>
</html>

Single-sap.config.js

import {
    constructRoutes,
    constructLayoutEngine,
    constructApplications,
} from "single-spa-layout";
import { registerApplication, start } from "single-spa";
console.log(registerApplication);

const routes = constructRoutes(document.querySelector("#single-spa-layout"), {
    loaders: {
        topNav: "<h1>Loading topnav</h1>",
    },
    errors: {
        topNav: "<h1>Failed to load topNav</h1>",
    },
});

const applications = constructApplications({
    routes,
    loadApp: ({ name }) => System.import(name),
});

const layoutEngine = constructLayoutEngine({
    routes,
    applications,
    active: false,
});

applications.forEach(registerApplication);

layoutEngine.activate();
start();

到这里,主应用的改造就算完成了,你可以单独运行一下主应用,切换到子应用路由,页面控制台会报未找到子应用的错误,是因为子应用没有改造完且没有运行,所以是找不到

Step 3

改造完主应用接下来来改造一下子应用
首先改造 webpack.config.js,因为子应用是我们直接通过 react 的 CRA 脚手架创建的,懒得把内置的配置暴露出来,所以自己就增加一个 webpack 配置,同样的在 package.json 中增加一条命令
webpack.config.js

const webpackMerge = require("webpack-merge");
const singleSpaDefaults = require("webpack-config-single-spa-react");
const HtmlWebpackPlugin = require("html-webpack-plugin");

module.exports = (webpackConfigEnv = {}) => {
		// TODO: 这部分具体干嘛的还不怎么清楚,感觉像是对外暴露这个包名的
    const defaultConfig = singleSpaDefaults({
        orgName: "react-mf",
        projectName: "app1",
        webpackConfigEnv,
    });

    const config = webpackMerge.smart(defaultConfig, {
        devServer: {
            historyApiFallback: true,
            https: true,
        },
        plugins: [
            new HtmlWebpackPlugin(),
        ],
        resolve: {
            extensions: [".js", ".jsx", ".ts", ".tsx"],
        },
        externals: [/^rxjs\/?.*$/],
    });
    return config;
};

Package.json 增加一条 script

"startDev": "webpack-dev-server --port 9001"

React-mf-app1.js

const webpackMerge = require("webpack-merge");
const singleSpaDefaults = require("webpack-config-single-spa-react");
const HtmlWebpackPlugin = require("html-webpack-plugin");

module.exports = (webpackConfigEnv = {}) => {
    const defaultConfig = singleSpaDefaults({
        orgName: "react-mf",
        projectName: "app1",
        webpackConfigEnv,
    });

    const config = webpackMerge.smart(defaultConfig, {
        // customizations go here
        devServer: {
            historyApiFallback: true,
            https: true,
        },
        plugins: [
            new HtmlWebpackPlugin(),
        ],
        resolve: {
            extensions: [".js", ".jsx", ".ts", ".tsx"],
        },
        externals: [/^rxjs\/?.*$/],
    });

    return config;
};

Set-public-path.js

import { setPublicPath } from "systemjs-webpack-interop";
setPublicPath("@react-mf/app1");

自此,子应用的也算是改造完了,app2 参考着 app1 改造就行。

Step 4

运行,配置 importmap ,分别启动主应用和子应用
⚠️ 这里使用的是 https ,所以注意自己的 url
运行起来后,我们可以看到我们主应用的页面,切换的子应用的路由控制台会报错,这是因为我们还是实际配置 importmap
在这之前先推荐安装一下 single-spa 的一个 chrome 扩展 single-spa-inspector ,这个扩展可以在我们运行 single-spa 的微服务应用的时候帮助我进行一些配置,以及做一个子应用的切换
Single-Spa 实践-- 拆分子应用不同目录

安装了扩展之后我们的 Chrome 控制台就会多这么一个 tab ,在这个 tab 下就能看到我们的子应用有哪些,初始 import override 那是没有配置的,这里根据我们自己的子应用做一个配置就行,上面就是我的配置,到这里算是完成了,我们切换路由就可以看到对应的子应用了。

本文地址:https://blog.csdn.net/F_Felix/article/details/110585819