[
  {
    "path": ".eslintrc.js",
    "content": "module.exports = {\n  env: {\n    browser: true,\n    es2021: true,\n    node: true,\n    jest: true,\n  },\n  extends: ['airbnb-base', 'prettier'],\n  parser: '@typescript-eslint/parser',\n  parserOptions: {\n    ecmaVersion: 12,\n    sourceType: 'module',\n  },\n  plugins: ['@typescript-eslint', 'import'],\n  rules: {\n    'semi': 'error',\n    'no-unused-vars': 'off',\n    '@typescript-eslint/no-unused-vars': ['error'],\n    'import/extensions': 'off',\n    'import/prefer-default-export': 'off',\n    'object-curly-newline': 'off',\n    'class-methods-use-this': 'off',\n    'no-shadow': 'off',\n    'no-console': 'off',\n    'arrow-body-style': 'off',\n    'no-useless-constructor': 'off',\n    'import/no-extraneous-dependencies': 'off',\n    'no-undef': 'off',\n    'object-shorthand': 'off',\n    'no-await-in-loop': 'off',\n    'consistent-return': 'off',\n    'no-restricted-syntax': 'off',\n    'prefer-destructuring': 'off',\n    'func-names': 'off',\n    'global-require': 'off',\n    'no-underscore-dangle': 'off',\n    'import/named': 'off',\n    'no-use-before-define': 'off',\n  },\n  settings: {\n    'import/parsers': {\n      '@typescript-eslint/parser': ['.ts', '.tsx'],\n    },\n    'import/resolver': {\n      typescript: {\n        alwaysTryTypes: true,\n      },\n    },\n  },\n};\n"
  },
  {
    "path": ".gitignore",
    "content": "# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.\n\n# dependencies\nnode_modules\n\n# testing\ncoverage\n\n# production\nbuild\n\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\n\n.idea\n\ndist\n\nesm\nlib\n\nyarn.lock\npackage.lock.json\n\nplayground\n"
  },
  {
    "path": ".prettierrc",
    "content": "{\n  \"semi\": true,\n  \"singleQuote\": true,\n  \"trailingComma\": \"es5\",\n  \"bracketSpacing\": true,\n  \"printWidth\": 120,\n  \"arrowParens\": \"always\"\n}\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2021 YuZhanglong\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "<div align=\"center\">\n<a href=\"https://github.com/yuzhanglong/mf-lite\">\n  <img src=\"https://user-images.githubusercontent.com/56540811/137176565-c6f240c2-73ee-4b9d-bc18-11b29e4512a4.png\" width=\"150\">\n</a>\n</div>\n<br/>\n\n<div align=\"center\">\n\n基于 Webpack 5 Module Federation，优雅且实用的微前端解决方案。\n\n</div>\n\n<div align=\"center\">\n\n[在线 DEMO](https://mf-lite-quick-start-base-app.vercel.app/) | [文档](https://yuzhanglong.feishu.cn/wiki/wikcncmRDZCUJRigluH7skQbtvg)\n</div>\n\n\n## 介绍\n\n**mf-lite** 是一个基于 Webpack 5 Module Federation 来实现模块共享、[qiankun](https://github.com/umijs/qiankun) 来做隔离沙箱的微前端解决方案，它提供以下内容：\n\n- 一个通过命令行快速创建基座应用或者微前端应用的[脚手架](https://github.com/yuzhanglong/mf-lite), 提供项目初始化依赖及开发、构建脚本。[![npm Version](https://img.shields.io/npm/v/@mf-lite/cli.svg)](https://www.npmjs.com/package/@mf-lite/cli)\n\n- 一个[核心工具库](https://github.com/yuzhanglong/mf-lite/tree/master/packages/core), 它可以：[![npm Version](https://img.shields.io/npm/v/@mf-lite/core.svg)](https://www.npmjs.com/package/@mf-lite/core)\n  - 基于 **Webpack Module Federation** 特性，让微前端架构下的的**库共享**(share library)、甚至**模块共享**(share module) 成为可能，且使用更加优雅、易于维护。\n  - 自动生成、处理开发、生产可用的 webpack 的复杂配置项，用户基本上无需直接接触 webpack 的相关配置。\n  - 支持生成远程模块的 typescript 类型定义。\n\n- 一个基于 node.js、方便独立开发微应用的 HTTP [请求代理工具](https://github.com/yuzhanglong/attachments/tree/main/packages/proxy), 使微应用的独立开发方式更加优雅。[![npm Version](https://img.shields.io/npm/v/@attachments/proxy.svg)](https://www.npmjs.com/package/@attachments/proxy)\n\n\n对于用户来说，唯一需要做的就是拉取模板、然后加上一些十分简单的配置，剩下的和平常的开发流程别无二致。\n\n## 特性\n\n📦 **开箱即用**：你只需要执行几行命令即可拉取相应的模板代码并把项目跑起来，包括基座应用和微前端应用，无需处理构建工具的复杂配置。\n\n🤩 **typescript 支持**：模块的生产者和消费者均可自动生成/消费相关的 typescript 类型定义。\n\n🚀 **舒适的开发体验**：开发体验与常规应用一致、完美接入 qiankun 微前端沙箱库、基座和微应用开发都支持热更新，类型定义的生成也不会打断正常的开发流程。\n\n🔨 **独立开发与部署**：基于提供的代理工具，微应用开发者在单独开发微应用时，无需启动基座或者其它微应用。\n\n🌟 **轻量的项目模板**：脚手架生成的初始项目只保留微前端相关的核心依赖，其它第三方库的选型（如 ui 组件库、状态管理库）交由开发者全权管理。\n\n## 快速开始\n\n**安装脚手架工具**\n\n```shell\nnpm install @mf-lite/cli -g\n```\n\n**在交互式命令行中创建项目**\n\n```shell\nmf-lite create\n```\n\n**安装依赖、执行项目**\n\n```shell\nnpm install\nnpm run dev:serve\n```\n\n更多信息以及实践方案，请[查看文档](https://yuzhanglong.feishu.cn/docs/doccnGEPiy8D3DJTZw6S05QJW4f)\n\n## 案例\n\n[快速开始](https://github.com/yuzhanglong/mf-lite/tree/master/examples/quick-start): 最简单的项目 DEMO，开箱即用，全部在本地运行开发。子应用能够共享基座应用暴露出来的模块或者 npm 包。\n\n[微应用独立开发](https://github.com/yuzhanglong/mf-lite/tree/master/examples/micro-app-only): 单独微应用的开发模式，基于部署在远程的基座开发，微应用基于它运行、消费其依赖。\n\n[远程部署案例](https://github.com/yuzhanglong/mf-lite/tree/master/examples/remote-deploy): 通过配置来实现远程部署，其实现效果就是上文的 [在线 DEMO](https://mf-lite-quick-start-base-app.vercel.app/)。\n\n[多个子应用部署案例](https://github.com/yuzhanglong/mf-lite/tree/master/examples/multiply-micro-app): 一个在同一个页面运行多个微应用的案例。\n\n> TIP: 所有案例都可以在本仓库的 `examples` 目录下找到。\n\n## 它是如何工作的\n\n请参考[这篇文章](https://zhuanlan.zhihu.com/p/422460780)\n\n## License\n\nMIT [@yuzhanglong](https://github.com/yuzhanglong)\n"
  },
  {
    "path": "examples/micro-app-only/README.md",
    "content": "# Example: Micro App Only\n\n单独微应用的开发模式，基于部署在远程的基座开发，在实际开发中强烈建议使用此方式。\n\n相关实践请参考文档的[这一小节](https://ph3xmz5sya.feishu.cn/docs/doccnGEPiy8D3DJTZw6S05QJW4f#EbxQgg)\n"
  },
  {
    "path": "examples/micro-app-only/micro-app/.eslintrc.js",
    "content": "module.exports = {\n  root: true,\n  env: {\n    browser: true,\n    es2021: true,\n    node: true,\n    jest: true,\n  },\n  extends: ['airbnb-base', 'prettier'],\n  parser: '@typescript-eslint/parser',\n  parserOptions: {\n    ecmaVersion: 12,\n    sourceType: 'module',\n  },\n  plugins: ['@typescript-eslint', 'import'],\n  rules: {\n    'semi': 'error',\n    'no-unused-vars': 'off',\n    '@typescript-eslint/no-unused-vars': ['error'],\n    'import/extensions': 'off',\n    'import/prefer-default-export': 'off',\n    'object-curly-newline': 'off',\n    'class-methods-use-this': 'off',\n    'no-shadow': 'off',\n    'no-console': 'off',\n    'arrow-body-style': 'off',\n    'no-useless-constructor': 'off',\n    'import/no-extraneous-dependencies': 'off',\n    'no-undef': 'off',\n    'object-shorthand': 'off',\n    'no-await-in-loop': 'off',\n    'consistent-return': 'off',\n    'no-restricted-syntax': 'off',\n    'prefer-destructuring': 'off',\n    'func-names': 'off',\n    'global-require': 'off',\n    'import/no-unresolved': 'off',\n    'no-underscore-dangle': 'off',\n    'no-use-before-define': 'off'\n  },\n  settings: {\n    'import/parsers': {\n      '@typescript-eslint/parser': ['.ts', '.tsx'],\n    },\n    'import/resolver': {\n      typescript: {\n        alwaysTryTypes: true,\n      },\n    },\n  },\n};\n"
  },
  {
    "path": "examples/micro-app-only/micro-app/.gitignore",
    "content": "# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.\n\n# dependencies\n/node_modules\n/.pnp\n.pnp.js\n\n# testing\n/coverage\n\n# production\n/build\ndist\n\n\n# IDE Config\n.idea\n\n# misc\n.DS_Store\n.env.local\n.env.development.local\n.env.test.local\n.env.production.local\n\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\n\n# tmp files\npublic/static\n\n.cache\n\n# 本地生成的类型定义文件\nsrc/types/mf-remotes\n\n# 模块提供者打包生成的类型定义\npublic/mf-expose/types\n"
  },
  {
    "path": "examples/micro-app-only/micro-app/.prettierrc.json",
    "content": "{\n  \"tabWidth\": 2,\n  \"semi\": false,\n  \"singleQuote\": true,\n  \"jsxBracketSameLine\": true\n}\n"
  },
  {
    "path": "examples/micro-app-only/micro-app/app-config.ts",
    "content": "import { MicroAppConfig } from '@mf-lite/core/lib/node/micro-fe-app-config';\n\nconst config: MicroAppConfig = {\n  name: 'micro_app',\n  url: 'http://localhost:10000/',\n  exposes: [],\n  remotes: [\n    {\n      name: 'base_app',\n      url: 'http://localhost:8080/',\n      sharedLibraries: [\n        'react',\n        'react-dom',\n        'react/jsx-dev-runtime',\n        'react-router',\n        'react-router-dom',\n        'react-router-config'\n      ]\n    }\n  ]\n};\n\nexport default config;\n"
  },
  {
    "path": "examples/micro-app-only/micro-app/package.json",
    "content": "{\n  \"name\": \"micro-app\",\n  \"version\": \"0.0.1\",\n  \"main\": \"index.js\",\n  \"license\": \"MIT\",\n  \"devDependencies\": {\n    \"@attachments/proxy\": \"^0.1.0\",\n    \"@types/fs-extra\": \"^9.0.12\",\n    \"@types/node\": \"^16.4.6\",\n    \"@types/react\": \"^17.0.18\",\n    \"@types/react-dom\": \"^17.0.9\",\n    \"@types/react-router\": \"^5.1.16\",\n    \"@types/react-router-config\": \"^5.0.3\",\n    \"@types/react-router-dom\": \"^5.1.8\",\n    \"@typescript-eslint/eslint-plugin\": \"^4.28.5\",\n    \"@typescript-eslint/parser\": \"^4.28.5\",\n    \"autoprefixer\": \"^10.3.6\",\n    \"concurrently\": \"^6.3.0\",\n    \"cross-env\": \"^7.0.3\",\n    \"eslint\": \"^7.31.0\",\n    \"eslint-config-airbnb\": \"^18.2.1\",\n    \"eslint-config-prettier\": \"^8.1.0\",\n    \"eslint-import-resolver-typescript\": \"^2.4.0\",\n    \"eslint-plugin-import\": \"^2.22.1\",\n    \"eslint-plugin-prettier\": \"^3.3.1\",\n    \"react-router-config\": \"^5.1.1\",\n    \"rimraf\": \"^3.0.2\",\n    \"ts-node\": \"^10.2.1\",\n    \"typescript\": \"^4.3.5\",\n    \"webpack-merge\": \"^5.8.0\"\n  },\n  \"scripts\": {\n    \"dev:proxy\": \"ts-node scripts/proxy.ts\",\n    \"dev:serve\": \"cross-env NODE_ENV=development mf-lite serve --port=10000 --app-type=micro-app\",\n    \"build:dev\": \"rimraf dist && cross-env NODE_ENV=development mf-lite build --app-type=micro-app\",\n    \"build:prod\": \"rimraf dist && cross-env NODE_ENV=production mf-lite build --app-type=micro-app\",\n    \"lint\": \"eslint --ext js,jsx,ts,tsx src\",\n    \"generate\": \"mf-lite generate\",\n    \"upgrade\": \"mf-lite upgrade\"\n  },\n  \"dependencies\": {\n    \"@mf-lite/cli\": \"^0.1.0\",\n    \"@mf-lite/core\": \"^0.1.0\",\n    \"@attachments/utils\": \"^0.1.15\",\n    \"react\": \"^17.0.2\",\n    \"react-dom\": \"^17.0.2\",\n    \"react-router\": \"^5.2.1\",\n    \"react-router-dom\": \"^5.2.1\"\n  }\n}\n"
  },
  {
    "path": "examples/micro-app-only/micro-app/public/index.html",
    "content": "<!DOCTYPE html>\n<html lang='en'>\n<head>\n  <meta charset='UTF-8'>\n  <title>micro-app</title>\n</head>\n<body>\n<div id='micro-app'></div>\n</body>\n</html>\n"
  },
  {
    "path": "examples/micro-app-only/micro-app/public/mf-expose-types/exposes.d.ts",
    "content": ""
  },
  {
    "path": "examples/micro-app-only/micro-app/scripts/proxy.ts",
    "content": "import { ProxyServer } from '@attachments/proxy';\n\nconst runProxy = async () => {\n  const server = new ProxyServer();\n\n  // micro app 代理\n  server.addRule(\n    'mf-lite-quick-start-micro-app.vercel.app',\n    {\n      location: '/',\n      proxyPass: 'http://localhost:10000',\n    }\n  );\n\n  await server.initServers();\n  await server.listen();\n};\n\nrunProxy().catch(e => {\n  console.log(e);\n});\n"
  },
  {
    "path": "examples/micro-app-only/micro-app/src/app.tsx",
    "content": "import React from 'react';\nimport ReactDOM from 'react-dom';\nimport { BrowserRouter } from 'react-router-dom';\nimport { renderRoutes } from 'react-router-config';\nimport './init-common';\nimport { routes } from './routes';\n\n\nconst App: React.FC = () => {\n  return (\n    <BrowserRouter>\n      {renderRoutes(routes)}\n    </BrowserRouter>\n  );\n};\n\nexport const render = () => {\n  const el = document.getElementById('micro-app');\n  if (el) {\n    ReactDOM.render(<App />, el);\n  }\n};\n\nexport const destroy = () => {\n  const el = document.getElementById('micro-app');\n  if (el) {\n    ReactDOM.unmountComponentAtNode(el);\n  }\n};\n"
  },
  {
    "path": "examples/micro-app-only/micro-app/src/index.tsx",
    "content": "const App = import('./app');\n\nconst render = () => {\n  App.then(res => res.render());\n};\n\nif (!window.__POWERED_BY_QIANKUN__) {\n  render();\n}\n\n/**\n * bootstrap 只会在微应用初始化的时候调用一次，下次微应用重新进入时会直接调用 mount 钩子，不会再重复触发 bootstrap。\n * 通常我们可以在这里做一些全局变量的初始化，比如不会在 unmount 阶段被销毁的应用级别的缓存等。\n */\nexport async function bootstrap() {\n  return 0;\n}\n\n\n/**\n * 应用每次进入都会调用 mount 方法，通常我们在这里触发应用的渲染方法\n */\nexport async function mount() {\n  render();\n}\n\n/**\n * 应用每次 切出/卸载 会调用的方法，通常在这里我们会卸载微应用的应用实例\n */\nexport async function unmount() {\n  App.then(res => res.destroy());\n}\n\n/**\n * 可选生命周期钩子，仅使用 loadMicroApp 方式加载微应用时生效\n */\nexport async function update() {\n  render();\n}\n"
  },
  {
    "path": "examples/micro-app-only/micro-app/src/init-common.ts",
    "content": "// @ts-ignore\nimport { injectBaseReactRefresh } from '@mf-lite/core/esm/browser/inject-base-react-refresh';\n\nif (process.env.NODE_ENV === 'development') {\n  injectBaseReactRefresh();\n}\n"
  },
  {
    "path": "examples/micro-app-only/micro-app/src/pages/home.less",
    "content": ".react-app-home {\n  .button-wrapper {\n    margin-bottom: 20px;\n  }\n\n  .home-content {\n    font-size: 20px;\n  }\n}\n"
  },
  {
    "path": "examples/micro-app-only/micro-app/src/pages/home.tsx",
    "content": "import React from 'react';\nimport { RouteComponentProps } from 'react-router';\nimport './home.less';\n\ninterface HomeProps extends RouteComponentProps {\n\n}\n\nconst Home: React.FC<HomeProps> = () => {\n  // @ts-ignore\n  return (\n    <div className={'react-app-home'}>\n      这是本地微应用的代码~\n    </div>\n  );\n};\n\nexport default Home;\n"
  },
  {
    "path": "examples/micro-app-only/micro-app/src/pages/page-one.tsx",
    "content": "import React from 'react';\n\ninterface ProfileProps {\n\n}\n\nconst PageOne: React.FC<ProfileProps> = () => {\n  return (\n    <div>Page One</div>\n  );\n};\n\nexport default PageOne;\n"
  },
  {
    "path": "examples/micro-app-only/micro-app/src/pages/page-two.tsx",
    "content": "import React from 'react';\n\ninterface PageTwoProps {\n\n}\n\nconst PageTwo: React.FC<PageTwoProps> = () => {\n  return (\n    <div>Page Two</div>\n  );\n};\n\nexport default PageTwo;\n"
  },
  {
    "path": "examples/micro-app-only/micro-app/src/routes.ts",
    "content": "import { RouteConfig } from 'react-router-config';\nimport PageOne from './pages/page-one';\nimport Home from './pages/home';\nimport PageTwo from './pages/page-two';\n\nexport const routes: RouteConfig[] = [\n  {\n    component: Home,\n    routes: [\n      {\n        path: '/',\n        exact: true,\n        component: PageOne,\n      },\n      {\n        path: '/page-one',\n        component: PageOne,\n      },\n      {\n        path: '/page-two',\n        component: PageTwo,\n      },\n    ],\n  },\n];\n"
  },
  {
    "path": "examples/micro-app-only/micro-app/src/types/global.d.ts",
    "content": "declare global {\n  interface Window {\n    __POWERED_BY_QIANKUN__: boolean;\n    __REACT_DEVTOOLS_GLOBAL_HOOK__: any;\n  }\n}\n\n\nexport {};\n"
  },
  {
    "path": "examples/micro-app-only/micro-app/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"target\": \"ES5\",\n    \"module\": \"CommonJS\",\n    \"baseUrl\": \"src\",\n    \"lib\": [\n      \"dom\",\n      \"dom.iterable\",\n      \"esnext\"\n    ],\n    \"paths\": {\n      \"~src/*\": [\n        \"./*\"\n      ]\n    },\n    \"types\": [\n      \"node\"\n    ],\n    \"allowJs\": true,\n    \"skipLibCheck\": true,\n    \"esModuleInterop\": true,\n    \"moduleResolution\": \"node\",\n    \"resolveJsonModule\": true,\n    \"isolatedModules\": false,\n    \"noEmit\": true,\n    \"experimentalDecorators\": true,\n    \"jsx\": \"preserve\",\n    \"downlevelIteration\": true\n  },\n  \"include\": [\n    \"src\"\n  ]\n}\n"
  },
  {
    "path": "examples/multiply-micro-app/README.md",
    "content": "# Example: Multiply Micro App\n\n一个基座，多个微应用同时运行。\n"
  },
  {
    "path": "examples/multiply-micro-app/base-app/.eslintrc.js",
    "content": "module.exports = {\n  root: true,\n  env: {\n    browser: true,\n    es2021: true,\n    node: true,\n    jest: true,\n  },\n  extends: ['airbnb-base', 'prettier'],\n  parser: '@typescript-eslint/parser',\n  parserOptions: {\n    ecmaVersion: 12,\n    sourceType: 'module',\n  },\n  plugins: ['@typescript-eslint', 'import'],\n  rules: {\n    'semi': 'error',\n    'no-unused-vars': 'off',\n    '@typescript-eslint/no-unused-vars': ['error'],\n    'import/extensions': 'off',\n    'import/prefer-default-export': 'off',\n    'object-curly-newline': 'off',\n    'class-methods-use-this': 'off',\n    'no-shadow': 'off',\n    'no-console': 'off',\n    'arrow-body-style': 'off',\n    'no-useless-constructor': 'off',\n    'import/no-extraneous-dependencies': 'off',\n    'no-undef': 'off',\n    'object-shorthand': 'off',\n    'no-await-in-loop': 'off',\n    'consistent-return': 'off',\n    'no-restricted-syntax': 'off',\n    'prefer-destructuring': 'off',\n    'func-names': 'off',\n    'global-require': 'off',\n    'import/no-unresolved': 'off',\n    'no-underscore-dangle': 'off',\n    'no-use-before-define': 'off'\n  },\n  settings: {\n    'import/parsers': {\n      '@typescript-eslint/parser': ['.ts', '.tsx'],\n    },\n    'import/resolver': {\n      typescript: {\n        alwaysTryTypes: true,\n      },\n    },\n  },\n};\n"
  },
  {
    "path": "examples/multiply-micro-app/base-app/.gitignore",
    "content": "# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.\n\n# dependencies\n/node_modules\n/.pnp\n.pnp.js\n\n# testing\n/coverage\n\n# production\n/build\ndist\n\n\n# IDE Config\n.idea\n\n# misc\n.DS_Store\n.env.local\n.env.development.local\n.env.test.local\n.env.production.local\n\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\n\n# tmp files\npublic/static\n\n.cache\n\n# 本地生成的类型定义文件\nsrc/types/mf-remotes\n\n# 模块提供者打包生成的类型定义\npublic/mf-expose/types\n"
  },
  {
    "path": "examples/multiply-micro-app/base-app/.prettierrc.json",
    "content": "{\n  \"tabWidth\": 2,\n  \"semi\": false,\n  \"singleQuote\": true,\n  \"jsxBracketSameLine\": true\n}\n"
  },
  {
    "path": "examples/multiply-micro-app/base-app/app-config.ts",
    "content": "import * as path from 'path';\nimport { MicroAppConfig } from '@mf-lite/core/lib/node/micro-fe-app-config';\nimport { sourcePath } from '@mf-lite/core/lib/common/paths';\n\nconst config: MicroAppConfig = {\n  remotes: [],\n  name: 'base_app',\n  url: 'http://localhost:8080/',\n  exposes: [\n    'react',\n    'react-dom',\n    'react-router',\n    'react-router-dom',\n    'react-router-config',\n    'react/jsx-dev-runtime',\n    {\n      name: 'shared-utils',\n      path: path.resolve(sourcePath, 'utils', 'shared-utils.ts'),\n      type: 'module',\n    },\n  ],\n};\n\nexport default config;\n"
  },
  {
    "path": "examples/multiply-micro-app/base-app/package.json",
    "content": "{\n  \"name\": \"base-app\",\n  \"version\": \"0.0.1\",\n  \"main\": \"index.js\",\n  \"license\": \"MIT\",\n  \"devDependencies\": {\n    \"@attachments/proxy\": \"^0.1.0\",\n    \"@types/fs-extra\": \"^9.0.12\",\n    \"@types/node\": \"^16.4.6\",\n    \"@types/react\": \"^17.0.18\",\n    \"@types/react-dom\": \"^17.0.9\",\n    \"@types/react-router\": \"^5.1.16\",\n    \"@types/react-router-config\": \"^5.0.3\",\n    \"@types/react-router-dom\": \"^5.1.8\",\n    \"@typescript-eslint/eslint-plugin\": \"^4.28.5\",\n    \"@typescript-eslint/parser\": \"^4.28.5\",\n    \"autoprefixer\": \"^10.3.6\",\n    \"concurrently\": \"^6.3.0\",\n    \"cross-env\": \"^7.0.3\",\n    \"eslint\": \"^7.31.0\",\n    \"eslint-config-airbnb\": \"^18.2.1\",\n    \"eslint-config-prettier\": \"^8.1.0\",\n    \"eslint-import-resolver-typescript\": \"^2.4.0\",\n    \"eslint-plugin-import\": \"^2.22.1\",\n    \"eslint-plugin-prettier\": \"^3.3.1\",\n    \"react-router-config\": \"^5.1.1\",\n    \"rimraf\": \"^3.0.2\",\n    \"ts-node\": \"^10.2.1\",\n    \"typescript\": \"^4.3.5\",\n    \"webpack-merge\": \"^5.8.0\"\n  },\n  \"scripts\": {\n    \"dev:proxy\": \"ts-node scripts/proxy.ts\",\n    \"dev:serve\": \"cross-env NODE_ENV=development mf-lite serve --port=8080 --app-type=base-app\",\n    \"build:dev\": \"rimraf dist && cross-env NODE_ENV=development mf-lite build --app-type=base-app\",\n    \"build:prod\": \"rimraf dist && cross-env NODE_ENV=production mf-lite build --app-type=base-app\",\n    \"lint\": \"eslint --ext js,jsx,ts,tsx src\",\n    \"generate\": \"mf-lite generate\",\n    \"upgrade\": \"mf-lite upgrade\"\n  },\n  \"dependencies\": {\n    \"@mf-lite/cli\": \"^0.1.0\",\n    \"@mf-lite/core\": \"^0.1.0\",\n    \"@attachments/utils\": \"^0.1.15\",\n    \"react\": \"^17.0.2\",\n    \"react-dom\": \"^17.0.2\",\n    \"react-router\": \"^5.2.1\",\n    \"react-router-dom\": \"^5.2.1\"\n  }\n}\n"
  },
  {
    "path": "examples/multiply-micro-app/base-app/public/index.html",
    "content": "<!DOCTYPE html>\n<html lang='en'>\n<head>\n  <meta charset='UTF-8'>\n  <title>base-app</title>\n</head>\n<body>\n<div id='base-app'></div>\n</body>\n</html>\n"
  },
  {
    "path": "examples/multiply-micro-app/base-app/public/mf-expose-types/exposes.d.ts",
    "content": "// module name: base_app/shared-utils\n\ndeclare module 'base_app/shared-utils' {\n    export const add: (a: number, b: number) => number;\n    export const sayHello: () => void;\n    export default add;\n    export { };\n}\n\n"
  },
  {
    "path": "examples/multiply-micro-app/base-app/scripts/proxy.ts",
    "content": "import { ProxyServer } from '@attachments/proxy';\n\nconst runProxy = async () => {\n  const server = new ProxyServer();\n\n  // 基座代理，将 base-app.vercel.app 的所有请求代理到 http://localhost:8080\n  server.addRule(\n    'base-app.vercel.app',\n    {\n      location: '/',\n      proxyPass: 'http://localhost:8080',\n    }\n  );\n\n  await server.initServers();\n  await server.listen();\n};\n\nrunProxy().catch(e => {\n  console.log(e);\n});\n"
  },
  {
    "path": "examples/multiply-micro-app/base-app/src/app.tsx",
    "content": "import ReactDOM from 'react-dom';\nimport { BrowserRouter } from 'react-router-dom';\nimport React, { Suspense } from 'react';\nimport { renderRoutes } from 'react-router-config';\nimport { routes } from '~src/routes';\nimport './utils/init-common';\nimport '@attachments/utils/src/browser/css/common.css';\n\nconst App = () => {\n  return (\n    <Suspense fallback={null}>\n      <BrowserRouter>\n        {renderRoutes(routes)}\n      </BrowserRouter>\n    </Suspense>\n  );\n};\n\n\nconst reactRenderer = () => {\n  ReactDOM.render((\n    <BrowserRouter>\n      <App />\n    </BrowserRouter>\n  ), document.getElementById('base-app'));\n};\n\nconst beforeAppStart = async () => {\n  return true;\n};\n\nbeforeAppStart()\n  .then(() => {\n    reactRenderer();\n  });\n\n\n"
  },
  {
    "path": "examples/multiply-micro-app/base-app/src/common/const.ts",
    "content": "export interface MicroAppConfig {\n  name: string;\n  url: string;\n}\n\nexport const MICRO_APPS: MicroAppConfig[] = [\n  {\n    name: 'micro-app-one',\n    url: 'http://localhost:10000/',\n  },\n  {\n    name: 'micro-app-two',\n    url: 'http://localhost:10001/',\n  },\n];\n"
  },
  {
    "path": "examples/multiply-micro-app/base-app/src/index.tsx",
    "content": "import ('./app');\n\n"
  },
  {
    "path": "examples/multiply-micro-app/base-app/src/pages/home.less",
    "content": ".base-app-home {\n  .title {\n    font-size: 16px;\n    margin-bottom: 20px;\n  }\n\n  .content {\n    border: 1px solid;\n    padding: 10px;\n    min-height: 100px;\n  }\n}\n"
  },
  {
    "path": "examples/multiply-micro-app/base-app/src/pages/home.tsx",
    "content": "import React from 'react';\nimport './home.less';\nimport { createMicroApp } from '~src/utils/create-micro-app';\n\ninterface HomeProps {\n\n}\n\nconst Home: React.FC<HomeProps> = () => {\n  return (\n    <div className={'base-app-home'}>\n      <div className={'title'}>\n        🎉 Two micro apps will be rendered below!!!\n      </div>\n      <div className={'content'}>\n        {createMicroApp('micro-app-one')()}\n      </div>\n      <div className={'content'}>\n        {createMicroApp('micro-app-two')()}\n      </div>\n    </div>\n  );\n};\n\nexport default Home;\n"
  },
  {
    "path": "examples/multiply-micro-app/base-app/src/routes.ts",
    "content": "import { RouteConfig } from 'react-router-config';\nimport Home from './pages/home';\n\nexport const routes: RouteConfig[] = [\n  {\n    component: Home,\n    routes: [],\n  },\n];\n"
  },
  {
    "path": "examples/multiply-micro-app/base-app/src/types/global.d.ts",
    "content": "declare module '*.module.css';\ndeclare module '*.module.sass';\ndeclare module '*.module.scss';\n\n\ndeclare global {\n  const __APP_VERSION__: string;\n  const __MODE__: string;\n  const __BUILD_TIME__: string;\n\n  interface Window {\n    __POWERED_BY_QIANKUN__: boolean;\n  }\n}\n\n\nexport {};\n\n"
  },
  {
    "path": "examples/multiply-micro-app/base-app/src/utils/create-micro-app.tsx",
    "content": "import React, { useEffect, useRef } from 'react';\nimport { MicroApp, MicroAppRef } from '@mf-lite/core/esm/browser/micro-app';\nimport { MICRO_APPS, MicroAppConfig } from '~src/common/const';\n\n\nexport const getMicroApp = (name: string): MicroAppConfig => {\n  const item = MICRO_APPS.find(res => res.name === name);\n  if (!item) {\n    throw new Error(`the micro app ${name} is not exist!`);\n  }\n  return item;\n};\n\n\nexport const createMicroApp = (name: string) => {\n  return () => {\n    const ref = useRef<MicroAppRef>(null);\n\n    const microAppConfig = {\n      name: name,\n      entry: getMicroApp(name).url,\n    }\n\n    useEffect(() => {\n      if (ref.current?.appStore) {\n        ref.current?.appStore.microApp?.loadPromise\n          .then(() => {\n            console.log('micro app loaded!');\n          });\n      }\n    }, []);\n\n    return (\n      <MicroApp\n        ref={ref}\n        microAppConfig={microAppConfig} />\n    );\n  };\n};\n"
  },
  {
    "path": "examples/multiply-micro-app/base-app/src/utils/init-common.ts",
    "content": "/**\n * File: init-common.ts\n * Description: 项目全局初始化\n * Created: 2021-09-28 21:51:34\n * Author: yuzhanglong\n * Email: yuzl1123@163.com\n */\n\n// patch 基座的 react-refresh\nimport { consoleTag } from '@attachments/utils/esm/browser/console-tag';\n\nconsoleTag(\n  {\n    key: 'MODE',\n    value: __MODE__,\n  },\n  {\n    key: 'VERSION',\n    value: __APP_VERSION__,\n    valueColor: '#409eff',\n  },\n  {\n    key: 'BUILD_TIME',\n    value: __BUILD_TIME__,\n    valueColor: '#ea7b27',\n  },\n);\n"
  },
  {
    "path": "examples/multiply-micro-app/base-app/src/utils/shared-utils.ts",
    "content": "export const add = (a: number, b: number) => {\n  return a + b;\n};\n\nexport const sayHello = () => {\n  console.log('hello world!');\n};\n\nexport default add;\n"
  },
  {
    "path": "examples/multiply-micro-app/base-app/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"target\": \"ES5\",\n    \"module\": \"CommonJS\",\n    \"baseUrl\": \"src\",\n    \"lib\": [\n      \"dom\",\n      \"dom.iterable\",\n      \"esnext\"\n    ],\n    \"paths\": {\n      \"~src/*\": [\n        \"./*\"\n      ]\n    },\n    \"types\": [\n      \"node\"\n    ],\n    \"allowJs\": true,\n    \"skipLibCheck\": true,\n    \"esModuleInterop\": true,\n    \"moduleResolution\": \"node\",\n    \"resolveJsonModule\": true,\n    \"isolatedModules\": false,\n    \"noEmit\": true,\n    \"experimentalDecorators\": true,\n    \"jsx\": \"preserve\",\n    \"downlevelIteration\": true\n  },\n  \"include\": [\n    \"src\"\n  ]\n}\n"
  },
  {
    "path": "examples/multiply-micro-app/micro-app-one/.eslintrc.js",
    "content": "module.exports = {\n  root: true,\n  env: {\n    browser: true,\n    es2021: true,\n    node: true,\n    jest: true,\n  },\n  extends: ['airbnb-base', 'prettier'],\n  parser: '@typescript-eslint/parser',\n  parserOptions: {\n    ecmaVersion: 12,\n    sourceType: 'module',\n  },\n  plugins: ['@typescript-eslint', 'import'],\n  rules: {\n    'semi': 'error',\n    'no-unused-vars': 'off',\n    '@typescript-eslint/no-unused-vars': ['error'],\n    'import/extensions': 'off',\n    'import/prefer-default-export': 'off',\n    'object-curly-newline': 'off',\n    'class-methods-use-this': 'off',\n    'no-shadow': 'off',\n    'no-console': 'off',\n    'arrow-body-style': 'off',\n    'no-useless-constructor': 'off',\n    'import/no-extraneous-dependencies': 'off',\n    'no-undef': 'off',\n    'object-shorthand': 'off',\n    'no-await-in-loop': 'off',\n    'consistent-return': 'off',\n    'no-restricted-syntax': 'off',\n    'prefer-destructuring': 'off',\n    'func-names': 'off',\n    'global-require': 'off',\n    'import/no-unresolved': 'off',\n    'no-underscore-dangle': 'off',\n    'no-use-before-define': 'off'\n  },\n  settings: {\n    'import/parsers': {\n      '@typescript-eslint/parser': ['.ts', '.tsx'],\n    },\n    'import/resolver': {\n      typescript: {\n        alwaysTryTypes: true,\n      },\n    },\n  },\n};\n"
  },
  {
    "path": "examples/multiply-micro-app/micro-app-one/.gitignore",
    "content": "# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.\n\n# dependencies\n/node_modules\n/.pnp\n.pnp.js\n\n# testing\n/coverage\n\n# production\n/build\ndist\n\n\n# IDE Config\n.idea\n\n# misc\n.DS_Store\n.env.local\n.env.development.local\n.env.test.local\n.env.production.local\n\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\n\n# tmp files\npublic/static\n\n.cache\n\n# 本地生成的类型定义文件\nsrc/types/mf-remotes\n\n# 模块提供者打包生成的类型定义\npublic/mf-expose/types\n"
  },
  {
    "path": "examples/multiply-micro-app/micro-app-one/.prettierrc.json",
    "content": "{\n  \"tabWidth\": 2,\n  \"semi\": false,\n  \"singleQuote\": true,\n  \"jsxBracketSameLine\": true\n}\n"
  },
  {
    "path": "examples/multiply-micro-app/micro-app-one/app-config.ts",
    "content": "import { MicroAppConfig } from '@mf-lite/core/lib/node/micro-fe-app-config';\n\nconst config: MicroAppConfig = {\n  name: 'micro_app_one',\n  url: 'http://localhost:10000/',\n  exposes: [],\n  remotes: [\n    {\n      name: 'base_app',\n      url: 'http://localhost:8080/',\n      sharedLibraries: [\n        'react',\n        'react-dom',\n        'react/jsx-dev-runtime',\n        'react-router',\n        'react-router-dom',\n        'react-router-config'\n      ]\n    }\n  ]\n};\n\nexport default config;\n"
  },
  {
    "path": "examples/multiply-micro-app/micro-app-one/package.json",
    "content": "{\n  \"name\": \"micro-app-one\",\n  \"version\": \"0.0.1\",\n  \"main\": \"index.js\",\n  \"license\": \"MIT\",\n  \"devDependencies\": {\n    \"@attachments/proxy\": \"^0.1.0\",\n    \"@types/fs-extra\": \"^9.0.12\",\n    \"@types/node\": \"^16.4.6\",\n    \"@types/react\": \"^17.0.18\",\n    \"@types/react-dom\": \"^17.0.9\",\n    \"@types/react-router\": \"^5.1.16\",\n    \"@types/react-router-config\": \"^5.0.3\",\n    \"@types/react-router-dom\": \"^5.1.8\",\n    \"@typescript-eslint/eslint-plugin\": \"^4.28.5\",\n    \"@typescript-eslint/parser\": \"^4.28.5\",\n    \"autoprefixer\": \"^10.3.6\",\n    \"concurrently\": \"^6.3.0\",\n    \"cross-env\": \"^7.0.3\",\n    \"eslint\": \"^7.31.0\",\n    \"eslint-config-airbnb\": \"^18.2.1\",\n    \"eslint-config-prettier\": \"^8.1.0\",\n    \"eslint-import-resolver-typescript\": \"^2.4.0\",\n    \"eslint-plugin-import\": \"^2.22.1\",\n    \"eslint-plugin-prettier\": \"^3.3.1\",\n    \"react-router-config\": \"^5.1.1\",\n    \"rimraf\": \"^3.0.2\",\n    \"ts-node\": \"^10.2.1\",\n    \"typescript\": \"^4.3.5\",\n    \"webpack-merge\": \"^5.8.0\"\n  },\n  \"scripts\": {\n    \"dev:proxy\": \"ts-node scripts/proxy.ts\",\n    \"dev:serve\": \"cross-env NODE_ENV=development mf-lite serve --port=10000 --app-type=micro-app\",\n    \"build:dev\": \"rimraf dist && cross-env NODE_ENV=development mf-lite build --app-type=micro-app\",\n    \"build:prod\": \"rimraf dist && cross-env NODE_ENV=production mf-lite build --app-type=micro-app\",\n    \"lint\": \"eslint --ext js,jsx,ts,tsx src\",\n    \"generate\": \"mf-lite generate\",\n    \"upgrade\": \"mf-lite upgrade\"\n  },\n  \"dependencies\": {\n    \"@mf-lite/cli\": \"^0.1.0\",\n    \"@mf-lite/core\": \"^0.1.0\",\n    \"@attachments/utils\": \"^0.1.15\",\n    \"react\": \"^17.0.2\",\n    \"react-dom\": \"^17.0.2\",\n    \"react-router\": \"^5.2.1\",\n    \"react-router-dom\": \"^5.2.1\"\n  }\n}\n"
  },
  {
    "path": "examples/multiply-micro-app/micro-app-one/public/index.html",
    "content": "<!DOCTYPE html>\n<html lang='en'>\n<head>\n  <meta charset='UTF-8'>\n  <title>micro-app-one</title>\n</head>\n<body>\n<div id='micro-app-one'></div>\n</body>\n</html>\n"
  },
  {
    "path": "examples/multiply-micro-app/micro-app-one/public/mf-expose-types/exposes.d.ts",
    "content": ""
  },
  {
    "path": "examples/multiply-micro-app/micro-app-one/scripts/proxy.ts",
    "content": "import { ProxyServer } from '@attachments/proxy';\n\nconst runProxy = async () => {\n  const server = new ProxyServer();\n\n  // micro app 代理\n  server.addRule(\n    'mf-lite-quick-start-micro-app.vercel.app',\n    {\n      location: '/',\n      proxyPass: 'http://localhost:10000',\n    }\n  );\n\n  await server.initServers();\n  await server.listen();\n};\n\nrunProxy().catch(e => {\n  console.log(e);\n});\n"
  },
  {
    "path": "examples/multiply-micro-app/micro-app-one/src/app.tsx",
    "content": "import React from 'react';\nimport ReactDOM from 'react-dom';\nimport { BrowserRouter } from 'react-router-dom';\nimport { renderRoutes } from 'react-router-config';\nimport './init-common';\nimport { routes } from './routes';\n\n\nconst App: React.FC = () => {\n  return (\n    <BrowserRouter>\n      {renderRoutes(routes)}\n    </BrowserRouter>\n  );\n};\n\nexport const render = () => {\n  const el = document.getElementById('micro-app-one');\n  if (el) {\n    ReactDOM.render(<App />, el);\n  }\n};\n\nexport const destroy = () => {\n  const el = document.getElementById('micro-app-one');\n  if (el) {\n    ReactDOM.unmountComponentAtNode(el);\n  }\n};\n"
  },
  {
    "path": "examples/multiply-micro-app/micro-app-one/src/index.tsx",
    "content": "const App = import('./app');\n\nconst render = () => {\n  App.then(res => res.render());\n};\n\nif (!window.__POWERED_BY_QIANKUN__) {\n  render();\n}\n\n/**\n * bootstrap 只会在微应用初始化的时候调用一次，下次微应用重新进入时会直接调用 mount 钩子，不会再重复触发 bootstrap。\n * 通常我们可以在这里做一些全局变量的初始化，比如不会在 unmount 阶段被销毁的应用级别的缓存等。\n */\nexport async function bootstrap() {\n  return 0;\n}\n\n\n/**\n * 应用每次进入都会调用 mount 方法，通常我们在这里触发应用的渲染方法\n */\nexport async function mount() {\n  render();\n}\n\n/**\n * 应用每次 切出/卸载 会调用的方法，通常在这里我们会卸载微应用的应用实例\n */\nexport async function unmount() {\n  App.then(res => res.destroy());\n}\n\n/**\n * 可选生命周期钩子，仅使用 loadMicroApp 方式加载微应用时生效\n */\nexport async function update() {\n  render();\n}\n"
  },
  {
    "path": "examples/multiply-micro-app/micro-app-one/src/init-common.ts",
    "content": "// @ts-ignore\nimport { injectBaseReactRefresh } from '@mf-lite/core/esm/browser/inject-base-react-refresh';\n\nif (process.env.NODE_ENV === 'development') {\n  injectBaseReactRefresh();\n}\n"
  },
  {
    "path": "examples/multiply-micro-app/micro-app-one/src/pages/home.less",
    "content": ".react-app-home {\n  .button-wrapper {\n    margin-bottom: 20px;\n  }\n\n  .home-content {\n    font-size: 20px;\n  }\n}\n"
  },
  {
    "path": "examples/multiply-micro-app/micro-app-one/src/pages/home.tsx",
    "content": "import React, { useState } from 'react';\nimport { renderRoutes } from 'react-router-config';\nimport { RouteComponentProps } from 'react-router';\nimport './home.less';\n\ninterface HomeProps extends RouteComponentProps {\n\n}\n\nconst Home: React.FC<HomeProps> = (props) => {\n  // @ts-ignore\n  const { route, history, location } = props;\n  const [currentPage, setCurrentPage] = useState<'one' | 'two'>(\n    location.pathname === '/page-two' ? 'two' : 'one'\n  );\n\n  const handleButtonClick = () => {\n    const nextPage = currentPage === 'one' ? 'two' : 'one';\n    setCurrentPage(nextPage);\n    history.push(`page-${nextPage}`);\n  };\n\n  return (\n    <div className={'react-app-home'}>\n      <div className={'button-wrapper'}>\n        <button className={'button'} onClick={() => handleButtonClick()}>\n          {`We are at page ${currentPage}, click to change!`}\n        </button>\n      </div>\n      <div className={'home-content'}>\n        {renderRoutes(route.routes)}\n      </div>\n    </div>\n  );\n};\n\nexport default Home;\n"
  },
  {
    "path": "examples/multiply-micro-app/micro-app-one/src/pages/page-one.tsx",
    "content": "import React from 'react';\n\ninterface ProfileProps {\n\n}\n\nconst PageOne: React.FC<ProfileProps> = () => {\n  return (\n    <div>我是第一个微应用~</div>\n  );\n};\n\nexport default PageOne;\n"
  },
  {
    "path": "examples/multiply-micro-app/micro-app-one/src/pages/page-two.tsx",
    "content": "import React from 'react';\n\ninterface PageTwoProps {\n\n}\n\nconst PageTwo: React.FC<PageTwoProps> = () => {\n  return (\n    <div>Page Two</div>\n  );\n};\n\nexport default PageTwo;\n"
  },
  {
    "path": "examples/multiply-micro-app/micro-app-one/src/routes.ts",
    "content": "import { RouteConfig } from 'react-router-config';\nimport PageOne from './pages/page-one';\nimport Home from './pages/home';\nimport PageTwo from './pages/page-two';\n\nexport const routes: RouteConfig[] = [\n  {\n    component: Home,\n    routes: [\n      {\n        path: '/',\n        exact: true,\n        component: PageOne,\n      },\n      {\n        path: '/page-one',\n        component: PageOne,\n      },\n      {\n        path: '/page-two',\n        component: PageTwo,\n      },\n    ],\n  },\n];\n"
  },
  {
    "path": "examples/multiply-micro-app/micro-app-one/src/types/global.d.ts",
    "content": "declare global {\n  interface Window {\n    __POWERED_BY_QIANKUN__: boolean;\n    __REACT_DEVTOOLS_GLOBAL_HOOK__: any;\n  }\n}\n\n\nexport {};\n"
  },
  {
    "path": "examples/multiply-micro-app/micro-app-one/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"target\": \"ES5\",\n    \"module\": \"CommonJS\",\n    \"baseUrl\": \"src\",\n    \"lib\": [\n      \"dom\",\n      \"dom.iterable\",\n      \"esnext\"\n    ],\n    \"paths\": {\n      \"~src/*\": [\n        \"./*\"\n      ]\n    },\n    \"types\": [\n      \"node\"\n    ],\n    \"allowJs\": true,\n    \"skipLibCheck\": true,\n    \"esModuleInterop\": true,\n    \"moduleResolution\": \"node\",\n    \"resolveJsonModule\": true,\n    \"isolatedModules\": false,\n    \"noEmit\": true,\n    \"experimentalDecorators\": true,\n    \"jsx\": \"preserve\",\n    \"downlevelIteration\": true\n  },\n  \"include\": [\n    \"src\"\n  ]\n}\n"
  },
  {
    "path": "examples/multiply-micro-app/micro-app-two/.eslintrc.js",
    "content": "module.exports = {\n  root: true,\n  env: {\n    browser: true,\n    es2021: true,\n    node: true,\n    jest: true,\n  },\n  extends: ['airbnb-base', 'prettier'],\n  parser: '@typescript-eslint/parser',\n  parserOptions: {\n    ecmaVersion: 12,\n    sourceType: 'module',\n  },\n  plugins: ['@typescript-eslint', 'import'],\n  rules: {\n    'semi': 'error',\n    'no-unused-vars': 'off',\n    '@typescript-eslint/no-unused-vars': ['error'],\n    'import/extensions': 'off',\n    'import/prefer-default-export': 'off',\n    'object-curly-newline': 'off',\n    'class-methods-use-this': 'off',\n    'no-shadow': 'off',\n    'no-console': 'off',\n    'arrow-body-style': 'off',\n    'no-useless-constructor': 'off',\n    'import/no-extraneous-dependencies': 'off',\n    'no-undef': 'off',\n    'object-shorthand': 'off',\n    'no-await-in-loop': 'off',\n    'consistent-return': 'off',\n    'no-restricted-syntax': 'off',\n    'prefer-destructuring': 'off',\n    'func-names': 'off',\n    'global-require': 'off',\n    'import/no-unresolved': 'off',\n    'no-underscore-dangle': 'off',\n    'no-use-before-define': 'off'\n  },\n  settings: {\n    'import/parsers': {\n      '@typescript-eslint/parser': ['.ts', '.tsx'],\n    },\n    'import/resolver': {\n      typescript: {\n        alwaysTryTypes: true,\n      },\n    },\n  },\n};\n"
  },
  {
    "path": "examples/multiply-micro-app/micro-app-two/.gitignore",
    "content": "# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.\n\n# dependencies\n/node_modules\n/.pnp\n.pnp.js\n\n# testing\n/coverage\n\n# production\n/build\ndist\n\n\n# IDE Config\n.idea\n\n# misc\n.DS_Store\n.env.local\n.env.development.local\n.env.test.local\n.env.production.local\n\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\n\n# tmp files\npublic/static\n\n.cache\n\n# 本地生成的类型定义文件\nsrc/types/mf-remotes\n\n# 模块提供者打包生成的类型定义\npublic/mf-expose/types\n"
  },
  {
    "path": "examples/multiply-micro-app/micro-app-two/.prettierrc.json",
    "content": "{\n  \"tabWidth\": 2,\n  \"semi\": false,\n  \"singleQuote\": true,\n  \"jsxBracketSameLine\": true\n}\n"
  },
  {
    "path": "examples/multiply-micro-app/micro-app-two/app-config.ts",
    "content": "import { MicroAppConfig } from '@mf-lite/core/lib/node/micro-fe-app-config';\n\nconst config: MicroAppConfig = {\n  name: 'micro_app_two',\n  url: 'http://localhost:10001/',\n  exposes: [],\n  remotes: [\n    {\n      name: 'base_app',\n      url: 'http://localhost:8080/',\n      sharedLibraries: [\n        'react',\n        'react-dom',\n        'react/jsx-dev-runtime',\n        'react-router',\n        'react-router-dom',\n        'react-router-config'\n      ]\n    },\n    {\n      name: 'micro_app_one',\n      url: 'http://localhost:10000/'\n    }\n  ]\n};\n\nexport default config;\n"
  },
  {
    "path": "examples/multiply-micro-app/micro-app-two/package.json",
    "content": "{\n  \"name\": \"micro-app-two\",\n  \"version\": \"0.0.1\",\n  \"main\": \"index.js\",\n  \"license\": \"MIT\",\n  \"devDependencies\": {\n    \"@attachments/proxy\": \"^0.1.0\",\n    \"@types/fs-extra\": \"^9.0.12\",\n    \"@types/node\": \"^16.4.6\",\n    \"@types/react\": \"^17.0.18\",\n    \"@types/react-dom\": \"^17.0.9\",\n    \"@types/react-router\": \"^5.1.16\",\n    \"@types/react-router-config\": \"^5.0.3\",\n    \"@types/react-router-dom\": \"^5.1.8\",\n    \"@typescript-eslint/eslint-plugin\": \"^4.28.5\",\n    \"@typescript-eslint/parser\": \"^4.28.5\",\n    \"autoprefixer\": \"^10.3.6\",\n    \"concurrently\": \"^6.3.0\",\n    \"cross-env\": \"^7.0.3\",\n    \"eslint\": \"^7.31.0\",\n    \"eslint-config-airbnb\": \"^18.2.1\",\n    \"eslint-config-prettier\": \"^8.1.0\",\n    \"eslint-import-resolver-typescript\": \"^2.4.0\",\n    \"eslint-plugin-import\": \"^2.22.1\",\n    \"eslint-plugin-prettier\": \"^3.3.1\",\n    \"react-router-config\": \"^5.1.1\",\n    \"rimraf\": \"^3.0.2\",\n    \"ts-node\": \"^10.2.1\",\n    \"typescript\": \"^4.3.5\",\n    \"webpack-merge\": \"^5.8.0\"\n  },\n  \"scripts\": {\n    \"dev:proxy\": \"ts-node scripts/proxy.ts\",\n    \"dev:serve\": \"cross-env NODE_ENV=development mf-lite serve --port=10001 --app-type=micro-app\",\n    \"build:dev\": \"rimraf dist && cross-env NODE_ENV=development mf-lite build --app-type=micro-app\",\n    \"build:prod\": \"rimraf dist && cross-env NODE_ENV=production mf-lite build --app-type=micro-app\",\n    \"lint\": \"eslint --ext js,jsx,ts,tsx src\",\n    \"generate\": \"mf-lite generate\",\n    \"upgrade\": \"mf-lite upgrade\"\n  },\n  \"dependencies\": {\n    \"@mf-lite/cli\": \"^0.1.0\",\n    \"@mf-lite/core\": \"^0.1.0\",\n    \"@attachments/utils\": \"^0.1.15\",\n    \"react\": \"^17.0.2\",\n    \"react-dom\": \"^17.0.2\",\n    \"react-router\": \"^5.2.1\",\n    \"react-router-dom\": \"^5.2.1\"\n  }\n}\n"
  },
  {
    "path": "examples/multiply-micro-app/micro-app-two/public/index.html",
    "content": "<!DOCTYPE html>\n<html lang='en'>\n<head>\n  <meta charset='UTF-8'>\n  <title>micro-app-two</title>\n</head>\n<body>\n<div id='micro-app-two'></div>\n</body>\n</html>\n"
  },
  {
    "path": "examples/multiply-micro-app/micro-app-two/public/mf-expose-types/exposes.d.ts",
    "content": ""
  },
  {
    "path": "examples/multiply-micro-app/micro-app-two/scripts/proxy.ts",
    "content": "import { ProxyServer } from '@attachments/proxy';\n\nconst runProxy = async () => {\n  const server = new ProxyServer();\n\n  // micro app 代理\n  server.addRule(\n    'mf-lite-quick-start-micro-app.vercel.app',\n    {\n      location: '/',\n      proxyPass: 'http://localhost:10000',\n    }\n  );\n\n  await server.initServers();\n  await server.listen();\n};\n\nrunProxy().catch(e => {\n  console.log(e);\n});\n"
  },
  {
    "path": "examples/multiply-micro-app/micro-app-two/src/app.tsx",
    "content": "import React from 'react';\nimport ReactDOM from 'react-dom';\nimport { BrowserRouter } from 'react-router-dom';\nimport { renderRoutes } from 'react-router-config';\nimport './init-common';\nimport { routes } from './routes';\n\n\nconst App: React.FC = () => {\n  return (\n    <BrowserRouter>\n      {renderRoutes(routes)}\n    </BrowserRouter>\n  );\n};\n\nexport const render = () => {\n  const el = document.getElementById('micro-app-two');\n  if (el) {\n    ReactDOM.render(<App />, el);\n  }\n};\n\nexport const destroy = () => {\n  const el = document.getElementById('micro-app-two');\n  if (el) {\n    ReactDOM.unmountComponentAtNode(el);\n  }\n};\n"
  },
  {
    "path": "examples/multiply-micro-app/micro-app-two/src/index.tsx",
    "content": "const App = import('./app');\n\nconst render = () => {\n  App.then(res => res.render());\n};\n\nif (!window.__POWERED_BY_QIANKUN__) {\n  render();\n}\n\n/**\n * bootstrap 只会在微应用初始化的时候调用一次，下次微应用重新进入时会直接调用 mount 钩子，不会再重复触发 bootstrap。\n * 通常我们可以在这里做一些全局变量的初始化，比如不会在 unmount 阶段被销毁的应用级别的缓存等。\n */\nexport async function bootstrap() {\n  return 0;\n}\n\n\n/**\n * 应用每次进入都会调用 mount 方法，通常我们在这里触发应用的渲染方法\n */\nexport async function mount() {\n  render();\n}\n\n/**\n * 应用每次 切出/卸载 会调用的方法，通常在这里我们会卸载微应用的应用实例\n */\nexport async function unmount() {\n  App.then(res => res.destroy());\n}\n\n/**\n * 可选生命周期钩子，仅使用 loadMicroApp 方式加载微应用时生效\n */\nexport async function update() {\n  render();\n}\n"
  },
  {
    "path": "examples/multiply-micro-app/micro-app-two/src/init-common.ts",
    "content": "// @ts-ignore\nimport { injectBaseReactRefresh } from '@mf-lite/core/esm/browser/inject-base-react-refresh';\n\nif (process.env.NODE_ENV === 'development') {\n  injectBaseReactRefresh();\n}\n"
  },
  {
    "path": "examples/multiply-micro-app/micro-app-two/src/pages/home.less",
    "content": ".react-app-home {\n  .button-wrapper {\n    margin-bottom: 20px;\n  }\n\n  .home-content {\n    font-size: 20px;\n  }\n}\n"
  },
  {
    "path": "examples/multiply-micro-app/micro-app-two/src/pages/home.tsx",
    "content": "import React, { useState } from 'react';\nimport { renderRoutes } from 'react-router-config';\nimport { RouteComponentProps } from 'react-router';\nimport './home.less';\n\ninterface HomeProps extends RouteComponentProps {\n\n}\n\nconst Home: React.FC<HomeProps> = (props) => {\n  // @ts-ignore\n  const { route, history, location } = props;\n  const [currentPage, setCurrentPage] = useState<'one' | 'two'>(\n    location.pathname === '/page-two' ? 'two' : 'one'\n  );\n\n  const handleButtonClick = () => {\n    const nextPage = currentPage === 'one' ? 'two' : 'one';\n    setCurrentPage(nextPage);\n    history.push(`page-${nextPage}`);\n  };\n\n  return (\n    <div className={'react-app-home'}>\n      <div className={'button-wrapper'}>\n        <button className={'button'} onClick={() => handleButtonClick()}>\n          {`We are at page ${currentPage}, click to change!`}\n        </button>\n      </div>\n      <div className={'home-content'}>\n        {renderRoutes(route.routes)}\n      </div>\n    </div>\n  );\n};\n\nexport default Home;\n"
  },
  {
    "path": "examples/multiply-micro-app/micro-app-two/src/pages/page-one.tsx",
    "content": "import React from 'react';\n\ninterface ProfileProps {\n\n}\n\nconst PageOne: React.FC<ProfileProps> = () => {\n  return (\n    <div>\n      我是第二个微应用\n    </div>\n  );\n};\n\nexport default PageOne;\n"
  },
  {
    "path": "examples/multiply-micro-app/micro-app-two/src/pages/page-two.tsx",
    "content": "import React from 'react';\n\ninterface PageTwoProps {\n\n}\n\nconst PageTwo: React.FC<PageTwoProps> = () => {\n  return (\n    <div>Page Two</div>\n  );\n};\n\nexport default PageTwo;\n"
  },
  {
    "path": "examples/multiply-micro-app/micro-app-two/src/routes.ts",
    "content": "import { RouteConfig } from 'react-router-config';\nimport PageOne from './pages/page-one';\nimport Home from './pages/home';\nimport PageTwo from './pages/page-two';\n\nexport const routes: RouteConfig[] = [\n  {\n    component: Home,\n    routes: [\n      {\n        path: '/',\n        exact: true,\n        component: PageOne,\n      },\n      {\n        path: '/page-one',\n        component: PageOne,\n      },\n      {\n        path: '/page-two',\n        component: PageTwo,\n      },\n    ],\n  },\n];\n"
  },
  {
    "path": "examples/multiply-micro-app/micro-app-two/src/types/global.d.ts",
    "content": "declare global {\n  interface Window {\n    __POWERED_BY_QIANKUN__: boolean;\n    __REACT_DEVTOOLS_GLOBAL_HOOK__: any;\n  }\n}\n\n\nexport {};\n"
  },
  {
    "path": "examples/multiply-micro-app/micro-app-two/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"target\": \"ES5\",\n    \"module\": \"CommonJS\",\n    \"baseUrl\": \"src\",\n    \"lib\": [\n      \"dom\",\n      \"dom.iterable\",\n      \"esnext\"\n    ],\n    \"paths\": {\n      \"~src/*\": [\n        \"./*\"\n      ]\n    },\n    \"types\": [\n      \"node\"\n    ],\n    \"allowJs\": true,\n    \"skipLibCheck\": true,\n    \"esModuleInterop\": true,\n    \"moduleResolution\": \"node\",\n    \"resolveJsonModule\": true,\n    \"isolatedModules\": false,\n    \"noEmit\": true,\n    \"experimentalDecorators\": true,\n    \"jsx\": \"preserve\",\n    \"downlevelIteration\": true\n  },\n  \"include\": [\n    \"src\"\n  ]\n}\n"
  },
  {
    "path": "examples/multiply-micro-app/package.json",
    "content": "{\n  \"name\": \"micro-app-share\",\n  \"version\": \"1.0.0\",\n  \"main\": \"index.js\",\n  \"scripts\": {\n    \"start-all\": \"npx concurrently \\\"yarn:dev:*\\\" --prefix-colors dim\",\n    \"dev:start-base-app\": \"cd base-app && yarn dev:serve\",\n    \"dev:start-micro-app-one\": \"cd micro-app-one && yarn dev:serve\",\n    \"dev:start-micro-app-two\": \"cd micro-app-two && yarn dev:serve\"\n  }\n}\n"
  },
  {
    "path": "examples/quick-start/README.md",
    "content": "# Example: Quick Start\n\n最简单的项目 DEMO，开箱即用，全部在本地运行开发。\n\n## Usage\n\n### 基本的开发环境\n\n启动基座应用和微应用：\n\n```shell\nyarn start-all\n```\n\n进入 `localhost:8080` 查看效果。\n\n### 子应用生成父应用模块共享的类型定义\n\n```shell\ncd micro-app\n\nyarn generate\n```\n\n接着检查微应用的 types/mf-remotes 下类型定义是否生成，其内容如下：\n\n```typescript\n// module name: base_app/shared-utils\n\ndeclare module 'base_app/shared-utils' {\n  export const add: (a: number, b: number) => number;\n  export const sayHello: () => void;\n  export default add;\n  export {};\n}\n```\n\n### 在子应用中调用父应用暴露出来的模块\n\n```typescript\nimport { sayHello } from 'base_app/shared-utils';\n\nsayHello() // hello world\n```\n\n### 打包\n\n```shell\n# 开发环境下打包\nyarn build:dev\n\n# 生产环境下打包\nyarn build:prod\n```\n"
  },
  {
    "path": "examples/quick-start/base-app/.eslintrc.js",
    "content": "module.exports = {\n  root: true,\n  env: {\n    browser: true,\n    es2021: true,\n    node: true,\n    jest: true,\n  },\n  extends: ['airbnb-base', 'prettier'],\n  parser: '@typescript-eslint/parser',\n  parserOptions: {\n    ecmaVersion: 12,\n    sourceType: 'module',\n  },\n  plugins: ['@typescript-eslint', 'import'],\n  rules: {\n    'semi': 'error',\n    'no-unused-vars': 'off',\n    '@typescript-eslint/no-unused-vars': ['error'],\n    'import/extensions': 'off',\n    'import/prefer-default-export': 'off',\n    'object-curly-newline': 'off',\n    'class-methods-use-this': 'off',\n    'no-shadow': 'off',\n    'no-console': 'off',\n    'arrow-body-style': 'off',\n    'no-useless-constructor': 'off',\n    'import/no-extraneous-dependencies': 'off',\n    'no-undef': 'off',\n    'object-shorthand': 'off',\n    'no-await-in-loop': 'off',\n    'consistent-return': 'off',\n    'no-restricted-syntax': 'off',\n    'prefer-destructuring': 'off',\n    'func-names': 'off',\n    'global-require': 'off',\n    'import/no-unresolved': 'off',\n    'no-underscore-dangle': 'off',\n    'no-use-before-define': 'off'\n  },\n  settings: {\n    'import/parsers': {\n      '@typescript-eslint/parser': ['.ts', '.tsx'],\n    },\n    'import/resolver': {\n      typescript: {\n        alwaysTryTypes: true,\n      },\n    },\n  },\n};\n"
  },
  {
    "path": "examples/quick-start/base-app/.gitignore",
    "content": "# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.\n\n# dependencies\n/node_modules\n/.pnp\n.pnp.js\n\n# testing\n/coverage\n\n# production\n/build\ndist\n\n\n# IDE Config\n.idea\n\n# misc\n.DS_Store\n.env.local\n.env.development.local\n.env.test.local\n.env.production.local\n\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\n\n# tmp files\npublic/static\n\n.cache\n\n# 本地生成的类型定义文件\nsrc/types/mf-remotes\n\n# 模块提供者打包生成的类型定义\npublic/mf-expose/types\n"
  },
  {
    "path": "examples/quick-start/base-app/.prettierrc.json",
    "content": "{\n  \"tabWidth\": 2,\n  \"semi\": false,\n  \"singleQuote\": true,\n  \"jsxBracketSameLine\": true\n}\n"
  },
  {
    "path": "examples/quick-start/base-app/app-config.ts",
    "content": "import * as path from 'path';\nimport { MicroAppConfig } from '@mf-lite/core/lib/node/micro-fe-app-config';\nimport { sourcePath } from '@mf-lite/core/lib/common/paths';\n\nconst config: MicroAppConfig = {\n  remotes: [],\n  name: 'base_app',\n  url: 'http://localhost:8080/',\n  exposes: [\n    'react',\n    'react-dom',\n    'react-router',\n    'react-router-dom',\n    'react-router-config',\n    'react/jsx-dev-runtime',\n    'antd',\n    {\n      name: 'shared-utils',\n      path: path.resolve(sourcePath, 'utils', 'shared-utils.ts'),\n      type: 'module'\n    }\n  ]\n};\n\nexport default config;\n"
  },
  {
    "path": "examples/quick-start/base-app/package.json",
    "content": "{\n  \"name\": \"base-app\",\n  \"version\": \"0.0.1\",\n  \"main\": \"index.js\",\n  \"license\": \"MIT\",\n  \"devDependencies\": {\n    \"@attachments/proxy\": \"^0.1.0\",\n    \"@types/fs-extra\": \"^9.0.12\",\n    \"@types/node\": \"^16.4.6\",\n    \"@types/react\": \"^17.0.18\",\n    \"@types/react-dom\": \"^17.0.9\",\n    \"@types/react-router\": \"^5.1.16\",\n    \"@types/react-router-config\": \"^5.0.3\",\n    \"@types/react-router-dom\": \"^5.1.8\",\n    \"@typescript-eslint/eslint-plugin\": \"^4.28.5\",\n    \"@typescript-eslint/parser\": \"^4.28.5\",\n    \"autoprefixer\": \"^10.3.6\",\n    \"concurrently\": \"^6.3.0\",\n    \"cross-env\": \"^7.0.3\",\n    \"eslint\": \"^7.31.0\",\n    \"eslint-config-airbnb\": \"^18.2.1\",\n    \"eslint-config-prettier\": \"^8.1.0\",\n    \"eslint-import-resolver-typescript\": \"^2.4.0\",\n    \"eslint-plugin-import\": \"^2.22.1\",\n    \"eslint-plugin-prettier\": \"^3.3.1\",\n    \"react-router-config\": \"^5.1.1\",\n    \"rimraf\": \"^3.0.2\",\n    \"ts-node\": \"^10.2.1\",\n    \"typescript\": \"^4.3.5\",\n    \"webpack-merge\": \"^5.8.0\"\n  },\n  \"scripts\": {\n    \"dev:proxy\": \"ts-node scripts/proxy.ts\",\n    \"dev:serve\": \"cross-env NODE_ENV=development mf-lite serve --port=8080 --app-type=base-app\",\n    \"build:dev\": \"rimraf dist && cross-env NODE_ENV=development mf-lite build --app-type=base-app\",\n    \"build:prod\": \"rimraf dist && cross-env NODE_ENV=production mf-lite build --app-type=base-app\",\n    \"lint\": \"eslint --ext js,jsx,ts,tsx src\",\n    \"generate\": \"mf-lite generate\",\n    \"upgrade\": \"mf-lite upgrade\"\n  },\n  \"dependencies\": {\n    \"@mf-lite/cli\": \"^0.1.0\",\n    \"@mf-lite/core\": \"^0.1.0\",\n    \"@attachments/utils\": \"^0.1.15\",\n    \"antd\": \"^4.16.13\",\n    \"react\": \"^17.0.2\",\n    \"react-dom\": \"^17.0.2\",\n    \"react-router\": \"^5.2.1\",\n    \"react-router-dom\": \"^5.2.1\"\n  }\n}\n"
  },
  {
    "path": "examples/quick-start/base-app/public/index.html",
    "content": "<!DOCTYPE html>\n<html lang='en'>\n<head>\n  <meta charset='UTF-8'>\n  <title>base-app</title>\n</head>\n<body>\n<div id='base-app'></div>\n</body>\n</html>\n"
  },
  {
    "path": "examples/quick-start/base-app/public/mf-expose-types/exposes.d.ts",
    "content": "// module name: base_app/shared-utils\n\ndeclare module 'base_app/shared-utils' {\n    export const add: (a: number, b: number) => number;\n    export const sayHello: () => void;\n    export default add;\n    export { };\n}\n\n"
  },
  {
    "path": "examples/quick-start/base-app/scripts/proxy.ts",
    "content": "import { ProxyServer } from '@attachments/proxy';\n\nconst runProxy = async () => {\n  const server = new ProxyServer();\n\n  // 基座代理，将 base-app.vercel.app 的所有请求代理到 http://localhost:8080\n  server.addRule(\n    'base-app.vercel.app',\n    {\n      location: '/',\n      proxyPass: 'http://localhost:8080',\n    }\n  );\n\n  await server.initServers();\n  await server.listen();\n};\n\nrunProxy().catch(e => {\n  console.log(e);\n});\n"
  },
  {
    "path": "examples/quick-start/base-app/src/app.tsx",
    "content": "import ReactDOM from 'react-dom';\nimport { BrowserRouter } from 'react-router-dom';\nimport React, { Suspense } from 'react';\nimport { renderRoutes } from 'react-router-config';\nimport { routes } from '~src/routes';\nimport './utils/init-common';\nimport 'antd/dist/antd.less';\nimport '@attachments/utils/src/browser/css/common.css';\n\nconst App = () => {\n  return (\n    <Suspense fallback={null}>\n      <BrowserRouter>\n        {renderRoutes(routes)}\n      </BrowserRouter>\n    </Suspense>\n  );\n};\n\n\nconst reactRenderer = () => {\n  ReactDOM.render((\n    <BrowserRouter>\n      <App />\n    </BrowserRouter>\n  ), document.getElementById('base-app'));\n};\n\nconst beforeAppStart = async () => {\n  return true;\n};\n\nbeforeAppStart()\n  .then(() => {\n    reactRenderer();\n  });\n\n\n"
  },
  {
    "path": "examples/quick-start/base-app/src/common/const.ts",
    "content": "export interface MicroAppConfig {\n  name: string;\n  url: string;\n}\n\nexport const MICRO_APPS: MicroAppConfig[] = [\n  {\n    name: 'micro-app',\n    url: 'http://localhost:10000/',\n  },\n];\n"
  },
  {
    "path": "examples/quick-start/base-app/src/index.tsx",
    "content": "import ('./app');\n\n"
  },
  {
    "path": "examples/quick-start/base-app/src/pages/home.less",
    "content": ".base-app-home {\n  .title {\n    font-size: 16px;\n    margin-bottom: 20px;\n  }\n\n  .content {\n    border: 1px solid;\n    padding: 10px;\n    min-height: 100px;\n  }\n}\n"
  },
  {
    "path": "examples/quick-start/base-app/src/pages/home.tsx",
    "content": "import React from 'react';\nimport './home.less';\nimport { createMicroApp } from '~src/utils/create-micro-app';\n\ninterface HomeProps {\n\n}\n\nconst Home: React.FC<HomeProps> = () => {\n  return (\n    <div className={'base-app-home'}>\n      <div className={'title'}>\n        🎉 This is Base App home page, the micro app will be rendered below! 🎉\n      </div>\n      <div className={'content'}>\n        {createMicroApp('micro-app')()}\n      </div>\n    </div>\n  );\n};\n\nexport default Home;\n"
  },
  {
    "path": "examples/quick-start/base-app/src/routes.ts",
    "content": "import { RouteConfig } from 'react-router-config';\nimport Home from './pages/home';\n\nexport const routes: RouteConfig[] = [\n  {\n    component: Home,\n    routes: [],\n  },\n];\n"
  },
  {
    "path": "examples/quick-start/base-app/src/types/global.d.ts",
    "content": "declare module '*.module.css';\ndeclare module '*.module.sass';\ndeclare module '*.module.scss';\n\n\ndeclare global {\n  const __APP_VERSION__: string;\n  const __MODE__: string;\n  const __BUILD_TIME__: string;\n\n  interface Window {\n    __POWERED_BY_QIANKUN__: boolean;\n  }\n}\n\n\nexport {};\n\n"
  },
  {
    "path": "examples/quick-start/base-app/src/utils/create-micro-app.tsx",
    "content": "import React, { useEffect, useRef } from 'react';\nimport { MicroApp, MicroAppRef } from '@mf-lite/core/esm/browser/micro-app';\nimport { MICRO_APPS, MicroAppConfig } from '~src/common/const';\n\n\nexport const getMicroApp = (name: string): MicroAppConfig => {\n  const item = MICRO_APPS.find(res => res.name === name);\n  if (!item) {\n    throw new Error(`the micro app ${name} is not exist!`);\n  }\n  return item;\n};\n\n\nexport const createMicroApp = (name: string) => {\n  return () => {\n    const ref = useRef<MicroAppRef>(null);\n\n    const microAppConfig = {\n      name: name,\n      entry: getMicroApp(name).url,\n    }\n\n    useEffect(() => {\n      if (ref.current?.appStore) {\n        ref.current?.appStore.microApp?.loadPromise\n          .then(() => {\n            console.log('micro app loaded!');\n          });\n      }\n    }, []);\n\n    return (\n      <MicroApp\n        ref={ref}\n        microAppConfig={microAppConfig} />\n    );\n  };\n};\n"
  },
  {
    "path": "examples/quick-start/base-app/src/utils/init-common.ts",
    "content": "/**\n * File: init-common.ts\n * Description: 项目全局初始化\n * Created: 2021-09-28 21:51:34\n * Author: yuzhanglong\n * Email: yuzl1123@163.com\n */\n\n// patch 基座的 react-refresh\nimport { consoleTag } from '@attachments/utils/esm/browser/console-tag';\n\nconsoleTag(\n  {\n    key: 'MODE',\n    value: __MODE__,\n  },\n  {\n    key: 'VERSION',\n    value: __APP_VERSION__,\n    valueColor: '#409eff',\n  },\n  {\n    key: 'BUILD_TIME',\n    value: __BUILD_TIME__,\n    valueColor: '#ea7b27',\n  },\n);\n"
  },
  {
    "path": "examples/quick-start/base-app/src/utils/shared-utils.ts",
    "content": "export const add = (a: number, b: number) => {\n  return a + b;\n};\n\nexport const sayHello = () => {\n  console.log('hello world!');\n};\n\nexport default add;\n"
  },
  {
    "path": "examples/quick-start/base-app/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"target\": \"ES5\",\n    \"module\": \"CommonJS\",\n    \"baseUrl\": \"src\",\n    \"lib\": [\n      \"dom\",\n      \"dom.iterable\",\n      \"esnext\"\n    ],\n    \"paths\": {\n      \"~src/*\": [\n        \"./*\"\n      ]\n    },\n    \"types\": [\n      \"node\"\n    ],\n    \"allowJs\": true,\n    \"skipLibCheck\": true,\n    \"esModuleInterop\": true,\n    \"moduleResolution\": \"node\",\n    \"resolveJsonModule\": true,\n    \"isolatedModules\": false,\n    \"noEmit\": true,\n    \"experimentalDecorators\": true,\n    \"jsx\": \"preserve\",\n    \"downlevelIteration\": true\n  },\n  \"include\": [\n    \"src\"\n  ]\n}\n"
  },
  {
    "path": "examples/quick-start/micro-app/.eslintrc.js",
    "content": "module.exports = {\n  root: true,\n  env: {\n    browser: true,\n    es2021: true,\n    node: true,\n    jest: true,\n  },\n  extends: ['airbnb-base', 'prettier'],\n  parser: '@typescript-eslint/parser',\n  parserOptions: {\n    ecmaVersion: 12,\n    sourceType: 'module',\n  },\n  plugins: ['@typescript-eslint', 'import'],\n  rules: {\n    'semi': 'error',\n    'no-unused-vars': 'off',\n    '@typescript-eslint/no-unused-vars': ['error'],\n    'import/extensions': 'off',\n    'import/prefer-default-export': 'off',\n    'object-curly-newline': 'off',\n    'class-methods-use-this': 'off',\n    'no-shadow': 'off',\n    'no-console': 'off',\n    'arrow-body-style': 'off',\n    'no-useless-constructor': 'off',\n    'import/no-extraneous-dependencies': 'off',\n    'no-undef': 'off',\n    'object-shorthand': 'off',\n    'no-await-in-loop': 'off',\n    'consistent-return': 'off',\n    'no-restricted-syntax': 'off',\n    'prefer-destructuring': 'off',\n    'func-names': 'off',\n    'global-require': 'off',\n    'import/no-unresolved': 'off',\n    'no-underscore-dangle': 'off',\n    'no-use-before-define': 'off'\n  },\n  settings: {\n    'import/parsers': {\n      '@typescript-eslint/parser': ['.ts', '.tsx'],\n    },\n    'import/resolver': {\n      typescript: {\n        alwaysTryTypes: true,\n      },\n    },\n  },\n};\n"
  },
  {
    "path": "examples/quick-start/micro-app/.gitignore",
    "content": "# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.\n\n# dependencies\n/node_modules\n/.pnp\n.pnp.js\n\n# testing\n/coverage\n\n# production\n/build\ndist\n\n\n# IDE Config\n.idea\n\n# misc\n.DS_Store\n.env.local\n.env.development.local\n.env.test.local\n.env.production.local\n\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\n\n# tmp files\npublic/static\n\n.cache\n\n# 本地生成的类型定义文件\nsrc/types/mf-remotes\n\n# 模块提供者打包生成的类型定义\npublic/mf-expose/types\n"
  },
  {
    "path": "examples/quick-start/micro-app/.prettierrc.json",
    "content": "{\n  \"tabWidth\": 2,\n  \"semi\": false,\n  \"singleQuote\": true,\n  \"jsxBracketSameLine\": true\n}\n"
  },
  {
    "path": "examples/quick-start/micro-app/app-config.ts",
    "content": "import { MicroAppConfig } from '@mf-lite/core/lib/node/micro-fe-app-config';\n\nconst config: MicroAppConfig = {\n  name: 'micro_app',\n  url: 'http://localhost:10000/',\n  exposes: [],\n  remotes: [\n    {\n      name: 'base_app',\n      url: 'http://localhost:8080/',\n      sharedLibraries: [\n        'react',\n        'react-dom',\n        'react/jsx-dev-runtime',\n        'react-router',\n        'react-router-dom',\n        'react-router-config'\n      ]\n    }\n  ]\n};\n\nexport default config;\n"
  },
  {
    "path": "examples/quick-start/micro-app/package.json",
    "content": "{\n  \"name\": \"micro-app\",\n  \"version\": \"0.0.1\",\n  \"main\": \"index.js\",\n  \"license\": \"MIT\",\n  \"devDependencies\": {\n    \"@attachments/proxy\": \"^0.1.0\",\n    \"@types/fs-extra\": \"^9.0.12\",\n    \"@types/node\": \"^16.4.6\",\n    \"@types/react\": \"^17.0.18\",\n    \"@types/react-dom\": \"^17.0.9\",\n    \"@types/react-router\": \"^5.1.16\",\n    \"@types/react-router-config\": \"^5.0.3\",\n    \"@types/react-router-dom\": \"^5.1.8\",\n    \"@typescript-eslint/eslint-plugin\": \"^4.28.5\",\n    \"@typescript-eslint/parser\": \"^4.28.5\",\n    \"autoprefixer\": \"^10.3.6\",\n    \"concurrently\": \"^6.3.0\",\n    \"cross-env\": \"^7.0.3\",\n    \"eslint\": \"^7.31.0\",\n    \"eslint-config-airbnb\": \"^18.2.1\",\n    \"eslint-config-prettier\": \"^8.1.0\",\n    \"eslint-import-resolver-typescript\": \"^2.4.0\",\n    \"eslint-plugin-import\": \"^2.22.1\",\n    \"eslint-plugin-prettier\": \"^3.3.1\",\n    \"react-router-config\": \"^5.1.1\",\n    \"rimraf\": \"^3.0.2\",\n    \"ts-node\": \"^10.2.1\",\n    \"typescript\": \"^4.3.5\",\n    \"webpack-merge\": \"^5.8.0\"\n  },\n  \"scripts\": {\n    \"dev:proxy\": \"ts-node scripts/proxy.ts\",\n    \"dev:serve\": \"cross-env NODE_ENV=development mf-lite serve --port=10000 --app-type=micro-app\",\n    \"build:dev\": \"rimraf dist && cross-env NODE_ENV=development mf-lite build --app-type=micro-app\",\n    \"build:prod\": \"rimraf dist && cross-env NODE_ENV=production mf-lite build --app-type=micro-app\",\n    \"lint\": \"eslint --ext js,jsx,ts,tsx src\",\n    \"generate\": \"mf-lite generate\",\n    \"upgrade\": \"mf-lite upgrade\"\n  },\n  \"dependencies\": {\n    \"@mf-lite/cli\": \"^0.1.0\",\n    \"@mf-lite/core\": \"^0.1.0\",\n    \"@attachments/utils\": \"^0.1.15\",\n    \"antd\": \"^4.16.13\",\n    \"react\": \"^17.0.2\",\n    \"react-dom\": \"^17.0.2\",\n    \"react-router\": \"^5.2.1\",\n    \"react-router-dom\": \"^5.2.1\"\n  }\n}\n"
  },
  {
    "path": "examples/quick-start/micro-app/public/index.html",
    "content": "<!DOCTYPE html>\n<html lang='en'>\n<head>\n  <meta charset='UTF-8'>\n  <title>micro-app</title>\n</head>\n<body>\n<div id='micro-app'></div>\n</body>\n</html>\n"
  },
  {
    "path": "examples/quick-start/micro-app/public/mf-expose-types/exposes.d.ts",
    "content": ""
  },
  {
    "path": "examples/quick-start/micro-app/scripts/proxy.ts",
    "content": "import { ProxyServer } from '@attachments/proxy';\n\nconst runProxy = async () => {\n  const server = new ProxyServer();\n\n  // micro app 代理\n  server.addRule(\n    'mf-lite-quick-start-micro-app.vercel.app',\n    {\n      location: '/',\n      proxyPass: 'http://localhost:10000',\n    }\n  );\n\n  await server.initServers();\n  await server.listen();\n};\n\nrunProxy().catch(e => {\n  console.log(e);\n});\n"
  },
  {
    "path": "examples/quick-start/micro-app/src/app.tsx",
    "content": "import React from 'react';\nimport ReactDOM from 'react-dom';\nimport { BrowserRouter } from 'react-router-dom';\nimport { renderRoutes } from 'react-router-config';\nimport './init-common';\nimport { Button } from 'antd';\nimport add, { sayHello } from 'base_app/shared-utils';\nimport { routes } from '~src/routes';\n\n\nconst App: React.FC = () => {\n  sayHello();\n  return (\n    <BrowserRouter>\n      <Button type={'primary'}>\n        微应用正在消费子应用的组件\n      </Button>\n      <div>\n        来自基座的 add 方法：{add(1, 2)}\n      </div>\n      {renderRoutes(routes)}\n    </BrowserRouter>\n  );\n};\n\nexport const render = () => {\n  const el = document.getElementById('micro-app');\n  if (el) {\n    ReactDOM.render(<App />, el);\n  }\n};\n\nexport const destroy = () => {\n  const el = document.getElementById('micro-app');\n  if (el) {\n    ReactDOM.unmountComponentAtNode(el);\n  }\n};\n"
  },
  {
    "path": "examples/quick-start/micro-app/src/index.tsx",
    "content": "const App = import('./app');\n\nconst render = () => {\n  App.then(res => res.render());\n};\n\nif (!window.__POWERED_BY_QIANKUN__) {\n  render();\n}\n\n/**\n * bootstrap 只会在微应用初始化的时候调用一次，下次微应用重新进入时会直接调用 mount 钩子，不会再重复触发 bootstrap。\n * 通常我们可以在这里做一些全局变量的初始化，比如不会在 unmount 阶段被销毁的应用级别的缓存等。\n */\nexport async function bootstrap() {\n  return 0;\n}\n\n\n/**\n * 应用每次进入都会调用 mount 方法，通常我们在这里触发应用的渲染方法\n */\nexport async function mount() {\n  render();\n}\n\n/**\n * 应用每次 切出/卸载 会调用的方法，通常在这里我们会卸载微应用的应用实例\n */\nexport async function unmount() {\n  App.then(res => res.destroy());\n}\n\n/**\n * 可选生命周期钩子，仅使用 loadMicroApp 方式加载微应用时生效\n */\nexport async function update() {\n  render();\n}\n"
  },
  {
    "path": "examples/quick-start/micro-app/src/init-common.ts",
    "content": "// @ts-ignore\nimport { injectBaseReactRefresh } from '@mf-lite/core/esm/browser/inject-base-react-refresh';\n\nif (process.env.NODE_ENV === 'development') {\n  injectBaseReactRefresh();\n}\n"
  },
  {
    "path": "examples/quick-start/micro-app/src/pages/home.less",
    "content": ".react-app-home {\n  .button-wrapper {\n    margin-bottom: 20px;\n  }\n\n  .home-content {\n    font-size: 20px;\n  }\n}\n"
  },
  {
    "path": "examples/quick-start/micro-app/src/pages/home.tsx",
    "content": "import React, { useState } from 'react';\nimport { renderRoutes } from 'react-router-config';\nimport { RouteComponentProps } from 'react-router';\nimport './home.less';\n\ninterface HomeProps extends RouteComponentProps {\n\n}\n\nconst Home: React.FC<HomeProps> = (props) => {\n  // @ts-ignore\n  const { route, history, location } = props;\n  const [currentPage, setCurrentPage] = useState<'one' | 'two'>(\n    location.pathname === '/page-two' ? 'two' : 'one'\n  );\n\n  const handleButtonClick = () => {\n    const nextPage = currentPage === 'one' ? 'two' : 'one';\n    setCurrentPage(nextPage);\n    history.push(`page-${nextPage}`);\n  };\n\n  return (\n    <div className={'react-app-home'}>\n      <div className={'button-wrapper'}>\n        <button className={'button'} onClick={() => handleButtonClick()}>\n          {`We are at page ${currentPage}, click me to change!`}\n        </button>\n      </div>\n      <div className={'home-content'}>\n        {renderRoutes(route.routes)}\n      </div>\n    </div>\n  );\n};\n\nexport default Home;\n"
  },
  {
    "path": "examples/quick-start/micro-app/src/pages/page-one.tsx",
    "content": "import React from 'react';\n\ninterface ProfileProps {\n\n}\n\nconst PageOne: React.FC<ProfileProps> = () => {\n  return (\n    <div>Page One</div>\n  );\n};\n\nexport default PageOne;\n"
  },
  {
    "path": "examples/quick-start/micro-app/src/pages/page-two.tsx",
    "content": "import React from 'react';\n\ninterface PageTwoProps {\n\n}\n\nconst PageTwo: React.FC<PageTwoProps> = () => {\n  return (\n    <div>Page Two</div>\n  );\n};\n\nexport default PageTwo;\n"
  },
  {
    "path": "examples/quick-start/micro-app/src/routes.ts",
    "content": "import { RouteConfig } from 'react-router-config';\nimport PageOne from './pages/page-one';\nimport Home from './pages/home';\nimport PageTwo from './pages/page-two';\n\nexport const routes: RouteConfig[] = [\n  {\n    component: Home,\n    routes: [\n      {\n        path: '/',\n        exact: true,\n        component: PageOne,\n      },\n      {\n        path: '/page-one',\n        component: PageOne,\n      },\n      {\n        path: '/page-two',\n        component: PageTwo,\n      },\n    ],\n  },\n];\n"
  },
  {
    "path": "examples/quick-start/micro-app/src/types/global.d.ts",
    "content": "declare global {\n  interface Window {\n    __POWERED_BY_QIANKUN__: boolean;\n    __REACT_DEVTOOLS_GLOBAL_HOOK__: any;\n  }\n}\n\n\nexport {};\n"
  },
  {
    "path": "examples/quick-start/micro-app/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"target\": \"ES5\",\n    \"module\": \"CommonJS\",\n    \"baseUrl\": \"src\",\n    \"lib\": [\n      \"dom\",\n      \"dom.iterable\",\n      \"esnext\"\n    ],\n    \"paths\": {\n      \"~src/*\": [\n        \"./*\"\n      ]\n    },\n    \"types\": [\n      \"node\"\n    ],\n    \"allowJs\": true,\n    \"skipLibCheck\": true,\n    \"esModuleInterop\": true,\n    \"moduleResolution\": \"node\",\n    \"resolveJsonModule\": true,\n    \"isolatedModules\": false,\n    \"noEmit\": true,\n    \"experimentalDecorators\": true,\n    \"jsx\": \"preserve\",\n    \"downlevelIteration\": true\n  },\n  \"include\": [\n    \"src\"\n  ]\n}\n"
  },
  {
    "path": "examples/quick-start/package.json",
    "content": "{\n  \"name\": \"quick-start\",\n  \"version\": \"1.0.0\",\n  \"main\": \"index.js\",\n  \"license\": \"MIT\",\n  \"scripts\": {\n    \"start-all\": \"npx concurrently \\\"yarn:dev:*\\\" --prefix-colors dim\",\n    \"dev:start-base-app\": \"cd base-app && yarn dev:serve\",\n    \"dev:start-micro-app-one\": \"cd micro-app && yarn dev:serve\"\n  }\n}\n"
  },
  {
    "path": "examples/remote-deploy/README.md",
    "content": "# Example: Remote Deploy\n\n远程部署案例，远程部署只需要将配置文件中的 url 改成远程 url 即可，之后和常规项目的部署方法是一样的。\n\n远程部署的实践文档请参考文档的[这一小节](https://ph3xmz5sya.feishu.cn/docs/doccnGEPiy8D3DJTZw6S05QJW4f#f7hzk7) 。\n\n\n"
  },
  {
    "path": "examples/remote-deploy/base-app/.eslintrc.js",
    "content": "module.exports = {\n  root: true,\n  env: {\n    browser: true,\n    es2021: true,\n    node: true,\n    jest: true,\n  },\n  extends: ['airbnb-base', 'prettier'],\n  parser: '@typescript-eslint/parser',\n  parserOptions: {\n    ecmaVersion: 12,\n    sourceType: 'module',\n  },\n  plugins: ['@typescript-eslint', 'import'],\n  rules: {\n    'semi': 'error',\n    'no-unused-vars': 'off',\n    '@typescript-eslint/no-unused-vars': ['error'],\n    'import/extensions': 'off',\n    'import/prefer-default-export': 'off',\n    'object-curly-newline': 'off',\n    'class-methods-use-this': 'off',\n    'no-shadow': 'off',\n    'no-console': 'off',\n    'arrow-body-style': 'off',\n    'no-useless-constructor': 'off',\n    'import/no-extraneous-dependencies': 'off',\n    'no-undef': 'off',\n    'object-shorthand': 'off',\n    'no-await-in-loop': 'off',\n    'consistent-return': 'off',\n    'no-restricted-syntax': 'off',\n    'prefer-destructuring': 'off',\n    'func-names': 'off',\n    'global-require': 'off',\n    'import/no-unresolved': 'off',\n    'no-underscore-dangle': 'off',\n    'no-use-before-define': 'off'\n  },\n  settings: {\n    'import/parsers': {\n      '@typescript-eslint/parser': ['.ts', '.tsx'],\n    },\n    'import/resolver': {\n      typescript: {\n        alwaysTryTypes: true,\n      },\n    },\n  },\n};\n"
  },
  {
    "path": "examples/remote-deploy/base-app/.gitignore",
    "content": "# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.\n\n# dependencies\n/node_modules\n/.pnp\n.pnp.js\n\n# testing\n/coverage\n\n# production\n/build\ndist\n\n\n# IDE Config\n.idea\n\n# misc\n.DS_Store\n.env.local\n.env.development.local\n.env.test.local\n.env.production.local\n\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\n\n# tmp files\npublic/static\n\n.cache\n\n# 本地生成的类型定义文件\nsrc/types/mf-remotes\n\n# 模块提供者打包生成的类型定义\npublic/mf-expose/types\n"
  },
  {
    "path": "examples/remote-deploy/base-app/.prettierrc.json",
    "content": "{\n  \"tabWidth\": 2,\n  \"semi\": false,\n  \"singleQuote\": true,\n  \"jsxBracketSameLine\": true\n}\n"
  },
  {
    "path": "examples/remote-deploy/base-app/app-config.ts",
    "content": "import * as path from 'path';\nimport { MicroAppConfig } from '@mf-lite/core/lib/node/micro-fe-app-config';\nimport { sourcePath } from '@mf-lite/core/lib/common/paths';\n\nconst config: MicroAppConfig = {\n  remotes: [],\n  name: 'base_app',\n  url: 'https://mf-lite-quick-start-base-app.vercel.app/',\n  exposes: [\n    'react',\n    'react-dom',\n    'react-router',\n    'react-router-dom',\n    'react-router-config',\n    'react/jsx-dev-runtime',\n    {\n      name: 'shared-utils',\n      path: path.resolve(sourcePath, 'utils', 'shared-utils.ts'),\n      type: 'module',\n    },\n  ],\n};\n\nexport default config;\n"
  },
  {
    "path": "examples/remote-deploy/base-app/package.json",
    "content": "{\n  \"name\": \"base-app\",\n  \"version\": \"0.0.1\",\n  \"main\": \"index.js\",\n  \"license\": \"MIT\",\n  \"devDependencies\": {\n    \"@attachments/proxy\": \"^0.1.15\",\n    \"@types/fs-extra\": \"^9.0.12\",\n    \"@types/node\": \"^16.4.6\",\n    \"@types/react\": \"^17.0.18\",\n    \"@types/react-dom\": \"^17.0.9\",\n    \"@types/react-router\": \"^5.1.16\",\n    \"@types/react-router-config\": \"^5.0.3\",\n    \"@types/react-router-dom\": \"^5.1.8\",\n    \"@typescript-eslint/eslint-plugin\": \"^4.28.5\",\n    \"@typescript-eslint/parser\": \"^4.28.5\",\n    \"autoprefixer\": \"^10.3.6\",\n    \"concurrently\": \"^6.3.0\",\n    \"cross-env\": \"^7.0.3\",\n    \"eslint\": \"^7.31.0\",\n    \"eslint-config-airbnb\": \"^18.2.1\",\n    \"eslint-config-prettier\": \"^8.1.0\",\n    \"eslint-import-resolver-typescript\": \"^2.4.0\",\n    \"eslint-plugin-import\": \"^2.22.1\",\n    \"eslint-plugin-prettier\": \"^3.3.1\",\n    \"react-router-config\": \"^5.1.1\",\n    \"rimraf\": \"^3.0.2\",\n    \"ts-node\": \"^10.2.1\",\n    \"typescript\": \"^4.3.5\",\n    \"webpack-merge\": \"^5.8.0\"\n  },\n  \"scripts\": {\n    \"dev:proxy\": \"ts-node scripts/proxy.ts\",\n    \"dev:serve\": \"cross-env NODE_ENV=development mf-lite serve --port=8080 --app-type=base-app\",\n    \"build:dev\": \"rimraf dist && cross-env NODE_ENV=development mf-lite build --app-type=base-app\",\n    \"build:prod\": \"rimraf dist && cross-env NODE_ENV=production mf-lite build --app-type=base-app\",\n    \"lint\": \"eslint --ext js,jsx,ts,tsx src\",\n    \"generate\": \"mf-lite generate\",\n    \"upgrade\": \"mf-lite upgrade\"\n  },\n  \"dependencies\": {\n    \"@mf-lite/cli\": \"^0.1.0\",\n    \"@mf-lite/core\": \"^0.1.2\",\n    \"@attachments/utils\": \"^0.1.15\",\n    \"react\": \"^17.0.2\",\n    \"react-dom\": \"^17.0.2\",\n    \"react-router\": \"^5.2.1\",\n    \"react-router-dom\": \"^5.2.1\"\n  }\n}\n"
  },
  {
    "path": "examples/remote-deploy/base-app/public/index.html",
    "content": "<!DOCTYPE html>\n<html lang='en'>\n<head>\n  <meta charset='UTF-8'>\n  <title>base-app</title>\n</head>\n<body>\n<div id='base-app'></div>\n</body>\n</html>\n"
  },
  {
    "path": "examples/remote-deploy/base-app/public/mf-expose-types/exposes.d.ts",
    "content": "// module name: base_app/shared-utils\n\ndeclare module 'base_app/shared-utils' {\n    export const add: (a: number, b: number) => number;\n    export const sayHello: () => void;\n    export default add;\n    export { };\n}\n\n"
  },
  {
    "path": "examples/remote-deploy/base-app/scripts/proxy.ts",
    "content": "import { ProxyServer } from '@attachments/proxy';\n\nconst runProxy = async () => {\n  const server = new ProxyServer();\n\n  // 基座代理，将 base-app.vercel.app 的所有请求代理到 http://localhost:8080\n  server.addRule(\n    'base-app.vercel.app',\n    {\n      location: '/',\n      proxyPass: 'http://localhost:8080',\n    }\n  );\n\n  await server.initServers();\n  await server.listen();\n};\n\nrunProxy().catch(e => {\n  console.log(e);\n});\n"
  },
  {
    "path": "examples/remote-deploy/base-app/src/app.tsx",
    "content": "import ReactDOM from 'react-dom';\nimport { BrowserRouter } from 'react-router-dom';\nimport React, { Suspense } from 'react';\nimport { renderRoutes } from 'react-router-config';\nimport { routes } from '~src/routes';\nimport './utils/init-common';\nimport '@attachments/utils/src/browser/css/common.css';\n\nconst App = () => {\n  return (\n    <Suspense fallback={null}>\n      <BrowserRouter>\n        {renderRoutes(routes)}\n      </BrowserRouter>\n    </Suspense>\n  );\n};\n\n\nconst reactRenderer = () => {\n  ReactDOM.render((\n    <BrowserRouter>\n      <App />\n    </BrowserRouter>\n  ), document.getElementById('base-app'));\n};\n\nconst beforeAppStart = async () => {\n  return true;\n};\n\nbeforeAppStart()\n  .then(() => {\n    reactRenderer();\n  });\n\n\n"
  },
  {
    "path": "examples/remote-deploy/base-app/src/common/const.ts",
    "content": "export interface MicroAppConfig {\n  name: string;\n  url: string;\n}\n\nexport const MICRO_APPS: MicroAppConfig[] = [\n  {\n    name: 'micro-app',\n    url: 'https://mf-lite-quick-start-micro-app.vercel.app/',\n  },\n];\n"
  },
  {
    "path": "examples/remote-deploy/base-app/src/index.tsx",
    "content": "import ('./app');\n\n"
  },
  {
    "path": "examples/remote-deploy/base-app/src/pages/home.less",
    "content": ".base-app-home {\n  .title {\n    font-size: 16px;\n    margin-bottom: 20px;\n  }\n\n  .content {\n    border: 1px solid;\n    padding: 10px;\n    min-height: 100px;\n  }\n}\n"
  },
  {
    "path": "examples/remote-deploy/base-app/src/pages/home.tsx",
    "content": "import React from 'react';\nimport './home.less';\nimport { createMicroApp } from '~src/utils/create-micro-app';\n\ninterface HomeProps {\n\n}\n\nconst Home: React.FC<HomeProps> = () => {\n  return (\n    <div className={'base-app-home'}>\n      <div className={'title'}>\n        🎉 This is Base App home page, the micro app will be rendered below! 🎉\n      </div>\n      <div className={'content'}>\n        {createMicroApp('micro-app')()}\n      </div>\n    </div>\n  );\n};\n\nexport default Home;\n"
  },
  {
    "path": "examples/remote-deploy/base-app/src/routes.ts",
    "content": "import { RouteConfig } from 'react-router-config';\nimport Home from './pages/home';\n\nexport const routes: RouteConfig[] = [\n  {\n    component: Home,\n    routes: [],\n  },\n];\n"
  },
  {
    "path": "examples/remote-deploy/base-app/src/types/global.d.ts",
    "content": "declare module '*.module.css';\ndeclare module '*.module.sass';\ndeclare module '*.module.scss';\n\n\ndeclare global {\n  const __APP_VERSION__: string;\n  const __MODE__: string;\n  const __BUILD_TIME__: string;\n\n  interface Window {\n    __POWERED_BY_QIANKUN__: boolean;\n  }\n}\n\n\nexport {};\n\n"
  },
  {
    "path": "examples/remote-deploy/base-app/src/utils/create-micro-app.tsx",
    "content": "import React, { useEffect, useRef, useState } from 'react';\nimport { MicroApp, MicroAppRef } from '@mf-lite/core/esm/browser/micro-app';\nimport { MICRO_APPS, MicroAppConfig } from '~src/common/const';\n\n\nexport const getMicroApp = (name: string): MicroAppConfig => {\n  const item = MICRO_APPS.find(res => res.name === name);\n  if (!item) {\n    throw new Error(`the micro app ${name} is not exist!`);\n  }\n  return item;\n};\n\n\nexport const createMicroApp = (name: string) => {\n  return () => {\n    const ref = useRef<MicroAppRef>(null);\n\n    const [isLoading, setIsLoading] = useState<boolean>(true);\n\n    const microAppConfig = {\n      name: name,\n      entry: getMicroApp(name).url,\n    };\n\n    useEffect(() => {\n      if (ref.current?.appStore) {\n        ref.current?.appStore.microApp?.loadPromise\n          .then(() => {\n            console.log('micro app loaded!');\n            setIsLoading(false);\n          });\n      }\n    }, []);\n\n    return (\n      <div>\n        {isLoading && 'loading...'}\n        <MicroApp\n          ref={ref}\n          microAppConfig={microAppConfig} />\n      </div>\n    );\n  };\n};\n"
  },
  {
    "path": "examples/remote-deploy/base-app/src/utils/init-common.ts",
    "content": "/**\n * File: init-common.ts\n * Description: 项目全局初始化\n * Created: 2021-09-28 21:51:34\n * Author: yuzhanglong\n * Email: yuzl1123@163.com\n */\n\n// patch 基座的 react-refresh\nimport { consoleTag } from '@attachments/utils/esm/browser/console-tag';\n\nconsoleTag(\n  {\n    key: 'MODE',\n    value: __MODE__,\n  },\n  {\n    key: 'VERSION',\n    value: __APP_VERSION__,\n    valueColor: '#409eff',\n  },\n  {\n    key: 'BUILD_TIME',\n    value: __BUILD_TIME__,\n    valueColor: '#ea7b27',\n  },\n);\n"
  },
  {
    "path": "examples/remote-deploy/base-app/src/utils/shared-utils.ts",
    "content": "export const add = (a: number, b: number) => {\n  return a + b;\n};\n\nexport const sayHello = () => {\n  console.log('hello world!');\n};\n\nexport default add;\n"
  },
  {
    "path": "examples/remote-deploy/base-app/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"target\": \"ES5\",\n    \"module\": \"CommonJS\",\n    \"baseUrl\": \"src\",\n    \"lib\": [\n      \"dom\",\n      \"dom.iterable\",\n      \"esnext\"\n    ],\n    \"paths\": {\n      \"~src/*\": [\n        \"./*\"\n      ]\n    },\n    \"types\": [\n      \"node\"\n    ],\n    \"allowJs\": true,\n    \"skipLibCheck\": true,\n    \"esModuleInterop\": true,\n    \"moduleResolution\": \"node\",\n    \"resolveJsonModule\": true,\n    \"isolatedModules\": false,\n    \"noEmit\": true,\n    \"experimentalDecorators\": true,\n    \"jsx\": \"preserve\",\n    \"downlevelIteration\": true\n  },\n  \"include\": [\n    \"src\"\n  ]\n}\n"
  },
  {
    "path": "examples/remote-deploy/micro-app/.eslintrc.js",
    "content": "module.exports = {\n  root: true,\n  env: {\n    browser: true,\n    es2021: true,\n    node: true,\n    jest: true,\n  },\n  extends: ['airbnb-base', 'prettier'],\n  parser: '@typescript-eslint/parser',\n  parserOptions: {\n    ecmaVersion: 12,\n    sourceType: 'module',\n  },\n  plugins: ['@typescript-eslint', 'import'],\n  rules: {\n    'semi': 'error',\n    'no-unused-vars': 'off',\n    '@typescript-eslint/no-unused-vars': ['error'],\n    'import/extensions': 'off',\n    'import/prefer-default-export': 'off',\n    'object-curly-newline': 'off',\n    'class-methods-use-this': 'off',\n    'no-shadow': 'off',\n    'no-console': 'off',\n    'arrow-body-style': 'off',\n    'no-useless-constructor': 'off',\n    'import/no-extraneous-dependencies': 'off',\n    'no-undef': 'off',\n    'object-shorthand': 'off',\n    'no-await-in-loop': 'off',\n    'consistent-return': 'off',\n    'no-restricted-syntax': 'off',\n    'prefer-destructuring': 'off',\n    'func-names': 'off',\n    'global-require': 'off',\n    'import/no-unresolved': 'off',\n    'no-underscore-dangle': 'off',\n    'no-use-before-define': 'off'\n  },\n  settings: {\n    'import/parsers': {\n      '@typescript-eslint/parser': ['.ts', '.tsx'],\n    },\n    'import/resolver': {\n      typescript: {\n        alwaysTryTypes: true,\n      },\n    },\n  },\n};\n"
  },
  {
    "path": "examples/remote-deploy/micro-app/.gitignore",
    "content": "# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.\n\n# dependencies\n/node_modules\n/.pnp\n.pnp.js\n\n# testing\n/coverage\n\n# production\n/build\ndist\n\n\n# IDE Config\n.idea\n\n# misc\n.DS_Store\n.env.local\n.env.development.local\n.env.test.local\n.env.production.local\n\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\n\n# tmp files\npublic/static\n\n.cache\n\n# 本地生成的类型定义文件\nsrc/types/mf-remotes\n\n# 模块提供者打包生成的类型定义\npublic/mf-expose/types\n"
  },
  {
    "path": "examples/remote-deploy/micro-app/.prettierrc.json",
    "content": "{\n  \"tabWidth\": 2,\n  \"semi\": false,\n  \"singleQuote\": true,\n  \"jsxBracketSameLine\": true\n}\n"
  },
  {
    "path": "examples/remote-deploy/micro-app/app-config.ts",
    "content": "import { MicroAppConfig } from '@mf-lite/core/lib/node/micro-fe-app-config';\n\nconst config: MicroAppConfig = {\n  name: 'micro_app',\n  url: 'https://mf-lite-quick-start-micro-app.vercel.app/',\n  exposes: [],\n  remotes: [\n    {\n      name: 'base_app',\n      url: 'https://mf-lite-quick-start-base-app.vercel.app/',\n      sharedLibraries: [\n        'react',\n        'react-dom',\n        'react/jsx-dev-runtime',\n        'react-router',\n        'react-router-dom',\n        'react-router-config',\n      ],\n    },\n  ],\n};\n\nexport default config;\n"
  },
  {
    "path": "examples/remote-deploy/micro-app/package.json",
    "content": "{\n  \"name\": \"micro-app\",\n  \"version\": \"0.0.1\",\n  \"main\": \"index.js\",\n  \"license\": \"MIT\",\n  \"devDependencies\": {\n    \"@attachments/proxy\": \"^0.1.15\",\n    \"@types/fs-extra\": \"^9.0.12\",\n    \"@types/node\": \"^16.4.6\",\n    \"@types/react\": \"^17.0.18\",\n    \"@types/react-dom\": \"^17.0.9\",\n    \"@types/react-router\": \"^5.1.16\",\n    \"@types/react-router-config\": \"^5.0.3\",\n    \"@types/react-router-dom\": \"^5.1.8\",\n    \"@typescript-eslint/eslint-plugin\": \"^4.28.5\",\n    \"@typescript-eslint/parser\": \"^4.28.5\",\n    \"autoprefixer\": \"^10.3.6\",\n    \"concurrently\": \"^6.3.0\",\n    \"cross-env\": \"^7.0.3\",\n    \"eslint\": \"^7.31.0\",\n    \"eslint-config-airbnb\": \"^18.2.1\",\n    \"eslint-config-prettier\": \"^8.1.0\",\n    \"eslint-import-resolver-typescript\": \"^2.4.0\",\n    \"eslint-plugin-import\": \"^2.22.1\",\n    \"eslint-plugin-prettier\": \"^3.3.1\",\n    \"react-router-config\": \"^5.1.1\",\n    \"rimraf\": \"^3.0.2\",\n    \"ts-node\": \"^10.2.1\",\n    \"typescript\": \"^4.3.5\",\n    \"webpack-merge\": \"^5.8.0\"\n  },\n  \"scripts\": {\n    \"dev:proxy\": \"ts-node scripts/proxy.ts\",\n    \"dev:serve\": \"cross-env NODE_ENV=development mf-lite serve --port=10000 --app-type=micro-app\",\n    \"build:dev\": \"rimraf dist && cross-env NODE_ENV=development mf-lite build --app-type=micro-app\",\n    \"build:prod\": \"rimraf dist && cross-env NODE_ENV=production mf-lite build --app-type=micro-app\",\n    \"lint\": \"eslint --ext js,jsx,ts,tsx src\",\n    \"generate\": \"mf-lite generate\",\n    \"upgrade\": \"mf-lite upgrade\"\n  },\n  \"dependencies\": {\n    \"@mf-lite/cli\": \"^0.1.3\",\n    \"@mf-lite/core\": \"^0.1.2\",\n    \"@attachments/utils\": \"^0.1.15\",\n    \"react\": \"^17.0.2\",\n    \"react-dom\": \"^17.0.2\",\n    \"react-router\": \"^5.2.1\",\n    \"react-router-dom\": \"^5.2.1\"\n  }\n}\n"
  },
  {
    "path": "examples/remote-deploy/micro-app/public/index.html",
    "content": "<!DOCTYPE html>\n<html lang='en'>\n<head>\n  <meta charset='UTF-8'>\n  <title>micro-app</title>\n</head>\n<body>\n<div id='micro-app'></div>\n</body>\n</html>\n"
  },
  {
    "path": "examples/remote-deploy/micro-app/public/mf-expose-types/exposes.d.ts",
    "content": ""
  },
  {
    "path": "examples/remote-deploy/micro-app/scripts/proxy.ts",
    "content": "import { ProxyServer } from '@attachments/proxy';\n\nconst runProxy = async () => {\n  const server = new ProxyServer();\n\n  // micro app 代理\n  server.addRule(\n    'mf-lite-quick-start-micro-app.vercel.app',\n    {\n      location: '/',\n      proxyPass: 'http://localhost:10000',\n    }\n  );\n\n  server.addRule(\n    'mf-lite-quick-start-base-app.vercel.app',\n    {\n      location: '/',\n      proxyPass: 'http://localhost:8080',\n    }\n  );\n\n  await server.initServers();\n  await server.listen();\n};\n\nrunProxy().catch(e => {\n  console.log(e);\n});\n"
  },
  {
    "path": "examples/remote-deploy/micro-app/src/app.tsx",
    "content": "import React from 'react';\nimport ReactDOM from 'react-dom';\nimport { BrowserRouter } from 'react-router-dom';\nimport { renderRoutes } from 'react-router-config';\nimport './init-common';\nimport { routes } from './routes';\n\n\nconst App: React.FC = () => {\n  return (\n    <BrowserRouter>\n      {renderRoutes(routes)}\n    </BrowserRouter>\n  );\n};\n\nexport const render = () => {\n  const el = document.getElementById('micro-app');\n  if (el) {\n    ReactDOM.render(<App />, el);\n  }\n};\n\nexport const destroy = () => {\n  const el = document.getElementById('micro-app');\n  if (el) {\n    ReactDOM.unmountComponentAtNode(el);\n  }\n};\n"
  },
  {
    "path": "examples/remote-deploy/micro-app/src/index.tsx",
    "content": "const App = import('./app');\n\nconst render = () => {\n  App.then(res => res.render());\n};\n\nif (!window.__POWERED_BY_QIANKUN__) {\n  render();\n}\n\n/**\n * bootstrap 只会在微应用初始化的时候调用一次，下次微应用重新进入时会直接调用 mount 钩子，不会再重复触发 bootstrap。\n * 通常我们可以在这里做一些全局变量的初始化，比如不会在 unmount 阶段被销毁的应用级别的缓存等。\n */\nexport async function bootstrap() {\n  return 0;\n}\n\n\n/**\n * 应用每次进入都会调用 mount 方法，通常我们在这里触发应用的渲染方法\n */\nexport async function mount() {\n  render();\n}\n\n/**\n * 应用每次 切出/卸载 会调用的方法，通常在这里我们会卸载微应用的应用实例\n */\nexport async function unmount() {\n  App.then(res => res.destroy());\n}\n\n/**\n * 可选生命周期钩子，仅使用 loadMicroApp 方式加载微应用时生效\n */\nexport async function update() {\n  render();\n}\n"
  },
  {
    "path": "examples/remote-deploy/micro-app/src/init-common.ts",
    "content": "// @ts-ignore\nimport { injectBaseReactRefresh } from '@mf-lite/core/esm/browser/inject-base-react-refresh';\n\nif (process.env.NODE_ENV === 'development') {\n  injectBaseReactRefresh();\n}\n"
  },
  {
    "path": "examples/remote-deploy/micro-app/src/pages/home.less",
    "content": ".react-app-home {\n  .button-wrapper {\n    margin-bottom: 20px;\n  }\n\n  .home-content {\n    font-size: 20px;\n  }\n}\n\n.parent-method {\n  color: #409eff;\n}\n\n.feature-image {\n  margin-top: 20px;\n  width: 480px;\n}\n"
  },
  {
    "path": "examples/remote-deploy/micro-app/src/pages/home.tsx",
    "content": "import React, { useState } from 'react';\nimport { renderRoutes } from 'react-router-config';\nimport { RouteComponentProps } from 'react-router';\nimport './home.less';\n\ninterface HomeProps extends RouteComponentProps {\n\n}\n\nconst Home: React.FC<HomeProps> = (props) => {\n  // @ts-ignore\n  const { route, history, location } = props;\n  const [currentPage, setCurrentPage] = useState<'one' | 'two'>(\n    location.pathname === '/page-two' ? 'two' : 'one'\n  );\n\n  const handleButtonClick = () => {\n    const nextPage = currentPage === 'one' ? 'two' : 'one';\n    setCurrentPage(nextPage);\n    history.push(`page-${nextPage}`);\n  };\n\n  return (\n    <div className={'react-app-home'}>\n      <div className={'button-wrapper'}>\n        <button className={'button'} onClick={() => handleButtonClick()}>\n          {`We are at page ${currentPage}, click to change!`}\n        </button>\n      </div>\n      <div className={'home-content'}>\n        {renderRoutes(route.routes)}\n      </div>\n    </div>\n  );\n};\n\nexport default Home;\n"
  },
  {
    "path": "examples/remote-deploy/micro-app/src/pages/page-one.tsx",
    "content": "import React from 'react';\nimport add from 'base_app/shared-utils';\nimport './home.less';\nimport feature from '../images/feature.png';\n\ninterface ProfileProps {\n\n}\n\nconst PageOne: React.FC<ProfileProps> = () => {\n  return (\n    <div>\n      <div>Page One</div>\n      <div className={'parent-method'}>来自父应用的方法：100 + 100 = {add(100, 100)}</div>\n      <div>\n        <img src={feature} alt='feature' className={'feature-image'}/>\n      </div>\n    </div>\n  );\n};\n\nexport default PageOne;\n"
  },
  {
    "path": "examples/remote-deploy/micro-app/src/pages/page-two.tsx",
    "content": "import React from 'react';\n\ninterface PageTwoProps {\n\n}\n\nconst PageTwo: React.FC<PageTwoProps> = () => {\n  return (\n    <div>Page Two</div>\n  );\n};\n\nexport default PageTwo;\n"
  },
  {
    "path": "examples/remote-deploy/micro-app/src/routes.ts",
    "content": "import { RouteConfig } from 'react-router-config';\nimport PageOne from './pages/page-one';\nimport Home from './pages/home';\nimport PageTwo from './pages/page-two';\n\nexport const routes: RouteConfig[] = [\n  {\n    component: Home,\n    routes: [\n      {\n        path: '/',\n        exact: true,\n        component: PageOne,\n      },\n      {\n        path: '/page-one',\n        component: PageOne,\n      },\n      {\n        path: '/page-two',\n        component: PageTwo,\n      },\n    ],\n  },\n];\n"
  },
  {
    "path": "examples/remote-deploy/micro-app/src/types/assets.d.ts",
    "content": "declare module '*.module.css';\ndeclare module '*.module.sass';\ndeclare module '*.module.scss';\ndeclare module '*.svg'\ndeclare module '*.png'\ndeclare module '*.jpg'\ndeclare module '*.jpeg'\ndeclare module '*.gif'\ndeclare module '*.bmp'\ndeclare module '*.tiff'\n"
  },
  {
    "path": "examples/remote-deploy/micro-app/src/types/global.d.ts",
    "content": "declare global {\n  interface Window {\n    __POWERED_BY_QIANKUN__: boolean;\n    __REACT_DEVTOOLS_GLOBAL_HOOK__: any;\n  }\n}\n\n\nexport {};\n"
  },
  {
    "path": "examples/remote-deploy/micro-app/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"target\": \"ES5\",\n    \"module\": \"CommonJS\",\n    \"baseUrl\": \"src\",\n    \"lib\": [\n      \"dom\",\n      \"dom.iterable\",\n      \"esnext\"\n    ],\n    \"paths\": {\n      \"~src/*\": [\n        \"./*\"\n      ]\n    },\n    \"types\": [\n      \"node\"\n    ],\n    \"allowJs\": true,\n    \"skipLibCheck\": true,\n    \"esModuleInterop\": true,\n    \"moduleResolution\": \"node\",\n    \"resolveJsonModule\": true,\n    \"isolatedModules\": false,\n    \"noEmit\": true,\n    \"experimentalDecorators\": true,\n    \"jsx\": \"preserve\",\n    \"downlevelIteration\": true\n  },\n  \"include\": [\n    \"src\"\n  ]\n}\n"
  },
  {
    "path": "lerna.json",
    "content": "{\n  \"packages\": [\n    \"packages/*\"\n  ],\n  \"command\": {\n    \"publish\": {\n      \"message\": \"chore(release): publish %s\",\n      \"registry\": \"https://registry.npmjs.org\"\n    }\n  },\n  \"version\": \"0.1.9\",\n  \"npmClient\": \"pnpm\"\n}\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"mf-lite\",\n  \"version\": \"1.0.0\",\n  \"private\": true,\n  \"workspaces\": [\n    \"packages/*\"\n  ],\n  \"main\": \"index.js\",\n  \"license\": \"MIT\",\n  \"scripts\": {\n    \"lint\": \"eslint --ext .ts --max-warnings 0 ./\",\n    \"test\": \"jest --no-cache\",\n    \"build-all\": \"pnpm -r build\",\n    \"clean-all\": \"lerna clean\",\n    \"publish-all\": \"pnpm clean-all && pnpm i && pnpm build-all && lerna publish --no-push\"\n  },\n  \"devDependencies\": {\n    \"@types/jest\": \"^26.0.24\",\n    \"@types/node\": \"^16.4.6\",\n    \"@typescript-eslint/eslint-plugin\": \"^4.28.5\",\n    \"@typescript-eslint/parser\": \"^4.28.5\",\n    \"concurrently\": \"^6.3.0\",\n    \"eslint\": \"^7.31.0\",\n    \"eslint-config-airbnb\": \"^18.2.1\",\n    \"eslint-config-prettier\": \"^8.1.0\",\n    \"eslint-import-resolver-typescript\": \"^2.4.0\",\n    \"eslint-plugin-import\": \"^2.22.1\",\n    \"eslint-plugin-prettier\": \"^3.3.1\",\n    \"fs-extra\": \"^10.0.0\",\n    \"html-webpack-plugin\": \"^5.3.2\",\n    \"jest\": \"^27.0.6\",\n    \"lerna\": \"^4.0.0\",\n    \"nodemon\": \"^2.0.12\",\n    \"npm-run-all\": \"^4.1.5\",\n    \"rimraf\": \"^3.0.2\",\n    \"stylelint\": \"^13.13.1\",\n    \"stylelint-config-standard\": \"^22.0.0\",\n    \"ts-jest\": \"^27.0.4\",\n    \"ts-node\": \"^10.1.0\",\n    \"typescript\": \"^4.3.5\"\n  }\n}\n"
  },
  {
    "path": "packages/assets/README.md",
    "content": "This project has moved [here](https://github.com/yuzhanglong/attachments/tree/main/packages/assets)\n\n\n"
  },
  {
    "path": "packages/cli/LICENSE",
    "content": "MIT License\n\nCopyright (c) 2021 YuZhanglong\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "packages/cli/README.md",
    "content": "# @mf-lite/cli\n\n一个通过命令行快速创建基座应用或者微前端应用的脚手架（CLI），提供项目初始化依赖及开发、构建脚本。\n\n## Usage\n\n[查看文档](https://ph3xmz5sya.feishu.cn/docs/doccnGEPiy8D3DJTZw6S05QJW4f?from=space_persnoal_filelist)\n\n"
  },
  {
    "path": "packages/cli/package.json",
    "content": "{\n  \"name\": \"@mf-lite/cli\",\n  \"version\": \"0.1.9\",\n  \"description\": \"A scaffold for quickly creating base applications or micro-front-end applications from the command line\",\n  \"author\": \"yuzhanglong <loveyzl1123@gmail.com>\",\n  \"homepage\": \"https://github.com/yuzhanglong/mf-lite\",\n  \"license\": \"MIT\",\n  \"main\": \"lib/index.js\",\n  \"module\": \"esm/index.js\",\n  \"bin\": {\n    \"mf-lite\": \"lib/mf-lite.js\"\n  },\n  \"files\": [\n    \"src\",\n    \"esm\",\n    \"lib\"\n  ],\n  \"scripts\": {\n    \"dev:start\": \"tsc -w\",\n    \"build:cjs\": \"rimraf ./lib && tsc --module commonjs --outDir lib\",\n    \"build:esm\": \"rimraf ./esm && tsc --module ESNext --outDir esm\",\n    \"build\": \"npm-run-all --parallel build:*\",\n    \"lint\": \"eslint --ext .ts --max-warnings 0 ./src\",\n    \"test\": \"jest\",\n    \"micro-app-template\": \"cd playground && npx mf-lite create\"\n  },\n  \"dependencies\": {\n    \"@attachments/assets\": \"^0.1.24\",\n    \"@attachments/utils\": \"^0.1.8\",\n    \"@mf-lite/core\": \"^0.1.9\",\n    \"chalk\": \"^4.1.2\",\n    \"commander\": \"^8.2.0\",\n    \"npm-check-updates\": \"^11.8.5\"\n  }\n}\n"
  },
  {
    "path": "packages/cli/src/index.ts",
    "content": "console.log('This is @mf-lite/cli project!');\n"
  },
  {
    "path": "packages/cli/src/mf-lite.ts",
    "content": "#!/usr/bin/env node\n\nimport { program } from 'commander';\nimport { loadTsConfigFile } from '@attachments/utils/lib/node';\nimport * as path from 'path';\nimport ncu from 'npm-check-updates';\nimport inquirer from 'inquirer';\nimport chalk from 'chalk';\nimport {\n  generateMfExposeDeclaration,\n  getMicroAppWebpackConfig,\n  MicroAppConfig,\n  MicroAppWebpackConfigOptions,\n  webpackBuild,\n  webpackServe\n} from '@mf-lite/core';\nimport { launchPlopByConfig } from '@attachments/assets/lib';\n\nconst APP_TYPES: (MicroAppWebpackConfigOptions['type'])[] = ['micro-app', 'base-app'];\n\nconst parseMicroAppBaseOptions = async (opt: any, isBuildMode: boolean) => {\n  const { appConfigPath, port, appType, analyze } = opt;\n  if (!APP_TYPES.includes(appType)) {\n    throw new Error('[mf-lite] app-type should be one of base-app or micro-app!');\n  }\n  const appConfig = await loadTsConfigFile(path.resolve(process.cwd(), appConfigPath));\n\n  return {\n    appConfig: appConfig,\n    // 在 build 模式下不起作用\n    port: port || 8080,\n    type: appType,\n    isBuildMode: isBuildMode,\n    isAnalyzeMode: analyze\n  } as MicroAppWebpackConfigOptions;\n};\n\n\n// 版本信息\nprogram\n  .version(`@mf-lite/cli ${require('../package.json').version}`);\n\n\n// 创建项目\nprogram\n  .command('create')\n  .description('create mf-lite project template for base-app or micro-app')\n  .action(\n    async () => {\n      await launchPlopByConfig('micro-fe-generator');\n    }\n  );\n\n// server 服务\nprogram\n  .command('serve')\n  .description('serve project by webpack-dev-server in development mode')\n  .option('--port <port>', 'dev-server port')\n  .option('--app-config-path <config>', 'app configuration file path', 'app-config.ts')\n  .option('--analyze <analyze>', 'open webpack-bundle-analyzer', false)\n  .requiredOption('--app-type <type>', 'set the app type, micro-app or base-app')\n  .action(\n    async (opt) => {\n      const config = await parseMicroAppBaseOptions(opt, false);\n      const microAppWebpackConfig = getMicroAppWebpackConfig(config);\n      await webpackServe(microAppWebpackConfig);\n    }\n  );\n\n// 构建服务\nprogram\n  .command('build')\n  .description('build your app')\n  .option('--app-config-path <config>', 'app configuration file path', 'app-config.ts')\n  .option('--analyze <analyze>', 'open webpack-bundle-analyzer', false)\n  .requiredOption('--app-type <type>', 'set the app type, micro-app or base-app')\n  .action(\n    async (opt) => {\n      const config = await parseMicroAppBaseOptions(opt, true);\n\n      const microAppWebpackConfig = getMicroAppWebpackConfig(config);\n\n      await webpackBuild(microAppWebpackConfig);\n    }\n  );\n\n// 类型定义生成器\nprogram\n  .command('generate')\n  .description('generate remote ts declarations for your app')\n  .option('--app-config-path <config>', 'app configuration file path', 'app-config.ts')\n  .action(\n    async (opt) => {\n      const { appConfigPath } = opt;\n      const appConfig = await loadTsConfigFile(path.resolve(process.cwd(), appConfigPath));\n      await generateMfExposeDeclaration(appConfig as MicroAppConfig);\n    }\n  );\n\n\n// 脚手架包升级\nprogram\n  .command('upgrade')\n  .description('upgrade mf-lite to newest version')\n  .action(\n    async () => {\n      console.log('[mf-lite] upgrading your mf-lite toolkits dependencies...');\n\n      const DEPS_TO_UPGRADE = [\n        '@attachments/proxy',\n        '@attachments/utils',\n        '@mf-lite/core',\n        '@mf-lite/cli'\n      ];\n\n      const res = await ncu.run({\n        packageFile: path.resolve(process.cwd(), 'package.json'),\n        upgrade: false,\n        filter: DEPS_TO_UPGRADE\n      });\n\n      const entries = Object.entries(res);\n\n      // 相关依赖没有需要更新的\n      if (!entries || entries.length === 0) {\n        console.log('\\n[mf-lite] mf-lite is already the latest version~');\n        return;\n      }\n\n      for (const [k, v] of entries) {\n        console.log(`${k} => ${chalk.blue(v)}`);\n      }\n\n      const userAnswers = await inquirer.prompt(\n        [\n          {\n            type: 'confirm',\n            message: '[mf-lite] There is a new version of mf-lite, the dependencies information is listed above, are you sure you want to update it?',\n            name: 'shouldUpgrade',\n            default: false\n          }\n        ]\n      );\n\n      if (userAnswers) {\n        await ncu.run({\n          packageFile: path.resolve(process.cwd(), 'package.json'),\n          upgrade: true,\n          filter: DEPS_TO_UPGRADE\n        });\n        console.log('[mf-lite] package.json is updated successfully, please run `yarn install` or `npm install` to upgrade your dependencies!');\n      }\n    }\n  );\n\nprogram.parse(process.argv);\n"
  },
  {
    "path": "packages/cli/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"compilerOptions\": {\n    \"baseUrl\": \"./\",\n    \"outDir\": \"lib\",\n    \"rootDir\": \"./src\",\n    \"jsx\": \"react\"\n  },\n  \"include\": [\n    \"src/**/*\"\n  ]\n}\n"
  },
  {
    "path": "packages/core/LICENSE",
    "content": "MIT License\n\nCopyright (c) 2021 YuZhanglong\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "packages/core/README.md",
    "content": "# @mf-lite/core\n\nmf-lite 的核心工具库\n\n## Usage\n\n[查看文档](https://ph3xmz5sya.feishu.cn/docs/doccnGEPiy8D3DJTZw6S05QJW4f?from=space_persnoal_filelist)\n"
  },
  {
    "path": "packages/core/__tests__/__snapshots__/ts-bundle.spec.ts.snap",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`test ts-bundle utils test bundleModuleDeclare 1`] = `\n\"// module name: app1/foo\n\ndeclare module 'app1/foo' {\n    export const add: (a: string, b: string) => string;\n\n    export class Hello {\n        private name;\n        constructor(name: string);\n    }\n\n    export default add;\n    export { };\n}\n\n// module name: app1/bar\n\ndeclare module 'app1/bar' {\n    export const add2: (a: string, b: string) => string;\n\n    export class Hello2 {\n        private name;\n        constructor(name: string);\n    }\n\n    export default Hello2;\n    export { };\n}\n\n\"\n`;\n\nexports[`test ts-bundle utils test dts bundle generator wrapper 1`] = `\n\"// Generated by dts-bundle-generator v5.9.0\n\nexport declare const add2: (a: string, b: string) => string;\nexport declare class Hello2 {\n\tprivate name;\n\tconstructor(name: string);\n}\nexport default Hello2;\n\nexport {};\n\"\n`;\n\nexports[`test ts-bundle utils test dts bundle generator wrapper 2`] = `\n\"// Generated by dts-bundle-generator v5.9.0\n\nexport declare const add: (a: string, b: string) => string;\nexport declare class Hello {\n\tprivate name;\n\tconstructor(name: string);\n}\nexport default add;\n\nexport {};\n\"\n`;\n"
  },
  {
    "path": "packages/core/__tests__/assets/app-config.ts",
    "content": "const a = 1;\nconsole.log(a);\n"
  },
  {
    "path": "packages/core/__tests__/assets/bar-tmp.d.ts",
    "content": "// Generated by dts-bundle-generator v5.9.0\n\nexport declare const add2: (a: string, b: string) => string;\nexport declare class Hello2 {\n\tprivate name;\n\n\tconstructor(name: string);\n}\nexport default Hello2;\n\nexport {};\n"
  },
  {
    "path": "packages/core/__tests__/assets/bar.ts",
    "content": "export const add2 = (a: string, b: string) => {\n  return a + b;\n};\n\nexport class Hello2 {\n  private name: string;\n\n  constructor(name: string) {\n    this.name = name;\n  }\n}\n\nexport default Hello2;\n"
  },
  {
    "path": "packages/core/__tests__/assets/foo-tmp.d.ts",
    "content": "// Generated by dts-bundle-generator v5.9.0\n\nexport declare const add: (a: string, b: string) => string;\nexport declare class Hello {\n\tprivate name;\n\n\tconstructor(name: string);\n}\nexport default add;\n\nexport {};\n"
  },
  {
    "path": "packages/core/__tests__/assets/foo.ts",
    "content": "export const add = (a: string, b: string) => {\n  return a + b;\n};\n\nexport class Hello {\n  private name: string;\n\n  constructor(name: string) {\n    this.name = name;\n  }\n}\n\nexport default add;\n"
  },
  {
    "path": "packages/core/__tests__/micro-app-config.spec.ts",
    "content": "import { getMicroAppConfigManager } from '../src';\n\ndescribe('test the micro application Config configuration library', () => {\n  test('test getModuleFederationRemotes()', () => {\n    const manager = getMicroAppConfigManager({\n      name: 'my_app',\n      url: 'www.base.com',\n      remotes: [\n        {\n          name: 'app1',\n          url: 'www.app1.com',\n          sharedLibraries: [],\n        },\n        {\n          name: 'app2',\n          url: 'www.app2.com',\n        },\n      ],\n      exposes: [],\n    });\n\n    expect(manager.getModuleFederationRemotes())\n      .toStrictEqual({\n        'app1': 'app1@www.app1.com/module-federation-entry.js',\n        'app2': 'app2@www.app2.com/module-federation-entry.js',\n      });\n  });\n\n  test('test getNormalModuleReplacementPluginCallBack()', () => {\n    const manager = getMicroAppConfigManager({\n      name: 'my_app',\n      url: 'www.base.com',\n      remotes: [\n        {\n          name: 'app1',\n          url: 'www.app1.com',\n          sharedLibraries: [\n            'react',\n          ],\n        },\n        {\n          name: 'app2',\n          url: 'www.app2.com',\n          sharedLibraries: [\n            'mobx',\n            {\n              name: 'global-store',\n              type: 'module',\n            },\n            {\n              name: 'foo',\n              type: 'package',\n            },\n          ],\n        },\n      ],\n      exposes: [],\n    });\n\n    const cb = manager.getNormalModuleReplacementPluginCallBack();\n\n    const runCb = (name: string) => {\n      const item = {\n        request: name,\n      };\n      cb(item);\n      return item.request;\n    };\n\n    expect(runCb('react')).toStrictEqual('app1/react');\n    expect(runCb('react-dom')).toStrictEqual('react-dom');\n    expect(runCb('foo')).toStrictEqual('app2/foo');\n  });\n});\n"
  },
  {
    "path": "packages/core/__tests__/ts-bundle.spec.ts",
    "content": "/**\n * File: ts-bundle.spec.ts\n * Description: typescript 类型定义打包工具封装\n * Created: 2021-10-01 14:25:20\n * Author: yuzhanglong\n * Email: yuzl1123@163.com\n */\n\n\nimport * as path from 'path';\nimport * as fs from 'fs';\nimport { bundleModuleDeclare, bundleTsDeclaration } from '../src';\n\ndescribe('test ts-bundle utils', () => {\n  const p = path.resolve(__dirname, 'assets');\n\n  test('test dts bundle generator wrapper', async () => {\n    await bundleTsDeclaration([\n      {\n        entryPath: path.resolve(p, 'bar.ts'),\n        outputPath: path.resolve(p, 'bar-tmp.d.ts'),\n      },\n      {\n        entryPath: path.resolve(p, 'foo.ts'),\n        outputPath: path.resolve(p, 'foo-tmp.d.ts'),\n      },\n    ]);\n\n    expect(fs.readFileSync(path.resolve(p, 'bar-tmp.d.ts')).toString()).toMatchSnapshot();\n    expect(fs.readFileSync(path.resolve(p, 'foo-tmp.d.ts')).toString()).toMatchSnapshot();\n  }, 20000);\n\n  test('test bundleModuleDeclare', () => {\n    const content = bundleModuleDeclare([\n      {\n        moduleName: 'app1/foo',\n        path: path.resolve(p, 'foo-tmp.d.ts'),\n      },\n      {\n        moduleName: 'app1/bar',\n        path: path.resolve(p, 'bar-tmp.d.ts'),\n      },\n    ]);\n    expect(content).toMatchSnapshot();\n  });\n});\n"
  },
  {
    "path": "packages/core/package.json",
    "content": "{\n  \"name\": \"@mf-lite/core\",\n  \"version\": \"0.1.9\",\n  \"description\": \"core library for mf-lite\",\n  \"author\": \"yuzhanglong <loveyzl1123@gmail.com>\",\n  \"homepage\": \"https://github.com/yuzhanglong/mf-lite\",\n  \"license\": \"MIT\",\n  \"main\": \"lib/index.js\",\n  \"module\": \"esm/index.js\",\n  \"files\": [\n    \"src\",\n    \"esm\",\n    \"lib\",\n    \"dist\"\n  ],\n  \"scripts\": {\n    \"dev:start\": \"tsc -w\",\n    \"build:cjs\": \"rimraf ./lib && tsc --module commonjs --outDir lib\",\n    \"build:esm\": \"rimraf ./esm && tsc --module ESNext --outDir esm\",\n    \"build\": \"npm-run-all --parallel build:*\",\n    \"lint\": \"eslint --ext .ts --max-warnings 0 ./src\",\n    \"test\": \"jest\",\n    \"mf-scripts:serve\": \"node lib/node/mf-scripts.js serve --port=8080 --app-config-path=__tests__/assets/app-config.ts --app-type=micro-app\",\n    \"mf-scripts:upgrade\": \"node lib/node/mf-scripts.js upgrade\"\n  },\n  \"devDependencies\": {\n    \"@types/fs-extra\": \"^9.0.13\",\n    \"@types/mini-css-extract-plugin\": \"^2.3.0\",\n    \"@types/react\": \"^17.0.26\",\n    \"@types/react-dom\": \"^17.0.9\",\n    \"@types/webpack-dev-server\": \"^4.1.0\"\n  },\n  \"dependencies\": {\n    \"@attachments/utils\": \"^0.1.8\",\n    \"@babel/core\": \"^7.15.5\",\n    \"@babel/plugin-proposal-decorators\": \"^7.15.4\",\n    \"@babel/plugin-transform-runtime\": \"^7.15.0\",\n    \"@babel/preset-env\": \"^7.15.6\",\n    \"@babel/preset-react\": \"^7.14.5\",\n    \"@babel/preset-typescript\": \"^7.15.0\",\n    \"@pmmmwh/react-refresh-webpack-plugin\": \"^0.5.1\",\n    \"@types/mini-css-extract-plugin\": \"^2.3.0\",\n    \"autoprefixer\": \"^10.3.6\",\n    \"axios\": \"^0.22.0\",\n    \"babel-loader\": \"^8.2.2\",\n    \"chalk\": \"^4.1.2\",\n    \"commander\": \"^8.2.0\",\n    \"css-loader\": \"^6.3.0\",\n    \"dts-bundle-generator\": \"^5.9.0\",\n    \"enhanced-resolve\": \"^5.8.3\",\n    \"fs-extra\": \"^10.0.0\",\n    \"html-webpack-plugin\": \"^5.3.2\",\n    \"inquirer\": \"^8.2.0\",\n    \"less\": \"^4.1.1\",\n    \"less-loader\": \"^10.0.1\",\n    \"mini-css-extract-plugin\": \"^2.3.0\",\n    \"moment\": \"^2.29.1\",\n    \"npm-check-updates\": \"^11.8.5\",\n    \"postcss\": \"^8.3.8\",\n    \"postcss-loader\": \"^6.1.1\",\n    \"qiankun\": \"^2.5.0\",\n    \"react\": \"^17.0.2\",\n    \"react-dom\": \"^17.0.2\",\n    \"react-refresh\": \"^0.10.0\",\n    \"sass\": \"^1.43.5\",\n    \"sass-loader\": \"^12.3.0\",\n    \"style-loader\": \"^3.3.0\",\n    \"terser-webpack-plugin\": \"^5.2.4\",\n    \"ts-morph\": \"^12.0.0\",\n    \"webpack\": \"^5.56.0\",\n    \"webpack-bundle-analyzer\": \"^4.4.2\",\n    \"webpack-dev-server\": \"^4.3.0\",\n    \"webpack-merge\": \"^5.8.0\"\n  }\n}\n"
  },
  {
    "path": "packages/core/src/browser/inject-base-react-refresh.ts",
    "content": "import { injectIntoGlobalHook } from 'react-refresh/cjs/react-refresh-runtime.development';\nimport ReactDOM from 'react-dom';\n\ndeclare global {\n  interface Window {\n    __REACT_DEVTOOLS_GLOBAL_HOOK__: any;\n  }\n}\n\n/**\n * 基于 webpack module Federation 架构下子应用的 react refresh 补丁\n *\n * @author yuzhanglong\n * @date 2021-09-27 22:19:36\n */\nexport const injectBaseReactRefresh = () => {\n  // Injects the react refresh replacing the one from the base app\n  injectIntoGlobalHook(window);\n  // Injects the react-dom instance again\n  window.__REACT_DEVTOOLS_GLOBAL_HOOK__.inject(ReactDOM);\n};\n"
  },
  {
    "path": "packages/core/src/browser/micro-app.tsx",
    "content": "import React, { forwardRef, useEffect, useImperativeHandle, useRef } from 'react';\nimport { loadMicroApp, ObjectType } from 'qiankun';\nimport { LoadableApp, MicroApp as IMicroApp } from 'qiankun/es/interfaces';\n\ninterface MicroAppProps {\n  microAppConfig: Omit<LoadableApp<ObjectType>, 'container'>;\n}\n\ninterface MicroAppCmpStore {\n  microApp: IMicroApp | null;\n  containerRef: HTMLElement | null;\n}\n\nexport interface MicroAppRef {\n  appStore: MicroAppCmpStore;\n}\n\n\nexport const MicroApp = forwardRef<MicroAppRef, MicroAppProps>((props, microAppRef) => {\n  const { current } = useRef<MicroAppCmpStore>({\n    containerRef: null,\n    microApp: null,\n  });\n\n  const loadApp = () => {\n    if (current.containerRef) {\n      current.microApp = loadMicroApp({\n        ...props.microAppConfig,\n        container: current.containerRef,\n      }, {\n        sandbox: {\n          experimentalStyleIsolation: true,\n        },\n      });\n    }\n  };\n\n  useEffect(() => {\n    loadApp();\n\n    return () => {\n      current.microApp?.unmount();\n    };\n  }, []);\n\n  useEffect(() => {\n    if (current.microApp && current.microApp.update) {\n      current.microApp.update({});\n    }\n  }, []);\n\n\n  useImperativeHandle(microAppRef, () => {\n    return {\n      appStore: current,\n    };\n  });\n\n  return (\n    <div className={`micro-app-${props.microAppConfig.name}`} ref={(ref) => {\n      current.containerRef = ref;\n    }} />\n  );\n});\n"
  },
  {
    "path": "packages/core/src/common/constants.ts",
    "content": "export const JS_PREFIX = 'static/js';\nexport const CSS_PREFIX = 'static/css';\nexport const IMG_PREFIX = 'static/images';\nexport const FONT_PREFIX = 'static/fonts';\nexport const FILE_PREFIX = 'static/files';\n"
  },
  {
    "path": "packages/core/src/common/paths.ts",
    "content": "import * as path from 'path';\n\nexport const sourcePath = path.resolve(process.cwd(), 'src');\n\nexport const publicPath = path.resolve(process.cwd(), 'public');\n\nexport const appConfigPath = path.resolve(process.cwd(), 'app-config.ts');\n"
  },
  {
    "path": "packages/core/src/index.ts",
    "content": "export { MicroAppConfig } from './node/micro-fe-app-config';\nexport { MicroAppWebpackConfigOptions } from './node/get-micro-app-webpack-config';\nexport { webpackBuild, webpackPromisify, webpackServe } from './node/webpack-command';\nexport { getMicroAppConfigManager } from './node/micro-fe-app-config';\nexport { generateMfExposeDeclaration } from './node/generate-mf-expose-declaration';\nexport { bundleTsDeclaration } from './node/bundle-ts-declaration';\nexport { generateDtsBundle } from 'dts-bundle-generator';\nexport { bundleModuleDeclare } from './node/bundle-module-declare';\nexport { emitMfExposeDeclaration } from './node/emit-mf-expose-declaration';\nexport { EmitMfExposeWebpackPlugin } from './node/emit-mf-expose-webpack-plugin';\nexport { getMicroAppWebpackConfig } from './node/get-micro-app-webpack-config';\nexport { getModuleFederationExposes } from './node/get-module-federation-exposes';\n"
  },
  {
    "path": "packages/core/src/node/add-entry-attribute-webpack-plugin.ts",
    "content": "import webpack from 'webpack';\nimport { Hooks } from 'html-webpack-plugin';\n\n/**\n * 向 html-webpack-plugin 导出的 HTML 模板 script 添加属性\n *\n * @author yuzhanglong\n * @date 2021-10-10 02:31:52\n */\nexport class AddEntryAttributeWebpackPlugin {\n  private readonly entryMatchCallback;\n\n  constructor(matchCallback: (src: string) => boolean) {\n    this.entryMatchCallback = matchCallback;\n  }\n\n  apply(compiler: webpack.Compiler) {\n    compiler.hooks.compilation.tap('AddEntryAttributeWebpackPlugin', (compilation) => {\n      // 通过最终的 webpack 配置的 plugins 属性，根据插件的 constructor.name 拿到 html-webpack-plugin 实例\n      const HtmlWebpackPluginInstance: any = compiler.options.plugins\n        .map(({ constructor }) => constructor)\n        .find(constructor => constructor && constructor.name === 'HtmlWebpackPlugin');\n\n\n      if (HtmlWebpackPluginInstance) {\n        // 获取 html-webpack-plugin 所有的 hooks\n        const hooks = HtmlWebpackPluginInstance.getHooks(compilation) as Hooks;\n\n        // 在插入标签之前做些什么\n        hooks.alterAssetTagGroups.tap(\n          'AddEntryAttributeWebpackPlugin', (data) => {\n            // 拿到所有的标签，如果是 script 标签，并且满足我们的匹配函数，则将其 attributes['entry'] 设为 true\n            data.headTags.forEach(tag => {\n              if (tag.tagName === 'script' && this.entryMatchCallback(tag.attributes?.src)) {\n                // eslint-disable-next-line no-param-reassign\n                tag.attributes.entry = true;\n              }\n            });\n            return data;\n          },\n        );\n      }\n    });\n  }\n}\n"
  },
  {
    "path": "packages/core/src/node/bundle-module-declare.ts",
    "content": "import { ModuleDeclarationKind, Project, SyntaxKind } from 'ts-morph';\n\nexport interface FileOptions {\n  // 声明文件路径\n  path: string;\n\n  // 声明文件模块名称\n  moduleName: string;\n}\n\n/**\n * 打包类型定义文件\n *\n * @author yuzhanglong\n * @date 2021-10-03 19:28:19\n * @param fileOptions 文件相关选项，可参考上面的类型定义\n */\nexport const bundleModuleDeclare = (fileOptions: FileOptions[]) => {\n  const project = new Project();\n\n  const content = [];\n\n  fileOptions.forEach(file => {\n    // 添加源代码\n    const source = project.addSourceFileAtPath(file.path);\n\n    // 遍历每一个子节点，如果是 SyntaxKind.DeclareKeyword（即 declare 关键词），进行文本替换\n    source.forEachDescendant(item => {\n      if (item.getKind() === SyntaxKind.DeclareKeyword) {\n        // 删除即可, 需要判断是不是第一个节点，否则会报异常\n        item.replaceWithText(item.isFirstNodeOnLine() ? 'export' : '');\n      }\n    });\n\n    // 备份根节点\n    const baseStatements = source.getStructure().statements;\n\n    // 移除现存的所有节点\n    source.getStatements().forEach(res => res.remove());\n\n    // 创建一个 module declaration，将上面备份的根节点插入之\n    source.addModule({\n      name: `'${file.moduleName}'`,\n      declarationKind: ModuleDeclarationKind.Module,\n      hasDeclareKeyword: true,\n      statements: baseStatements,\n    });\n\n    // 格式化代码\n    source.formatText();\n\n    // 补充一些注释\n    content.push(`// module name: ${file.moduleName}\\n\\n`);\n    content.push(source.getText());\n    content.push('\\n');\n  });\n\n  return content.join('');\n};\n"
  },
  {
    "path": "packages/core/src/node/bundle-ts-declaration.ts",
    "content": "import * as os from 'os';\nimport * as path from 'path';\nimport { runCommand } from '@attachments/utils/lib/node/run-command';\n\nexport interface BundleFileConfig {\n  // 入口文件路径\n  entryPath: string;\n\n  // 输出路径\n  outputPath: string;\n}\n\n/**\n * 封装 dts-bundle-generator\n *\n * @author yuzhanglong\n * @date 2021-10-01 20:09:23\n * @param entries 一个数组，详见 BundleFileConfig\n * @see BundleFileConfig\n */\nexport const bundleTsDeclaration = async (\n  entries: BundleFileConfig[],\n) => {\n  // 最大并行工作数目为 cpu 核心数 - 1\n  const maxWorkSize = os.cpus().length - 1;\n\n  while (entries.length > 0) {\n    const runningItems = entries.splice(0, maxWorkSize);\n    await Promise.all(runningItems.map((item) => {\n      const { entryPath, outputPath } = item;\n      return runCommand(\n        path.resolve(\n          require.resolve('dts-bundle-generator'),\n          '../bin/dts-bundle-generator.js',\n        ), [\n          entryPath,\n          '--out-file',\n          outputPath,\n          '--project',\n          path.resolve(process.cwd(), 'tsconfig.json'),\n          '--no-banner',\n        ]);\n    }));\n  }\n};\n"
  },
  {
    "path": "packages/core/src/node/emit-mf-expose-declaration.ts",
    "content": "import * as path from 'path';\nimport * as fs from 'fs-extra';\nimport { MicroAppConfig } from './micro-fe-app-config';\nimport { BundleFileConfig, bundleTsDeclaration } from './bundle-ts-declaration';\nimport { bundleModuleDeclare } from './bundle-module-declare';\n\n/**\n * 供公共组件的提供者使用，用来将相应的类型定义写入某个文件目录下\n * 我们可以在 webpack 写入文件之后 hook 到相应的生命周期中追加内容\n *\n * @author yuzhanglong\n * @date 2021-10-02 14:51:10\n * @param appConfig app 配置\n * @param baseUrl 写入的根路径\n */\nexport const emitMfExposeDeclaration = async (appConfig: MicroAppConfig, baseUrl: string) => {\n  // 增加临时缓存文件，用来打包每个小 bundle\n  await fs.ensureDir(path.resolve(baseUrl, '.cache'));\n\n  const entries: (BundleFileConfig & { name: string })[] = [];\n\n\n  for (const expose of appConfig.exposes) {\n    // 只处理 module 类型\n    if (typeof expose === 'object' && expose.type !== 'package') {\n      entries.push({\n        name: expose.name,\n        entryPath: expose.path,\n        outputPath: path.resolve(baseUrl, '.cache', `${expose.name}.d.ts`),\n      });\n    }\n  }\n\n  // 并行打包\n  await bundleTsDeclaration(entries.slice());\n\n  // 合并上面的所有小 bundle\n  const content = bundleModuleDeclare(\n    entries.map(res => {\n      return {\n        path: res.outputPath,\n        moduleName: `${appConfig.name}/${res.name}`,\n      };\n    }),\n  );\n\n  await fs.writeFile(path.resolve(baseUrl, 'exposes.d.ts'), content);\n  await fs.remove(path.resolve(baseUrl, '.cache'));\n};\n"
  },
  {
    "path": "packages/core/src/node/emit-mf-expose-webpack-plugin.ts",
    "content": "import webpack from 'webpack';\nimport * as path from 'path';\nimport { MicroAppConfig } from './micro-fe-app-config';\nimport { emitMfExposeDeclaration } from './emit-mf-expose-declaration';\n\n\ninterface EmitMfExposeWebpackPluginOptions {\n  // app 配置\n  appConfig: MicroAppConfig;\n\n  // 输出内容的基础路径，如果没有指定则为 compilation.compiler.outputPath\n  // 由于 serve 模式 build 模式输出位置不同，这个选项是有必要的，降低开发成本\n  outputBasePath?: string;\n}\n\n/**\n * 防抖函数\n *\n * @author yuzhanglong\n * @date 2021-12-01 00:51:19\n */\nexport const debounce = <T extends (...args: any[]) => any>(fn: T, timeout: number = 0) => {\n  if (typeof fn !== 'function') {\n    throw new Error('fn should be a function');\n  }\n\n  let timer = null;\n  return function(...args: Parameters<T>) {\n    if (timer) {\n      clearTimeout(timer);\n    }\n\n    timer = setTimeout(() => {\n      fn.call(this, ...args);\n    }, timeout);\n  };\n};\n\n/**\n * 向 build 打包产物注入类型定义的 webpack-plugin\n *\n * @author yuzhanglong\n * @date 2021-10-03 19:31:02\n */\nexport class EmitMfExposeWebpackPlugin {\n  private readonly config: EmitMfExposeWebpackPluginOptions;\n\n  constructor(config: EmitMfExposeWebpackPluginOptions) {\n    this.config = config;\n  }\n\n  apply(compiler: webpack.Compiler) {\n    const { appConfig, outputBasePath } = this.config;\n\n    const handler = debounce(async (compilation: webpack.Compilation) => {\n      try {\n        // 用 try catch 包裹一下防止 webpack-dev-server 热更新过程中偶发的强制 exit 现象\n        if (appConfig) {\n          // 拿到本项目的 outputPath\n          const { outputPath } = compilation.compiler;\n          // 生成相关目录\n          const target = path.resolve(outputBasePath ?? outputPath, 'mf-expose-types');\n          console.log('[mf-lite] compiling shared remote module declarations...');\n\n          // 基于用户的配置 appConfig 生成类型定义\n          await emitMfExposeDeclaration(appConfig, target);\n        }\n      } catch (e) {\n        console.log(e);\n      }\n    }, 1500);\n\n    // afterEmit 生命周期的时机：输出 asset 到 output 目录之后\n    // 实践证明，它不会阻塞 webpack dev-server 的流程，不会影响开发体验。\n    compiler.hooks.afterEmit.tap('EmitMfExposeWebpackPlugin', handler);\n\n    // TODO: 使用文件 hash 进行缓存，避免相同的内容重复打包，可以参考下面的的注释 DEMO\n    // compiler.hooks.thisCompilation.tap('EmitMfExposeWebpackPlugin', (compilation) => {\n    //   compilation.hooks.processAssets.tapAsync({\n    //     name: 'EmitMfExposeWebpackPlugin',\n    //     stage: webpack.Compilation.PROCESS_ASSETS_STAGE_OPTIMIZE_INLINE,\n    //   }, (compilationAssets, callback) => {\n    //     // 首先收集所有的文件，进行 content hash 值比对\n    //     // @ts-ignore\n    //     const data = [...compilation.modules].filter(res => res.request && res.request.includes('shared-utils.ts'))[0];\n    //     console.log(data.buildInfo);\n    //     return callback();\n    //   });\n    // });\n  }\n}\n"
  },
  {
    "path": "packages/core/src/node/generate-mf-expose-declaration.ts",
    "content": "/**\n * 生成 module federation expose 声明，一般用于消费者调用\n *\n * @author yuzhanglong\n * @date 2021-10-02 14:53:24\n */\nimport axios from 'axios';\nimport * as url from 'url';\nimport * as fs from 'fs-extra';\nimport * as path from 'path';\nimport { MicroAppConfig } from './micro-fe-app-config';\nimport { sourcePath } from '../common/paths';\n\nexport const generateMfExposeDeclaration = async (appConfig: MicroAppConfig) => {\n  const declareTypeRoot = path.resolve(sourcePath, 'types', 'mf-remotes');\n  await fs.ensureDir(declareTypeRoot);\n\n  for (const { name, url: remoteUrl } of appConfig.remotes) {\n    const targetFileName = `${name}-exposes.d.ts`;\n    // example: https://base-40kkvlqeq-yzl.vercel.app/mf-expose-types/exposes.d.ts\n    const remote = url.resolve(remoteUrl, 'mf-expose-types/exposes.d.ts');\n    console.log(`fetching remotes types declarations from ${remote}...`);\n    const declarations = await axios.get(remote);\n    await fs.writeFile(path.resolve(declareTypeRoot, targetFileName), declarations.data);\n  }\n\n  console.log('Done!');\n};\n"
  },
  {
    "path": "packages/core/src/node/get-micro-app-webpack-config.ts",
    "content": "import webpack, { NormalModuleReplacementPlugin } from 'webpack';\nimport HtmlWebpackPlugin from 'html-webpack-plugin';\nimport ReactRefreshWebpackPlugin from '@pmmmwh/react-refresh-webpack-plugin';\nimport MiniCssExtractPlugin from 'mini-css-extract-plugin';\nimport moment from 'moment';\nimport * as path from 'path';\nimport { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer';\nimport merge from 'webpack-merge';\nimport { publicPath as assetPublicPath, sourcePath } from '../common/paths';\nimport { CSS_PREFIX, FILE_PREFIX, JS_PREFIX } from '../common/constants';\nimport { getMicroAppConfigManager, MicroAppConfig } from './micro-fe-app-config';\nimport { getModuleFederationExposes } from './get-module-federation-exposes';\nimport { EmitMfExposeWebpackPlugin } from './emit-mf-expose-webpack-plugin';\nimport { AddEntryAttributeWebpackPlugin } from './add-entry-attribute-webpack-plugin';\n\nconst TerserWebpackPlugin = require('terser-webpack-plugin');\n\nconst { ModuleFederationPlugin } = require('webpack').container;\n\nexport interface MicroAppWebpackConfigOptions {\n  // 项目类型，base: 基座， micro-app 微应用\n  type: 'base-app' | 'micro-app';\n\n  // 项目运行的端口\n  port: number;\n\n  // 微应用配置\n  appConfig: MicroAppConfig;\n\n  // 是否在构建环境\n  isBuildMode: boolean;\n\n  // 开启分析模式\n  isAnalyzeMode?: boolean;\n}\n\n/**\n * 基座或者微应用的 webpack 配置封装\n *\n * @author yuzhanglong\n * @date 2021-10-03 19:32:18\n * @param options 相关配置选项，可参考上面的类型定义\n * @see MicroAppWebpackConfigOptions\n */\nexport const getMicroAppWebpackConfig = (options: MicroAppWebpackConfigOptions) => {\n  const { port, appConfig, isBuildMode, isAnalyzeMode } = options;\n  const websocketPath = `ws://localhost:${port.toString()}/ws`;\n\n  // 是否为生产环境\n  const isProductionEnvironment = process.env.NODE_ENV === 'production';\n\n  // 微应用工具管理类\n  const microAppConfigManager = getMicroAppConfigManager(appConfig);\n\n  // 样式默认配置\n  const baseStyleConfigRules = [\n    isProductionEnvironment ? MiniCssExtractPlugin.loader : require.resolve('style-loader'),\n    require.resolve('css-loader'),\n    {\n      loader: require.resolve('postcss-loader'),\n      options: {\n        postcssOptions: {\n          plugins: [\n            require('autoprefixer'),\n          ],\n        },\n      },\n    },\n  ].filter(Boolean);\n\n  // noinspection UnnecessaryLocalVariableJS\n  const config = {\n    mode: isProductionEnvironment ? 'production' : 'development',\n\n    // 打包入口，默认为 index.tsx\n    entry: path.resolve(sourcePath, 'index.tsx'),\n\n    // 在生产环境下默认不会打包 sourcemap (但有时候可能还是有必要的，比如接入监控平台)\n    devtool: isProductionEnvironment ? false : 'source-map',\n\n    // 开启打包文件缓存，第二次打开可以节约大量的时间\n    // 在 build 模式下不要打开，否则会报错\n    cache: isBuildMode ? false : {\n      type: 'filesystem',\n    },\n\n    // 代码优化配置\n    optimization: {\n      // 这里保证了基座热更新的实现\n      runtimeChunk: 'single',\n      minimize: isProductionEnvironment,\n      minimizer: [\n        new TerserWebpackPlugin({\n          terserOptions: {\n            format: {\n              comments: false,\n            },\n          },\n          extractComments: false,\n        }),\n      ],\n      // 一些常见依赖的代码分割\n      splitChunks: {\n        chunks: 'all',\n        cacheGroups: {\n          thirdVendors: {\n            name: 'initial-third-vendors',\n            test: /moment|lodash|mobx|qiankun/,\n            priority: 20,\n            enforce: true,\n          },\n          reactVendors: {\n            name: 'initial-react-vendors',\n            test: /react\\/|react-dom\\/|react-router\\/|react-router-dom\\/|axios/,\n            priority: 20,\n            enforce: true,\n          },\n          uiComponents: {\n            name: 'initial-ui-components-vendors',\n            test: /antd/,\n            priority: 20,\n            enforce: true,\n          },\n          uiIcons: {\n            name: 'initial-ui-icons-vendors',\n            test: /@ant-design\\/icons/,\n            priority: 20,\n            enforce: true,\n          },\n          uiOthers: {\n            name: 'initial-material-ui-others-vendors',\n            test: /@ant-design\\/*/,\n            priority: 10,\n            enforce: true,\n          },\n        },\n      },\n    },\n\n    // webpack dev-server\n    // @ts-ignore\n    devServer: {\n      client: {\n        webSocketURL: websocketPath,\n      },\n      static: {\n        directory: assetPublicPath,\n        watch: {\n          ignored: (f: string) => {\n            // 生成的类型定义不要监听，否则会引发全局的 reload 使 HMR 失去意义\n            return f.endsWith('.d.ts');\n          },\n        },\n      },\n      allowedHosts: 'all',\n      hot: true,\n      port: port,\n      historyApiFallback: true,\n      headers: {\n        'Access-Control-Allow-Origin': '*',\n      },\n    },\n\n    // 输出\n    output: {\n      // library 名称\n      library: `${microAppConfigManager.config.name}`,\n\n      // 输出的文件名称\n      // 如果你要修改此内容，请看一下下面调用 html-webpack-plugin 代码的相关注释\n      filename: isProductionEnvironment\n        ? `${JS_PREFIX}/[name].[contenthash:8].bundle.js`\n        : `${JS_PREFIX}/[name].bundle.js`,\n\n      // 输出文件名称，和 fileName 不同，这里的输出文件为非初始（non-initial）文件，例如我们熟悉的路由懒加载\n      chunkFilename: isProductionEnvironment\n        ? `${JS_PREFIX}/[name].[contenthash:8].chunk.js`\n        : `${JS_PREFIX}/[name].chunk.js`,\n\n      // asset/resource 模块以 [hash][ext][query] 文件名发送到输出目录\n      assetModuleFilename: `${FILE_PREFIX}/[name].[hash][ext]`,\n\n      // 公共路径\n      publicPath: microAppConfigManager.config.url,\n\n      // 输出 umd 类型的 bundle\n      libraryTarget: 'umd',\n    },\n\n\n    plugins: [\n      // NormalModuleReplacementPlugin 需要我们传入一个回调\n      // 我们可以在这里将默认的公共的 package 级别依赖重定向到 remote(即共享模块)\n      // 这个回调已被封装成公共方法，它会从你的 app-config 目录下读取 remote 字段，从中找到匹配的 sharedLibraries\n      new NormalModuleReplacementPlugin(\n        /(.*)/,\n        microAppConfigManager.getNormalModuleReplacementPluginCallBack(),\n      ),\n\n      // 输出 html 入口文件\n      new HtmlWebpackPlugin({\n        template: path.resolve(assetPublicPath, 'index.html'),\n      }),\n\n      // qiankun 底层依赖的 import-html-entry 会取所有 scripts 里面排在最后的 script 作为 entry。\n      // 具体代码可查看：https://github.com/kuitos/import-html-entry/blob/master/src/index.js#L321\n      // 但是我们通过 html-webpack-plugin 导出的 HTML，一般情况下是 main 在最后，但是在 webpack module federation 中，会生成一个额外的 entry 排在 main 的后面。\n      // 从而导致拿不到 main 入口的生命周期函数, 我们可以向 script 标签加入 entry 属性解决这个问题\n      new AddEntryAttributeWebpackPlugin((src => {\n        return !!(src.match(/main\\.(.*)\\.bundle.js$/) || src.match('main.bundle.js'));\n      })),\n\n      // webpack module federation 的插件，其配置基于 app-config 封装，一般无需改动\n      new ModuleFederationPlugin({\n        name: microAppConfigManager.config.name,\n        filename: 'module-federation-entry.js',\n        remotes: microAppConfigManager.getModuleFederationRemotes(),\n        exposes: getModuleFederationExposes(microAppConfigManager.config.exposes),\n      }),\n\n      // 非生产环境下启动 react 热更新插件\n      // 注意，如果将代码打包到测试服务器上(非生产环境)，那么也应该开启这个插件以向主应用插入相关胶水代码\n      // 由于子应用的 react 是由主应用 share 的，子应用如果需要热更新必须依赖这些胶水代码\n      // 另外这需要和 src/utils 目录下的 init-common 配合使用，开发者无需额外处理\n      !isProductionEnvironment && new ReactRefreshWebpackPlugin({\n        overlay: {\n          sockPath: websocketPath,\n        },\n      }),\n\n      // css 压缩\n      isProductionEnvironment && new MiniCssExtractPlugin({\n        filename: `${CSS_PREFIX}/${isProductionEnvironment ? '[name].[contenthash].css' : '[name].css'}`,\n        chunkFilename: `${CSS_PREFIX}/${isProductionEnvironment ? '[id].[contenthash].css' : '[id].css'}`,\n        ignoreOrder: true,\n      }),\n\n      // 定义一些全局的变量，例如版本、打包时间、环境信息\n      new webpack.DefinePlugin({\n        // eslint-disable-next-line import/no-dynamic-require\n        __APP_VERSION__: JSON.stringify(require(path.resolve(process.cwd(), 'package.json')).version),\n        __MODE__: JSON.stringify(process.env.NODE_ENV?.toUpperCase()),\n        __BUILD_TIME__: JSON.stringify(moment().format('MMMM Do YYYY, h:mm:ss A')),\n      }),\n\n      // Moment.js 默认情况下它会打包所有的 locale 文件\n      // 我们需要用户选择导入特定的区域设置\n      new webpack.IgnorePlugin({\n        resourceRegExp: /^\\.\\/locale$/,\n        contextRegExp: /moment$/,\n      }),\n\n      // 写入共享模块（非 package）的类型定义\n      new EmitMfExposeWebpackPlugin({\n        appConfig: microAppConfigManager.config,\n        outputBasePath: isBuildMode ? undefined : assetPublicPath,\n      }),\n\n      isAnalyzeMode && new BundleAnalyzerPlugin(),\n    ].filter(Boolean),\n\n    // 解析配置\n    resolve: {\n      // 扩展名省略\n      extensions: ['.ts', '.tsx', '.js', '.jsx'],\n\n      // 实用 alias\n      alias: {\n        '~src': sourcePath,\n      },\n    },\n\n    // 模块解析\n    module: {\n      rules: [\n        {\n          oneOf: [\n            // babel 相关\n            {\n              test: [/\\.[jt]sx?$/],\n              include: [sourcePath],\n              use: {\n                loader: require.resolve('babel-loader'),\n                options: {\n                  presets: [\n                    [\n                      require.resolve('@babel/preset-env'),\n                    ],\n                    [\n                      require.resolve('@babel/preset-react'),\n                      {\n                        runtime: 'automatic',\n                      },\n                    ],\n                    [\n                      require.resolve('@babel/preset-typescript'),\n                    ],\n                  ],\n                  plugins: [\n                    [\n                      require.resolve('@babel/plugin-proposal-decorators'),\n                      {\n                        legacy: true,\n                      },\n                    ],\n                    [require.resolve('@babel/plugin-transform-runtime')],\n                  ].filter(Boolean),\n                },\n              },\n            },\n            // css 预处理相关 css 和 less\n            {\n              test: [/\\.(le|c)ss$/],\n              use: [\n                ...baseStyleConfigRules,\n                {\n                  loader: require.resolve('less-loader'),\n                  options: {\n                    lessOptions: {\n                      javascriptEnabled: true,\n                    },\n                  },\n                },\n              ],\n            },\n            // css 预处理相关 sass\n            {\n              test: [/\\.s[ac]ss$/],\n              use: [\n                ...baseStyleConfigRules,\n                {\n                  loader: require.resolve('sass-loader'),\n                },\n              ],\n            },\n            // 其它内容全部以 asset/resource 输出\n            {\n              exclude: [/^$/, /\\.(js|mjs|jsx|ts|tsx)$/, /\\.html$/, /\\.json$/],\n              type: 'asset/resource',\n            },\n          ],\n        },\n      ],\n    },\n  };\n\n  // 合并用户自定义的 webpack 配置\n  const additionalConfig = microAppConfigManager.config.webpackConfig;\n  if (typeof additionalConfig === 'function') {\n    // 用户可以二次修改\n    additionalConfig(config as webpack.Configuration);\n    return config;\n  }\n\n  // @ts-ignore\n  return merge(config, additionalConfig || {});\n};\n"
  },
  {
    "path": "packages/core/src/node/get-module-federation-exposes.ts",
    "content": "/**\n * File: get-mf-exposes.ts\n * Description: 根据配置的目录（src/externals 下）, 生成 webpack module federation 配置\n * Created: 2021-08-29 13:39:40\n * Author: yuzhanglong\n * Email: yuzl1123@163.com\n */\n\nimport { CachedInputFileSystem, ResolverFactory } from 'enhanced-resolve';\nimport * as fs from 'fs';\n\ntype MfExposesModule = string | {\n  name: string;\n  path: string;\n}\n\nconst myResolver = ResolverFactory.createResolver({\n  fileSystem: new CachedInputFileSystem(fs, 4000),\n  conditionNames: ['node'],\n  extensions: ['.js', '.json', '.node'],\n  useSyncFileSystemCalls: true,\n  mainFields: ['esm', 'module', 'main'],\n});\n\nexport function getModuleFederationExposes(modules: MfExposesModule[]) {\n  const exposes: Record<string, string> = {};\n  for (const module of modules) {\n    if (typeof module === 'string') {\n      const key = `./${module}`;\n\n      const resolveResult = myResolver.resolveSync({}, process.cwd(), module);\n\n      if (typeof resolveResult !== 'string') {\n        throw new Error(`resolve error: ${module}`);\n      }\n\n      exposes[key] = resolveResult;\n    } else if (typeof module === 'object') {\n      exposes[`./${module.name}`] = module.path;\n    }\n  }\n  return exposes;\n}\n"
  },
  {
    "path": "packages/core/src/node/micro-fe-app-config.ts",
    "content": "import webpack from 'webpack';\n\ntype SharedLibraryExpose = string | {\n  name: string;\n  path: string;\n  type?: 'package' | 'module'\n};\n\ntype SharedLibrary = string | {\n  name: string;\n  type?: 'package' | 'module'\n};\n\nexport interface MicroAppConfig {\n  name: string;\n  url: string;\n  remotes: {\n    name: string;\n    url: string;\n    sharedLibraries?: SharedLibrary[]\n  }[];\n  exposes: SharedLibraryExpose[];\n  webpackConfig?: Partial<webpack.Configuration> | ((config: webpack.Configuration) => void);\n}\n\n/**\n * 基于 micro app config 生成目录\n *\n * @author yuzhanglong\n * @date 2021-09-28 00:40:39\n * @return object 一个对象, key 表示远程应用的名称，value 表示其入口 url\n */\nexport const getModuleFederationRemotes = (microAppConfig: MicroAppConfig) => {\n  const remotes: Record<string, string> = {};\n\n  // example: 'base_app': `base_app@https://base-yzl.vercel.app/base_app_entry.js`,\n  for (const remote of microAppConfig.remotes) {\n    remotes[remote.name] = `${remote.name}@${remote.url.endsWith('/') ? remote.url : `${remote.url}/`}module-federation-entry.js`;\n  }\n  return remotes;\n};\n\n/**\n * 获取 share library 的导入替换回调函数\n *\n * 基座暴露一些公共库，我们称为 share library，我们通过 NormalModuleReplacementPlugin 将所有的公共依赖导向相应的 app\n *\n * @author yuzhanglong\n * @date 2021-09-28 00:47:33\n */\nexport const getNormalModuleReplacementPluginCallBack = (microAppConfig: MicroAppConfig) => {\n  return (v: { request: string }) => {\n    // 寻找相应的 request，例如我们要重定向 react，那么我们要从所有的 remotes 中找到第一个其 shareLibrary 中有 react 的远程模块\n    const externalRemoteApp = microAppConfig.remotes\n      .find(res => {\n        if (!res.sharedLibraries) {\n          return false;\n        }\n\n        return res.sharedLibraries\n          .some(i => {\n            // 如果直接是 string 类型表示是一个 package\n            if (typeof i === 'string') {\n              return i === v.request;\n            }\n\n            return i.type === 'package' && i.name === v.request;\n          });\n      });\n    if (externalRemoteApp) {\n      // eslint-disable-next-line no-param-reassign\n      v.request = `${externalRemoteApp.name}/${v.request}`;\n    }\n  };\n};\n\n/**\n * 初始化全局 manager 方便调用\n *\n * @author yuzhanglong\n * @date 2021-09-28 00:53:32\n */\nexport const getMicroAppConfigManager = (microAppConfig: MicroAppConfig) => {\n  return {\n    getNormalModuleReplacementPluginCallBack: () => getNormalModuleReplacementPluginCallBack(microAppConfig),\n    getModuleFederationRemotes: () => getModuleFederationRemotes(microAppConfig),\n    config: microAppConfig,\n  };\n};\n\n\n"
  },
  {
    "path": "packages/core/src/node/webpack-command.ts",
    "content": "import webpack from 'webpack';\nimport WebpackDevServer from 'webpack-dev-server';\n\nexport const webpackPromisify = (config: Record<string, any>) => {\n  return new Promise((resolve, reject) => {\n    webpack(config, (err: any, state) => {\n      if (err) {\n        console.error(err.stack || err);\n        if (err.details) {\n          console.error(err.details);\n        }\n        reject();\n      }\n\n      const info = state.toJson();\n\n      if (state.hasErrors()) {\n        console.error(info.errors);\n        reject();\n      }\n\n      if (state.hasWarnings()) {\n        console.warn(info.warnings);\n        reject();\n      }\n\n      resolve(true);\n    });\n  });\n};\n\nexport const webpackBuild = async (config: Record<string, any>) => {\n  await webpackPromisify(config);\n};\n\n\nexport const webpackServe = async (config: Record<string, any>) => {\n  const compiler = webpack(config);\n\n  const devServerOptions = {\n    ...config.devServer,\n  };\n\n  // @ts-ignore\n  const server = new WebpackDevServer(devServerOptions, compiler);\n\n  server.startCallback(() => {\n    console.log('webpack dev server is running...');\n  });\n};\n"
  },
  {
    "path": "packages/core/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"compilerOptions\": {\n    \"baseUrl\": \"./\",\n    \"outDir\": \"lib\",\n    \"rootDir\": \"./src\",\n    \"jsx\": \"react\"\n  },\n  \"include\": [\n    \"src/**/*\"\n  ]\n}\n"
  },
  {
    "path": "packages/proxy/README.md",
    "content": "This project has moved [here](https://github.com/yuzhanglong/attachments/tree/main/packages/proxy)\n\n\n"
  },
  {
    "path": "pnpm-workspace.yaml",
    "content": "packages:\n  - 'packages/*'\n"
  },
  {
    "path": "tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"target\": \"ESNext\",\n    \"module\": \"CommonJS\",\n    \"declaration\": true,\n    \"moduleResolution\": \"Node\",\n    \"resolveJsonModule\": true,\n    \"types\": [\n      \"jest\",\n      \"node\"\n    ],\n    \"emitDecoratorMetadata\": true,\n    \"sourceMap\": true,\n    \"allowJs\": true,\n    \"skipLibCheck\": true,\n    \"esModuleInterop\": true,\n    \"isolatedModules\": false,\n    \"experimentalDecorators\": true,\n    \"jsx\": \"preserve\",\n    \"downlevelIteration\": true\n  }\n}\n"
  }
]