跳到主要内容

开发与适配

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);