开发与适配
CloudBase CMS 基于 qiankun 实现了微应用加载能力,已有的项目经过简单的配置修改,即可适配为微应用。
同时,我们也提供了 Vue 和 React 的微应用开发模版,提供快速开发使用,你可以通过 CloudBase CLI 直接下载模版。
# 新建 React 微应用项目
tcb new react-app cms-microapp-react
# 新建 Vue 微应用项目
tcb new vue-app cms-microapp-vue
React 项目适配
1. 路由适配
设置 hash
模式路由的 basename
为 /project/microapp/${microAppID}/
,其中 ${microApp}
为你创建的微应用的 AppID
目前,CloudBase CMS 仅支持 hash
模式的路由
<HashRouter basename={`/project/microapp/${microAppID}/`}>
2. 入口修改
修改 index.js
入口文件,为了避免根 id #root 与其他的 DOM 冲突,需要限制查找范围
import React from "react";
import ReactDOM from "react-dom";
import App from "./App";
function render(props) {
const { container } = props;
ReactDOM.render(
<App />,
container ? container.querySelector("#root") : document.querySelector("#root")
);
}
if (!window.__POWERED_BY_QIANKUN__) {
render({});
}
export async function bootstrap() {
console.log("[react16] react app bootstraped");
}
export async function mount(props) {
console.log("[react16] props from main framework", props);
render(props);
}
export async function unmount(props) {
const { container } = props;
ReactDOM.unmountComponentAtNode(
container ? container.querySelector("#root") : document.querySelector("#root")
);
}
3. 构建配置修改
修改 Webpack 配置,需要修改 output
配置以及 publicPath
为 /cloudbase-cms/apps/${microAppID}/
,其中 ${microApp}
为你创建的微应用的 AppID
// 微应用 APPID
const microAppID = "reactApp";
module.exports = {
webpack: (config) => {
// 微应用的包名,这里与主应用中注册的微应用名称一致
config.output.library = `${microAppID}`;
// 将你的 library 暴露为所有的模块定义下都可运行的方式
config.output.libraryTarget = "umd";
// 按需加载相关,设置为 webpackJsonp_react-project 即可
config.output.jsonpFunction = `webpackJsonp_${microAppID}`;
// 修改 publicPath
if (process.env.NODE_ENV === "production") {
config.output.publicPath = `/cloudbase-cms/apps/${microAppID}/`;
}
return config;
}
};
Vue 项目适配
以 Vue CLI 生成的 Vue 2.x 项目为例
1. 入口文件修改
入口文件 main.js
修改,为了避免根 id #app 与其他的 DOM 冲突,需要限制查找范围
import Vue from "vue";
import App from "./App.vue";
Vue.config.productionTip = false;
let instance = null;
const isDev = process.env.NODE_ENV === "development";
function render(props = {}) {
const { container } = props;
instance = new Vue({
render: (h) => h(App)
}).$mount(container ? container.querySelector("#app") : "#app");
}
// 独立运行时
if (isDev || !window.__POWERED_BY_QIANKUN__) {
render();
}
export async function bootstrap() {
console.log("[vue] vue app bootstraped");
}
export async function mount(props) {
console.log("[vue] props from main framework", props);
render(props);
}
export async function unmount() {
instance.$destroy();
instance.$el.innerHTML = "";
instance = null;
}
2. 构建配置修改
打包配置修改(vue.config.js
),修改 output
配置,以及设置publicPath
为 /cloudbase-cms/apps/${microAppID}/
,其中 ${microApp}
为你创建的微应用的 AppID
// CMS 微应用 APPID
const microAppID = "vueApp";
const isDev = process.env.NODE_ENV === "development";
module.exports = {
publicPath: isDev ? "/" : `/cloudbase-cms/apps/${microAppID}/`,
devServer: {
headers: {
"Access-Control-Allow-Origin": "*"
}
},
configureWebpack: {
output: {
library: `${microAppID}`,
libraryTarget: "umd", // 把微应用打包成 umd 库格式
jsonpFunction: `webpackJsonp_${microAppID}`
}
}
};
注意,由于 Vue Hash 模式的问题,目前 CloudBase CMS 微应用还无法支持 Vue 路由的使用
非 Webpack 构建的微应用
一些非 webpack 构建的项目,例如 jQuery 项目、jsp 项目,都可以按照这个处理。
接入之前请确保你的项目里的图片、音视频等资源能正常加载,如果这些资源的地址都是完整路径(例如 https://docs.cloudbase.net/logo.png
),则没问题。如果都是相对路径,需要先将这些资源上传到服务器,使用完整路径。
接入非常简单,只需要额外声明一个 script,用于 export 相对应的 lifecycles。例如:
1. 声明 entry 入口
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Purehtml Example</title>
</head>
<body>
<div>Purehtml Example</div>
</body>
<script src="//yourhost/entry.js" entry></script>
</html>
2. 在 entry.js
里声明 lifecycles
const render = ($) => {
$("#purehtml-container").html("Hello, render with jQuery");
return Promise.resolve();
};
((global) => {
global["purehtml"] = {
bootstrap: () => {
console.log("purehtml bootstrap");
return Promise.resolve();
},
mount: () => {
console.log("purehtml mount");
return render($);
},
unmount: () => {
console.log("purehtml unmount");
return Promise.resolve();
}
};
})(window);