>[success] # 简单上手 -- single-spa
~~~
1.在 'single-spa' 方案中,应用被分为两类:基座应用和子应用。基座应用是整体父级,内部子应用在基座应用中
和单页应用的实现原理类似,'single-spa' 会在基座应用中维护一个路由注册表,每个路由对应一个子应用。基座应用启
动以后,当我们切换路由时,如果是一个新的子应用,会动态获取子应用的 js 脚本,然后执行脚本并渲染出相应的页
面;如果是一个已经访问过的子应用,那么就会从缓存中获取已经缓存的子应用,激活子应用并渲染出对应的页面。
~~~
>[info] ## 创建过程
~~~
1.'npm install create-single-spa -g' -- 安装sigle-spa 脚手架
2.'create-single-spa 基座项目文件名' -- 举个例子'create-single-spa c' 自动创建一个c 文件夹内部是生成的,如果不是
全局安装需要通过'npx' 执行脚本命令,基座代码,当然执行'create-single-spa' 会出现一下选择
2.1. 应用文件夹填写 container
2.2. 应用选择 single-spa root config
2.3. 组织名称填写 study 组织名称可以理解为团队名称,微前端架构允许多团队共同开发应用,组织名称可以标识应用
由哪个团队开发。应用名称的命名规则为 @组织名称/应用名称 ,比如 @study/todos
3.'create-single-spa 文件名' -- 这时候选择.'single-spa-application / parcel':微前端架构中的微应用,可以使用 vue、
react、angular 等框架
注关于几个选项详细解释:
'single-spa root config':创建微前端容器应用。
'single-spa applications':为一组特定路由渲染组件的微前端。
'single-spa parcels': 不受路由控制,渲染组件的微前端。
'utility modules': 非渲染组件,用于暴露共享javascript逻辑的微前端。
~~~
![](https://img.kancloud.cn/2c/7c/2c7c6fb016bec291b8148bf85e15b1f8_1057x175.png)
>[info] ## 生成的基座文件介绍
~~~js
1.生成的目录结构
base-root
├─ src
│ ├─ index.ejs
│ └─ study-root-config.js
├─ package-lock.json
├─ package.json
└─ webpack.config.js
2.创建基座后发现自动生成以下几个关键文件
2.1.'index.ejs' -- 所有微前端应用共享的根 HTML 页面,主要利用systemjs 实现'importmap' 做到按需导入
2.2.'*-root-config.js' -- 这是注册微前端应用的配置文件
2.3.'webpack.config.js' -- webpack配置文件
~~~
>[danger] ##### webpack.config.js
~~~
1.这个文件主要导入了 "webpack-config-single-spa",一个可共享的、可定制的 webpack 配置,用于实用程序模块
和 single-spa 应用程序,就是已经帮忙做好的关于'single-spa的webpack 文件'
2.对下面'disableHtmlGeneration' 变量做一个说明,默认为false,禁用html-webpack-plugin (and
standalone-single-spa-webpack-plugin)。下面案例设置为true 是因为自己配置了'html-webpack-plugin'
~~~
~~~
const { merge } = require("webpack-merge");
const singleSpaDefaults = require("webpack-config-single-spa");
const HtmlWebpackPlugin = require("html-webpack-plugin");
module.exports = (webpackConfigEnv, argv) => {
const orgName = "study";
const defaultConfig = singleSpaDefaults({
orgName,
projectName: "root-config",
webpackConfigEnv,
argv,
disableHtmlGeneration: true,
});
return merge(defaultConfig, {
// modify the webpack config however you'd like to by adding to this object
plugins: [
new HtmlWebpackPlugin({
inject: false,
template: "src/index.ejs",
// 模版需要的参数,这里也就是为什么在'index.ejs' 会看到'isLocal' 变量名
templateParameters: {
isLocal: webpackConfigEnv && webpackConfigEnv.isLocal,
orgName,
},
}),
],
});
};
~~~
[官方介绍](https://single-spa.js.org/docs/create-single-spa/#create-single-spa)
>[danger] ##### study-root-config.js -- 文件
~~~
1.创建完基座后会出现一个'study-root-config.js' 文件,这是注册微前端应用的配置文件,可以理解成路由文件
不过这个路由控制的是对应微前端展现对应项目
2.这个文件的名字来源,其实来自'webpack.config.js'文件中的'webpack-config-single-spa'配置
中,也就是其对webpack 的入口文件命名,点开'webpack-config-single-spa'就可以看到。
entry: path.resolve(
process.cwd(),
`src/${opts.orgName}-${opts.projectName}`
),
其中打包入口地址可以看到是'orgName' 和'projectName' 拼接得到的,这两个属性不难发现其实
在'webpack.config.js' 中设置的。到此这里变明白了'study-root-config.js'文件名字是如何生成的
~~~
~~~
import { registerApplication, start } from "single-spa";
/*
注册微前端应用
1.name: 字符串类型, 微前端应用名称 "@组织名称/应用名称"
2.app: 函数类型, 返回 Promise, 通过 systemjs 引用打包好的微前端应用模块代码 (umd)
3.activeWhen: 路由匹配时激活应用
*/
registerApplication({
name: "@study/root-config",
app: () =>
System.import(
"https://unpkg.com/single-spa-welcome/dist/single-spa-welcome.js"
),
activeWhen: ["/react"],
});
// start 方法必须在 single spa 的配置文件中调用
// 在调用 start 之前, 应用会被加载, 但不会初始化, 挂载或卸载.
start({
// 是否可以通过 history.pushState() 和 history.replaceState() 更改触发 single-spa 路由
// true 不允许 false 允许
urlRerouteOnly: true,
});
~~~
>[danger] ##### index.ejs
~~~
1.所有微前端应用共享的根 HTML 页面,主要利用systemjs 实现'importmap' 做到按需导入
~~~
~~~html
<!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>Root Config</title>
<!-- async/await 解析包-->
<script src="https://cdn.jsdelivr.net/npm/regenerator-runtime@0.13.7/runtime.min.js"></script>
<!--
This CSP allows any SSL-enabled host and for arbitrary eval(), but you should limit these directives further to increase your app's security.
Learn more about CSP policies at https://content-security-policy.com/#directive
-->
<meta
http-equiv="Content-Security-Policy"
content="default-src 'self' https: localhost:*; script-src 'unsafe-inline' 'unsafe-eval' https: localhost:*; connect-src https: localhost:* ws://localhost:*; style-src 'unsafe-inline' https:; object-src 'none';"
/>
<meta name="importmap-type" content="systemjs-importmap" />
<!-- 当加载基座时,需要导入single-spa -->
<script type="systemjs-importmap">
{
"imports": {
"single-spa": "https://cdn.jsdelivr.net/npm/single-spa@5.9.0/lib/system/single-spa.min.js"
}
}
</script>
<link
rel="preload"
href="https://cdn.jsdelivr.net/npm/single-spa@5.9.0/lib/system/single-spa.min.js"
as="script"
/>
<!-- Add your organization's prod import map URL to this script's src -->
<!-- <script type="systemjs-importmap" src="/importmap.json"></script> -->
<% if (isLocal) { %>
<script type="systemjs-importmap">
{
"imports": {
"@study/root-config": "//localhost:9000/study-root-config.js"
}
}
</script>
<% } %>
<!-- 需要systemJS模块化和amd解析 -->
<script src="https://cdn.jsdelivr.net/npm/import-map-overrides@2.2.0/dist/import-map-overrides.js"></script>
<% if (isLocal) { %>
<script src="https://cdn.jsdelivr.net/npm/systemjs@6.8.3/dist/system.js"></script>
<script src="https://cdn.jsdelivr.net/npm/systemjs@6.8.3/dist/extras/amd.js"></script>
<% } else { %>
<script src="https://cdn.jsdelivr.net/npm/systemjs@6.8.3/dist/system.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/systemjs@6.8.3/dist/extras/amd.min.js"></script>
<% } %>
</head>
<body>
<noscript> You need to enable JavaScript to run this app. </noscript>
<main></main>
<script>
// 加载基座应用
System.import('@study/root-config')
</script>
<import-map-overrides-full
show-when-local-storage="devtools"
dev-libs
></import-map-overrides-full>
</body>
</html>
~~~
* [Configuring single-spa官网对参数的介绍](https://zh-hans.single-spa.js.org/docs/configuration)
>[danger] ##### 不通过脚手架创建基座步骤
~~~
1.通过脚手架创建的基座基本已经明确了一个基座创建主要几个解析文件
1.1.'webpack-config.js'作为使用webpack打包配置文件,因此相对的主要需要的几个包'wepabck'
'webpack-cli',还用html作为模板相对的也需要' html-webpack-plugin',通过官方提供的将一些基础
配置已经配置好的'webpack-config-single-spa'
1.2.到了webpack入口文件,'src/*-*.js' 上面分析过这两个'*' 具体名字是根据.'webpack-config.js'
中'orgName' 和'projectName' 拼接得到的,也可以覆盖自定义,入口文件主要是为了作为
各个路由调用微前端的映射文件这里需要"single-spa" 这个包来帮助
2.分析所需要的包和各个文件之间的关系,如果没有脚手架,想自己生成基座文件相对的第一步
安装上面提到的文件,按照对应规则创建文件即可
~~~
>[info] ## 创建微应用 -- 子应用的构建
~~~
1.已经明确了'single-spa' 基座应用是类似路由映射,当我们创建好了子应用的时候,需要做的
是在基座应用的入口做好路由映射举个例子和基座联动,注册微应用在'*-*-config.js' 中
registerApplication({
name: "@study/vue",
app: () => System.import("@study/vue-app"),
activeWhen: location => location.pathname.startsWith('/vue'),
});
下一步需要在'index.ejs' 声明打包后的文件,例如下面vue项目启动的端口是3000,并且vuecli打包后的默认文件都是
在'js/app.js'
<% if (isLocal) { %>
<script type="systemjs-importmap">
{
"imports": {
"@study/root-config": "//localhost:9000/study-root-config.js",
"@study/vue-app":"//localhost:3000/js/app.js"
}
}
</script>
<% } %>
2.'single-spa' 微应用的解决实现方案,对主流框架依旧提供了对应的封装配置包例如
'webpack-config-single-spa-react'、'single-spa-vue' ,只要按照规则依旧可以对进行配置,
非主流框架可以按照下面步骤来做整体和基座的解决思路类似
3.子应用对应的需要对外暴露'bootstrap' 、'mount'、'unmount' 声明周期
4.关于'app: System.import()'中值名字,其实这个是'System.js' 导入的用法,当你将
一个包打包成'system.js'规范的时候,注册名字以spa-vue 的脚手架为例,当你通过打印
'npx vue-cli-service inspect --mode production > aa.js' 就可以发现'SystemJSPublicPathWebpackPlugin'
这里做了对应的映射,如果在细看会在'node_modules'找'vue-cli-plugin-single-spa',跟具体的配置可以发现这个名字
来源的代码如下
const packageJsonPath = api.resolve("package.json");
const { name } = require(packageJsonPath);
即也就是你注册对应项目的'package.json' 文件中的name
~~~
>[danger] ##### 非框架的微应用
~~~
1.只需要将你的webpack 配置和提供的webpack配置做合并即可
~~~
~~~js
const { merge } = require("webpack-merge")
const singleSpaDefaults = require("webpack-config-single-spa")
module.exports = () => {
const defaultConfig = singleSpaDefaults({
// 组织名称
orgName: "study",
// 项目名称
projectName: "root"
})
return merge(defaultConfig, { devServer: { port: 9001 } }) }
~~~
>[danger] ##### vue 创建的微前端主要配置 -- main.js
~~~js
import Vue from "vue";
import singleSpaVue from "single-spa-vue";
import App from "./App.vue";
import router from "./router";
import store from "./store";
Vue.config.productionTip = false;
const vueLifecycles = singleSpaVue({
Vue,
appOptions: {
render (h) {
return h(App, {
props: {
// single-spa props are available on the "this" object. Forward them to your component as needed.
// https://single-spa.js.org/docs/building-applications#lifecyle-props
// if you uncomment these, remember to add matching prop definitions for them in your App.vue file.
/*
name: this.name,
mountParcel: this.mountParcel,
singleSpa: this.singleSpa,
*/
},
});
},
router,
store,
},
});
export const bootstrap = vueLifecycles.bootstrap;
export const mount = vueLifecycles.mount;
export const unmount = vueLifecycles.unmount;
~~~
>[info] ## 总结
~~~
1.在使用就像名字应'single-spa' 做的一种单页面微前端的形式,通过一个基座,要创建一个关于子应用的路由注册
表,然后根据路由注册表使用 single-spa 提供的 registerApplication 方法注册子应用,最后在基座应用挂载完成
,执行 single-spa 提供的 start 方法即可,各个微前端子应用配合官方提供的配置,并暴露出'bootstrap'
'mount'、'unmount' 这些暴露的属性最终和基座配合控制各个微前端交互
~~~
- 工程化 -- Node
- vscode -- 插件
- vscode -- 代码片段
- 前端学会调试
- 谷歌浏览器调试技巧
- 权限验证
- 包管理工具 -- npm
- 常见的 npm ci 指令
- npm -- npm install安装包
- npm -- package.json
- npm -- 查看包版本信息
- npm - package-lock.json
- npm -- node_modules 层级
- npm -- 依赖包规则
- npm -- install 安装流程
- npx
- npm -- 发布自己的包
- 包管理工具 -- pnpm
- 模拟数据 -- Mock
- 页面渲染
- 渲染分析
- core.js && babel
- core.js -- 到底是什么
- 编译器那些术语
- 词法解析 -- tokenize
- 语法解析 -- ast
- 遍历节点 -- traverser
- 转换阶段、生成阶段略
- babel
- babel -- 初步上手之了解
- babel -- 初步上手之各种配置(preset-env)
- babel -- 初步上手之各种配置@babel/helpers
- babel -- 初步上手之各种配置@babel/runtime
- babel -- 初步上手之各种配置@babel/plugin-transform-runtime
- babel -- 初步上手之各种配置(babel-polyfills )(未来)
- babel -- 初步上手之各种配置 polyfill-service
- babel -- 初步上手之各种配置(@babel/polyfill )(过去式)
- babel -- 总结
- 各种工具
- 前端 -- 工程化
- 了解 -- Yeoman
- 使用 -- Yeoman
- 了解 -- Plop
- node cli -- 开发自己的脚手架工具
- 自动化构建工具
- Gulp
- 模块化打包工具为什么出现
- 模块化打包工具(新) -- webpack
- 简单使用 -- webpack
- 了解配置 -- webpack.config.js
- webpack -- loader 浅解
- loader -- 配置css模块解析
- loader -- 图片和字体(4.x)
- loader -- 图片和字体(5.x)
- loader -- 图片优化loader
- loader -- 配置解析js/ts
- webpack -- plugins 浅解
- eslit
- plugins -- CleanWebpackPlugin(4.x)
- plugins -- CleanWebpackPlugin(5.x)
- plugin -- HtmlWebpackPlugin
- plugin -- DefinePlugin 注入全局成员
- webapck -- 模块解析配置
- webpack -- 文件指纹了解
- webpack -- 开发环境运行构建
- webpack -- 项目环境划分
- 模块化打包工具 -- webpack
- webpack -- 打包文件是个啥
- webpack -- 基础配置项用法
- webpack4.x系列学习
- webpack -- 常见loader加载器
- webpack -- 移动端px转rem处理
- 开发一个自己loader
- webpack -- plugin插件
- webpack -- 文件指纹
- webpack -- 压缩css和html构建
- webpack -- 清里构建包
- webpack -- 复制静态文件
- webpack -- 自定义插件
- wepack -- 关于静态资源内联
- webpack -- source map 对照包
- webpack -- 环境划分构建
- webpack -- 项目构建控制台输出
- webpack -- 项目分析
- webpack -- 编译提速优护体积
- 提速 -- 编译阶段
- webpack -- 项目优化
- webpack -- DefinePlugin 注入全局成员
- webpack -- 代码分割
- webpack -- 页面资源提取
- webpack -- import按需引入
- webpack -- 摇树
- webpack -- 多页面打包
- webpack -- eslint
- webpack -- srr打包后续看
- webpack -- 构建一个自己的配置后续看
- webpack -- 打包组件和基础库
- webpack -- 源码
- webpack -- 启动都做了什么
- webpack -- cli做了什么
- webpack - 5
- 模块化打包工具 -- Rollup
- 工程化搭建代码规范
- 规范化标准--Eslint
- eslint -- 扩展配置
- eslint -- 指令
- eslint -- vscode
- eslint -- 原理
- Prettier -- 格式化代码工具
- EditorConfig -- 编辑器编码风格
- 检查提交代码是否符合检查配置
- 整体流程总结
- 微前端
- single-spa
- 简单上手 -- single-spa
- 快速理解systemjs
- single-sap 不使用systemjs
- monorepo -- 工程
- Vue -- 响应式了解
- Vue2.x -- 源码分析
- 发布订阅和观察者模式
- 简单 -- 了解响应式模型(一)
- 简单 -- 了解响应式模型(二)
- 简单 --了解虚拟DOM(一)
- 简单 --了解虚拟DOM(二)
- 简单 --了解diff算法
- 简单 --了解nextick
- Snabbdom -- 理解虚拟dom和diff算法
- Snabbdom -- h函数
- Snabbdom - Vnode 函数
- Snabbdom -- init 函数
- Snabbdom -- patch 函数
- 手写 -- 虚拟dom渲染
- Vue -- minVue
- vue3.x -- 源码分析
- 分析 -- reactivity
- 好文
- grpc -- 浏览器使用gRPC
- grcp-web -- 案例
- 待续