{"id":27248217,"url":"https://github.com/chemistwang/demo-qiankun","last_synced_at":"2025-04-10T23:08:07.298Z","repository":{"id":182764424,"uuid":"585051627","full_name":"chemistwang/demo-qiankun","owner":"chemistwang","description":"qiankun 小试","archived":false,"fork":false,"pushed_at":"2023-01-06T09:29:43.000Z","size":1264,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-04-10T23:08:04.614Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/chemistwang.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2023-01-04T07:36:32.000Z","updated_at":"2023-01-04T07:52:15.000Z","dependencies_parsed_at":"2023-07-21T10:31:15.009Z","dependency_job_id":null,"html_url":"https://github.com/chemistwang/demo-qiankun","commit_stats":null,"previous_names":["chemistwang/demo-qiankun"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chemistwang%2Fdemo-qiankun","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chemistwang%2Fdemo-qiankun/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chemistwang%2Fdemo-qiankun/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chemistwang%2Fdemo-qiankun/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/chemistwang","download_url":"https://codeload.github.com/chemistwang/demo-qiankun/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248312148,"owners_count":21082638,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-04-10T23:08:06.811Z","updated_at":"2025-04-10T23:08:07.281Z","avatar_url":"https://github.com/chemistwang.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# QIANKUN demo 小试\n\n## 前期准备\n\n1. 分别创建主应用和子应用\n\n```bash\n# 创建 base-react\nnpx create-react-app base-react\n# 创建 mini-react18\nnpx create-react-app mini-react18\n# 创建 mini-vue2\nvue create mini-vue2\n```\n\n2. 创建 `.env` 指定具体端口，方便管理\n\n| 应用         | 端口  |\n| ------------ | ----- |\n| base-react   | 11110 |\n| mini-react18 | 11111 |\n| mini-vue2    | 11112 |\n\n\u003e 说明：chrome 对于端口有部分的限制，指定非法端口号会出现 `ERR_UNSAFE_PORT`，可搜索关键词 `Google Chrome 默认非安全端口列表`\n\n## base-react\n\n### 描述\n\n- 主应用\n- 不限技术栈，只需要提供一个容器 DOM\n- 注册微应用并 start 即可\n\n### 步骤\n\n1. 安装 `qiankun`\n\n```bash\nyarn add qiankun # 或者 npm i qiankun -S\n```\n\n2. 在 `App.tsx` 中创建容器\n\n```tsx\nfunction App() {\n  return (\n    \u003cdiv className=\"App\"\u003e\n      \u003cdiv id=\"mini-react1\"\u003e\u003c/div\u003e\n      \u003cdiv id=\"mini-react2\"\u003e\u003c/div\u003e\n    \u003c/div\u003e\n  );\n}\n\nexport default App;\n```\n\n3. 在 `index.tsx` 中注册并启动\n\n```js\nimport { registerMicroApps, start } from \"qiankun\";\n\nregisterMicroApps([\n  {\n    name: \"react app 18\",\n    entry: \"//localhost:11111\",\n    container: \"#mini-react18\",\n    activeRule: \"/mini-react18\",\n  },\n  {\n    name: \"vue app 2\",\n    entry: \"//localhost:11112\",\n    container: \"#mini-vue2\",\n    activeRule: \"/mini-vue2\",\n  },\n  {\n    name: \"vue app 3\",\n    entry: \"//localhost:11113\",\n    container: \"#mini-vue3\",\n    activeRule: \"/mini-vue3\",\n  },\n]);\n// 启动 qiankun\nstart();\n```\n\n## mini-react18\n\n### 描述\n\n- 微应用 1（react18）\n\n### 步骤\n\n1. 新建 `src/public-path.js`\n\n```js\nif (window.__POWERED_BY_QIANKUN__) {\n  __webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;\n}\n```\n\n2. 新建 `src/types/index.d.ts`\n\n因为项目给予 ts 编译，需要手动指定 `POWERED_BY_QIANKUN`，否则会报错\n\n```ts\ndeclare global {\n  interface Window {\n    __POWERED_BY_QIANKUN__: string;\n  }\n}\n\nexport {};\n```\n\n3. 利用 `react-app-rewired` 重写 `webpack` 配置\n\n安装\n\n```bash\nnpm i react-app-rewired\n```\n\n根目录新建 `config-overrides.js` 文件 （文件名是规定好的）\n\n```js\nconst { name } = require(\"./package\");\n\nmodule.exports = {\n  webpack: (config) =\u003e {\n    config.output.library = `${name}-[name]`;\n    config.output.libraryTarget = \"umd\";\n    // config.output.jsonpFunction = `webpackJsonp_${name}`;\n    config.output.globalObject = \"window\";\n\n    return config;\n  },\n\n  devServer: (_) =\u003e {\n    const config = _;\n\n    config.headers = {\n      \"Access-Control-Allow-Origin\": \"*\",\n    };\n    config.historyApiFallback = true;\n    config.hot = false;\n    config.watchContentBase = false;\n    config.liveReload = false;\n\n    return config;\n  },\n};\n```\n\n修改 `package.json`\n\n```json\n  \"scripts\": {\n    \"start\": \"react-app-rewired start\",\n    \"build\": \"react-scripts build\",\n    \"test\": \"react-scripts test\",\n    \"eject\": \"react-scripts eject\"\n  },\n```\n\n4. 在 `index.tsx` 中导出子应用生命周期\n\n```tsx\nimport React from \"react\";\nimport ReactDOM from \"react-dom/client\";\nimport \"./index.css\";\nimport App from \"./App\";\nimport reportWebVitals from \"./reportWebVitals\";\n\n// const root = ReactDOM.createRoot(\n//   document.getElementById('root') as HTMLElement\n// );\n// root.render(\n//   \u003cReact.StrictMode\u003e\n//     \u003cApp /\u003e\n//   \u003c/React.StrictMode\u003e\n// );\n\n// let root: ReactDOM.Root;\n\nfunction render(props: any) {\n  const { container } = props;\n  const root = container\n    ? ReactDOM.createRoot(container.querySelector(\"#root\") as HTMLElement)\n    : ReactDOM.createRoot(document.getElementById(\"root\") as HTMLElement);\n\n  root.render(\n    \u003cReact.StrictMode\u003e\n      \u003cApp /\u003e\n    \u003c/React.StrictMode\u003e\n  );\n}\n\nif (!window.__POWERED_BY_QIANKUN__) {\n  render({});\n}\n\nexport async function bootstrap() {\n  console.log(\"[react18] react app bootstraped\");\n}\n\nexport async function mount(props: any) {\n  console.log(\"[react18] props from main framework\", props);\n  render(props);\n}\n\nexport async function unmount(props: any) {\n  const { container } = props;\n  const root = container\n    ? ReactDOM.createRoot(container.querySelector(\"#root\") as HTMLElement)\n    : ReactDOM.createRoot(document.getElementById(\"root\") as HTMLElement);\n  root.unmount();\n}\n\n// If you want to start measuring performance in your app, pass a function\n// to log results (for example: reportWebVitals(console.log))\n// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals\nreportWebVitals();\n```\n\n5. 解决静态资源不加载\n\n在 `index.tsx` 顶部引入 `public-path`\n\n```tsx\nimport \"./public-path\";\n...\n```\n\n## mini-vue2\n\n### 描述\n\n- 微应用 2（vue2.0）\n\n### 步骤\n\n1. 新建 `src/public-path.js`\n\n```js\nif (window.__POWERED_BY_QIANKUN__) {\n  __webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;\n}\n```\n\n2. 修改 `main.js`\n\n```js\nimport \"./public-path\";\nimport Vue from \"vue\";\nimport App from \"./App.vue\";\n\nVue.config.productionTip = false;\n\n// new Vue({\n//   render: h =\u003e h(App),\n// }).$mount('#app')\n\n// let router = null;\nlet instance = null;\nfunction render(props = {}) {\n  const { container } = props;\n  // router = new VueRouter({\n  //   base: window.__POWERED_BY_QIANKUN__ ? \"/app-vue/\" : \"/\",\n  //   mode: \"history\",\n  //   routes,\n  // });\n\n  instance = new Vue({\n    // router,\n    // store,\n    render: (h) =\u003e h(App),\n  }).$mount(container ? container.querySelector(\"#app\") : \"#app\");\n}\n\n// 独立运行时\nif (!window.__POWERED_BY_QIANKUN__) {\n  render();\n}\n\nexport async function bootstrap() {\n  console.log(\"[vue] vue app bootstraped\");\n}\nexport async function mount(props) {\n  console.log(\"[vue] props from main framework\", props);\n  render(props);\n}\nexport async function unmount() {\n  instance.$destroy();\n  instance.$el.innerHTML = \"\";\n  instance = null;\n  // router = null;\n}\n```\n\n3. 根目录新增 `vue.config.js`\n\n```js\nconst { name } = require(\"./package\");\nmodule.exports = {\n  devServer: {\n    headers: {\n      \"Access-Control-Allow-Origin\": \"*\",\n    },\n  },\n  configureWebpack: {\n    output: {\n      library: `${name}-[name]`,\n      libraryTarget: \"umd\", // 把微应用打包成 umd 库格式\n      jsonpFunction: `webpackJsonp_${name}`,\n    },\n  },\n};\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchemistwang%2Fdemo-qiankun","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fchemistwang%2Fdemo-qiankun","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchemistwang%2Fdemo-qiankun/lists"}