├── .github ├── ISSUE_TEMPLATE │ └── bug_report.md ├── pull_request_template.md └── workflows │ └── main.yml ├── .gitignore ├── .husky ├── commit-msg └── pre-commit ├── .prettierrc.js ├── CHANGELOG.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── commitlint.config.js ├── docs ├── .vitepress │ ├── config.ts │ └── theme │ │ ├── components │ │ ├── wujie-content.vue │ │ └── wujie-home.vue │ │ ├── index.ts │ │ └── styles │ │ ├── DocSearch.css │ │ └── vars.css ├── CHANGELOG.md ├── api │ ├── bus.md │ ├── destroyApp.md │ ├── preloadApp.md │ ├── setupApp.md │ ├── startApp.md │ └── wujie.md ├── documate.json ├── guide │ ├── communication.md │ ├── degrade.md │ ├── demo.md │ ├── index.md │ ├── information.md │ ├── install.md │ ├── jump.md │ ├── lifecycle.md │ ├── mode.md │ ├── nest.md │ ├── plugin.md │ ├── preload.md │ ├── principle.drawio │ ├── share.md │ ├── simple.drawio │ ├── start.md │ ├── sync.md │ └── variable.md ├── index.md ├── pack │ ├── index.md │ └── react.md ├── package.json ├── public │ ├── favicon.ico │ ├── wujie.png │ └── wujie.svg ├── question │ └── index.md ├── readme.md ├── vite.config.ts └── wujie │ ├── components │ ├── data.ts │ ├── wujie-connect.vue │ └── wujie-online.vue │ └── index.md ├── examples ├── angular12 │ ├── .browserslistrc │ ├── .editorconfig │ ├── .gitignore │ ├── CHANGELOG.md │ ├── README.md │ ├── angular.json │ ├── karma.conf.js │ ├── package.json │ ├── src │ │ ├── app │ │ │ ├── app-routing.module.ts │ │ │ ├── app.component.html │ │ │ ├── app.component.scss │ │ │ ├── app.component.spec.ts │ │ │ ├── app.component.ts │ │ │ └── app.module.ts │ │ ├── assets │ │ │ └── .gitkeep │ │ ├── environments │ │ │ ├── environment.prod.ts │ │ │ └── environment.ts │ │ ├── favicon.ico │ │ ├── index.html │ │ ├── main.ts │ │ ├── polyfills.ts │ │ ├── styles.scss │ │ └── test.ts │ ├── tsconfig.app.json │ ├── tsconfig.json │ └── tsconfig.spec.json ├── main-react │ ├── .env │ ├── .gitignore │ ├── CHANGELOG.md │ ├── README.md │ ├── config │ │ ├── env.js │ │ ├── getHttpsConfig.js │ │ ├── jest │ │ │ ├── babelTransform.js │ │ │ ├── cssTransform.js │ │ │ └── fileTransform.js │ │ ├── modules.js │ │ ├── paths.js │ │ ├── webpack.config.js │ │ ├── webpack │ │ │ └── persistentCache │ │ │ │ └── createEnvironmentHash.js │ │ └── webpackDevServer.config.js │ ├── package.json │ ├── public │ │ ├── favicon.ico │ │ ├── index.html │ │ ├── logo192.png │ │ ├── logo512.png │ │ ├── manifest.json │ │ └── robots.txt │ ├── scripts │ │ ├── build.js │ │ ├── integration.js │ │ ├── start.js │ │ └── test.js │ └── src │ │ ├── App.js │ │ ├── App.test.js │ │ ├── fetch.js │ │ ├── hostMap.js │ │ ├── index.css │ │ ├── index.js │ │ ├── lifecycle.js │ │ ├── logo.svg │ │ ├── pages │ │ ├── All.js │ │ ├── Angular12.js │ │ ├── Home.js │ │ ├── React16.js │ │ ├── React17.js │ │ ├── Vite.js │ │ ├── Vue2.js │ │ └── Vue3.js │ │ ├── plugin.js │ │ ├── reportWebVitals.js │ │ └── setupTests.js ├── main-vue │ ├── .browserslistrc │ ├── .eslintrc.js │ ├── .gitignore │ ├── CHANGELOG.md │ ├── README.md │ ├── babel.config.js │ ├── package.json │ ├── public │ │ ├── favicon.ico │ │ └── index.html │ ├── src │ │ ├── App.vue │ │ ├── assets │ │ │ └── logo.png │ │ ├── fetch.js │ │ ├── hostMap.js │ │ ├── lifecycle.js │ │ ├── main.js │ │ ├── plugin.js │ │ ├── router │ │ │ └── index.js │ │ └── views │ │ │ ├── Angular12.vue │ │ │ ├── Home.vue │ │ │ ├── Multiple.vue │ │ │ ├── PostMessage.vue │ │ │ ├── React16-sub.vue │ │ │ ├── React16.vue │ │ │ ├── React17-sub.vue │ │ │ ├── React17.vue │ │ │ ├── Vite-sub.vue │ │ │ ├── Vite.vue │ │ │ ├── Vue2-sub.vue │ │ │ ├── Vue2.vue │ │ │ ├── Vue3-sub.vue │ │ │ └── Vue3.vue │ ├── tsconfig.json │ └── vue.config.js ├── react16 │ ├── .env │ ├── .gitignore │ ├── CHANGELOG.md │ ├── README.md │ ├── config │ │ ├── env.js │ │ ├── getHttpsConfig.js │ │ ├── jest │ │ │ ├── babelTransform.js │ │ │ ├── cssTransform.js │ │ │ └── fileTransform.js │ │ ├── modules.js │ │ ├── paths.js │ │ ├── webpack.config.js │ │ ├── webpack │ │ │ └── persistentCache │ │ │ │ └── createEnvironmentHash.js │ │ └── webpackDevServer.config.js │ ├── package.json │ ├── public │ │ ├── favicon.ico │ │ ├── index.html │ │ ├── logo192.png │ │ ├── logo512.png │ │ ├── manifest.json │ │ └── robots.txt │ ├── scripts │ │ ├── build.js │ │ ├── start.js │ │ └── test.js │ └── src │ │ ├── App.js │ │ ├── Communication.js │ │ ├── Dialog.js │ │ ├── Font.js │ │ ├── Location.js │ │ ├── hostMap.js │ │ ├── index.js │ │ ├── lifecycle.js │ │ ├── logo.svg │ │ ├── nest.js │ │ └── styles.css ├── react17 │ ├── .env │ ├── .gitignore │ ├── CHANGELOG.md │ ├── README.md │ ├── config │ │ ├── env.js │ │ ├── getHttpsConfig.js │ │ ├── jest │ │ │ ├── babelTransform.js │ │ │ ├── cssTransform.js │ │ │ └── fileTransform.js │ │ ├── modules.js │ │ ├── paths.js │ │ ├── pnpTs.js │ │ ├── webpack.config.js │ │ └── webpackDevServer.config.js │ ├── package.json │ ├── public │ │ ├── favicon.ico │ │ ├── index.html │ │ ├── logo192.png │ │ ├── logo512.png │ │ ├── manifest.json │ │ └── robots.txt │ ├── scripts │ │ ├── build.js │ │ ├── start.js │ │ └── test.js │ └── src │ │ ├── App.js │ │ ├── App.test.js │ │ ├── Communication.js │ │ ├── Dialog.js │ │ ├── Location.js │ │ ├── State.js │ │ ├── index.css │ │ ├── index.js │ │ ├── logo.svg │ │ ├── reportWebVitals.js │ │ └── setupTests.js ├── vite │ ├── .gitignore │ ├── CHANGELOG.md │ ├── README.md │ ├── index.html │ ├── package.json │ ├── public │ │ └── favicon.ico │ ├── src │ │ ├── App.vue │ │ ├── assets │ │ │ └── logo.png │ │ ├── components │ │ │ ├── AppendBody.vue │ │ │ └── HelloWorld.vue │ │ ├── env.d.ts │ │ ├── index.css │ │ ├── main.ts │ │ ├── router │ │ │ └── index.ts │ │ └── views │ │ │ ├── Communication.vue │ │ │ ├── Dialog.vue │ │ │ ├── Home.vue │ │ │ ├── Location.vue │ │ │ └── State.vue │ ├── tsconfig.json │ └── vite.config.ts ├── vue2 │ ├── .browserslistrc │ ├── .eslintrc.js │ ├── .gitignore │ ├── CHANGELOG.md │ ├── README.md │ ├── babel.config.js │ ├── package.json │ ├── public │ │ ├── favicon.ico │ │ └── index.html │ ├── src │ │ ├── App.vue │ │ ├── assets │ │ │ └── logo.png │ │ ├── components │ │ │ ├── AppendBody.vue │ │ │ └── HelloWorld.vue │ │ ├── hostMap.js │ │ ├── index.css │ │ ├── main.js │ │ ├── pageLifeTest.js │ │ ├── router │ │ │ └── index.js │ │ └── views │ │ │ ├── Communication.vue │ │ │ ├── Dialog.vue │ │ │ ├── Home.vue │ │ │ ├── Location.vue │ │ │ └── PostMessage.vue │ └── vue.config.js └── vue3 │ ├── .browserslistrc │ ├── .eslintrc.js │ ├── .gitignore │ ├── CHANGELOG.md │ ├── README.md │ ├── babel.config.js │ ├── package.json │ ├── public │ ├── favicon.ico │ └── index.html │ ├── src │ ├── App.vue │ ├── assets │ │ └── logo.png │ ├── components │ │ ├── AppendBody.vue │ │ └── HelloWorld.vue │ ├── index.css │ ├── main.js │ ├── router │ │ └── index.js │ └── views │ │ ├── Communication.vue │ │ ├── Dialog.vue │ │ ├── Home.vue │ │ ├── Location.vue │ │ ├── PostMessage.vue │ │ └── State.vue │ └── vue.config.js ├── lerna.json ├── package.json ├── packages ├── wujie-core │ ├── .babelrc │ ├── .eslintrc.js │ ├── CHANGELOG.md │ ├── __test__ │ │ ├── integration │ │ │ ├── alive.test.ts │ │ │ ├── common.ts │ │ │ ├── degrade.test.ts │ │ │ ├── font.test.ts │ │ │ ├── head.test.ts │ │ │ ├── host.test.ts │ │ │ ├── href.test.ts │ │ │ ├── jest-preset.js │ │ │ ├── jest.config.js │ │ │ ├── lifecycle.test.ts │ │ │ ├── pageEvent.test.ts │ │ │ ├── plugin.test.ts │ │ │ ├── preLoadApp.test.ts │ │ │ ├── proxy.test.ts │ │ │ ├── startApp.test.ts │ │ │ ├── sync.test.ts │ │ │ ├── tsconfig.json │ │ │ └── utils.ts │ │ └── unit │ │ │ ├── event.test.ts │ │ │ ├── jest.config.js │ │ │ ├── jestSetup.js │ │ │ ├── plugin.test.ts │ │ │ └── tsconfig.json │ ├── build.sh │ ├── jest-puppeteer.config.js │ ├── package.json │ ├── src │ │ ├── common.ts │ │ ├── constant.ts │ │ ├── effect.ts │ │ ├── entry.ts │ │ ├── event.ts │ │ ├── iframe.ts │ │ ├── index.ts │ │ ├── plugin.ts │ │ ├── proxy.ts │ │ ├── sandbox.ts │ │ ├── shadow.ts │ │ ├── sync.ts │ │ ├── template.ts │ │ └── utils.ts │ ├── tsconfig.json │ └── webpack.config.js ├── wujie-react │ ├── .babelrc │ ├── .eslintrc.js │ ├── CHANGELOG.md │ ├── build.sh │ ├── index.d.ts │ ├── index.js │ ├── package.json │ └── webpack.config.js ├── wujie-vue2 │ ├── .babelrc │ ├── .eslintrc.js │ ├── CHANGELOG.md │ ├── build.sh │ ├── index.d.ts │ ├── index.js │ ├── package.json │ └── webpack.config.js └── wujie-vue3 │ ├── .babelrc │ ├── .eslintrc.js │ ├── CHANGELOG.md │ ├── build.sh │ ├── index.d.ts │ ├── index.js │ ├── package.json │ └── webpack.config.js ├── pnpm-lock.yaml ├── pnpm-workspace.yaml └── scripts ├── local-angular12-build.sh ├── local-doc-build.sh ├── local-main-react.sh ├── local-main-vue.sh ├── local-react16-build.sh ├── local-react17-build.sh ├── local-vite-build.sh ├── local-vue2-build.sh └── local-vue3-build.sh /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | 11 | 12 | **描述bug** 13 | 清晰准确的描述bug 14 | 15 | **如何复现** 16 | 给出详细的复现步骤 17 | 1、第一步 xxx 18 | 2、 第二步 xxx 19 | 20 | **错误截图** 21 | 如果有可以将截图带上 22 | 23 | **最小复现仓库或者地址** 24 | 重要!!!,请尽量给出复现仓库,这样能极大加快bug解决速度 25 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | 7 | 8 | - [ ] 提交符合commit规范 9 | - [ ] 文档更改 10 | - [ ] 测试用例添加 11 | - [ ] `npm run test`通过 12 | 13 | ##### 详细描述 14 | 15 | - 特性 16 | - 关联issue 17 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: npm publish 2 | 3 | on: 4 | push: 5 | tags: 6 | - v* 7 | 8 | jobs: 9 | publish: 10 | runs-on: ubuntu-latest 11 | 12 | steps: 13 | - uses: actions/checkout@v3 14 | 15 | - uses: actions/setup-node@v3.3.0 16 | with: 17 | node-version: "14.x" 18 | check-latest: true 19 | registry-url: "https://registry.npmjs.org" 20 | 21 | - name: install 22 | run: | 23 | npm install -g pnpm@7.9.5 24 | pnpm i --filter "wujie-project" --filter "./packages/**" --frozen-lockfile 25 | 26 | - name: publish to npm 27 | run: | 28 | ./node_modules/.bin/lerna run prepack 29 | ./node_modules/.bin/lerna publish from-package --no-verify-access --ignore-scripts --create-release github -y 30 | env: 31 | NODE_AUTH_TOKEN: ${{ secrets.NPM_AUTH_TOKEN }} 32 | GH_TOKEN: ${{ secrets.GH_TOKEN }} 33 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | dist 4 | site 5 | lib 6 | esm 7 | .DS_Store 8 | .vscode 9 | yarn.lock 10 | coverage 11 | .history 12 | .npmrc 13 | 14 | # Log files 15 | .pnpm-debug.log* 16 | cache 17 | .idea 18 | -------------------------------------------------------------------------------- /.husky/commit-msg: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | # npx --no-install commitlint --edit "$1" 5 | 6 | npm run husky-commitlint 7 | 8 | 9 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | ./node_modules/.bin/lerna run --scope wujie lint 5 | -------------------------------------------------------------------------------- /.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | printWidth: 120, 3 | }; 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (C) 2022 THL A29 Limited, a Tencent company. All rights reserved. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 10 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 11 | 12 | Other dependencies: 13 | 14 | The below software in this distribution may have been modified by THL A29 Limited ("Tencent Modifications"). 15 | All Tencent Modifications are Copyright (C) 2022 THL A29 Limited. 16 | 17 | --------------------------------------------------------------------------------------------------------------- 18 | 19 | 1. import-html-entry 20 | Copyright (c) 2018 Kuitos 21 | 22 | 2. qiankun 23 | Copyright (c) 2019 Kuitos -------------------------------------------------------------------------------- /commitlint.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: ['@commitlint/config-conventional'] 3 | } -------------------------------------------------------------------------------- /docs/.vitepress/theme/components/wujie-content.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 14 | 58 | -------------------------------------------------------------------------------- /docs/.vitepress/theme/index.ts: -------------------------------------------------------------------------------- 1 | import Theme from "vitepress/theme"; 2 | import wujieHome from "./components/wujie-home.vue"; 3 | import { h } from "vue"; 4 | import "./styles/vars.css"; 5 | import "./styles/DocSearch.css"; 6 | 7 | const inBrowser = typeof window !== "undefined"; 8 | export default { 9 | ...Theme, 10 | Layout() { 11 | return h(wujieHome); 12 | }, 13 | enhanceApp({ app }) { 14 | inBrowser && 15 | import("wujie-vue3").then((module) => { 16 | app.use(module.default); 17 | }); 18 | }, 19 | }; 20 | -------------------------------------------------------------------------------- /docs/.vitepress/theme/styles/DocSearch.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --vp-z-index-doc-search: 1000 !important; 3 | --vp-doc-search-background-color: linear-gradient(45deg, var(--color1), var(--color1), var(--color2), var(--color1)); 4 | } 5 | 6 | .DocSearch { 7 | --docsearch-primary-color: var(--vp-c-brand) !important; 8 | } 9 | 10 | .DocSearch-Container { 11 | z-index: var(--vp-z-index-doc-search); 12 | } 13 | 14 | .DocSearch-Button { 15 | font-weight: bold; 16 | width: 300px; 17 | display: flex; 18 | justify-content: space-between; 19 | border: none; 20 | outline: none; 21 | color: #fff; 22 | cursor: pointer; 23 | position: relative; 24 | background-color: var(--vp-c-bg-soft-mute); 25 | z-index: 0; 26 | border-radius: 10px; 27 | } 28 | 29 | .DocSearch-Button:before { 30 | /* content: ""; */ 31 | background: var(--vp-doc-search-background-color); 32 | position: absolute; 33 | top: -2px; 34 | left: -2px; 35 | background-size: 400%; 36 | z-index: -1; 37 | filter: blur(4px); 38 | width: calc(100% + 4px); 39 | height: calc(100% + 4px); 40 | animation: RhyshaKachari-glowing 20s linear infinite; 41 | opacity: 1; 42 | transition: opacity 0.3s ease-in-out; 43 | border-radius: 10px; 44 | } 45 | 46 | .DocSearch-Button:after { 47 | z-index: -1; 48 | content: ""; 49 | position: absolute; 50 | width: 100%; 51 | height: 100%; 52 | background-color: var(--vp-c-bg-soft-mute); 53 | left: 0; 54 | top: 0; 55 | border-radius: 10px; 56 | } 57 | 58 | @keyframes RhyshaKachari-glowing { 59 | 0% { 60 | background-position: 0 0; 61 | } 62 | 63 | 50% { 64 | background-position: 400% 0; 65 | } 66 | 67 | 100% { 68 | background-position: 0 0; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /docs/api/bus.md: -------------------------------------------------------------------------------- 1 | # bus 2 | 3 | - **类型:** `EventBus` 4 | 5 | ```typescript 6 | type callback = (...args: Array) => any; 7 | 8 | export declare class EventBus { 9 | private id; 10 | private eventObj; 11 | constructor(id: string); 12 | $on(event: string, fn: callback): EventBus; 13 | /** 任何$emit都会导致监听函数触发,第一个参数为事件名,后续的参数为$emit的参数 */ 14 | $onAll(fn: (event: string, ...args: Array) => any): EventBus; 15 | $once(event: string, fn: callback): void; 16 | $off(event: string, fn: callback): EventBus; 17 | $offAll(fn: callback): EventBus; 18 | $emit(event: string, ...args: Array): EventBus; 19 | $clear(): EventBus; 20 | } 21 | ``` 22 | 23 | - **详情:** 去中心化的事件平台,类`Vue`的事件`api`,支持链式调用。[示例](/guide/communication.html#eventbus-通信) 24 | 25 | ## $on 26 | 27 | - **类型:** `(event: string, fn: callback) => EventBus` 28 | 29 | - **参数:** 30 | - `{string} event` 事件名 31 | - `{callback} fn` 回调参数 32 | 33 | - **详情:** 监听事件并提供回调 34 | 35 | ## $onAll 36 | 37 | - **类型:** `(fn: (event: string, ...args: Array) => any) => EventBus` 38 | 39 | - **参数:** 40 | - `{callback} fn` 回调参数 41 | 42 | - **详情:** 监听所有事件并提供回调,回调函数的第一个参数是事件名 43 | 44 | 45 | ## $once 46 | 47 | - **类型:** `(event: string, fn: callback) => void` 48 | 49 | - **参数:** 50 | - `{string} event` 事件名 51 | - `{callback} fn` 回调参数 52 | 53 | - **详情:** 一次性的监听事件 54 | 55 | ## $off 56 | 57 | - **类型:** `(event: string, fn: callback) => EventBus` 58 | 59 | - **参数:** 60 | - `{string} event` 事件名 61 | - `{callback} fn` 回调参数 62 | 63 | - **详情:** 取消事件监听 64 | 65 | ## $offAll 66 | 67 | - **类型:** `(fn: callback) => EventBus` 68 | 69 | - **参数:** 70 | - `{callback} fn` 回调参数 71 | 72 | - **详情:** 取消监听所有事件 73 | 74 | ## $emit 75 | 76 | - **类型:** `(event: string, ...args: Array) => EventBus` 77 | 78 | - **参数:** 79 | - `{string} event` 事件名 80 | - `{Array} args` 其他回调参数 81 | 82 | - **详情:** 触发事件 83 | 84 | ## $clear 85 | 86 | - **类型:** `Function` 87 | 88 | - **详情:** 清空`EventBus`实例下所有监听事件 89 | 90 | ::: warning 警告 91 | 92 | - 子应用在被销毁或者重新渲染(非保活状态)时框架会自动调用清空上次渲染所有的订阅事件 93 | - 子应用内部组件的渲染可能导致反复订阅(比如在`mounted`生命周期调用`$wujie.bus.$on`),需要用户在`unmount`生命周期内手动调用`$wujie.bus.$off`来取消订阅 94 | ::: 95 | -------------------------------------------------------------------------------- /docs/api/destroyApp.md: -------------------------------------------------------------------------------- 1 | # destroyApp 2 | 3 | - 类型: `Function` 4 | 5 | - 参数: `string`,子应用`name` 6 | 7 | - 返回值: `void` 8 | 9 | 主动销毁子应用,承载子应用的`iframe`和`shadowRoot`都会被销毁,无界实例也会被销毁,相当于所有的缓存都被清空,除非后续不会再使用子应用,否则都不应该主动销毁。 10 | -------------------------------------------------------------------------------- /docs/api/wujie.md: -------------------------------------------------------------------------------- 1 | 无界对子应用注入了`$wujie`对象,可以通过`$wujie`或者`window.$wujie`获取 2 | 3 | # $wujie 4 | 5 | - **类型:** 6 | 7 | ```typescript 8 | { 9 | bus: EventBus; 10 | shadowRoot?: ShadowRoot; 11 | props?: { [key: string]: any }; 12 | location?: Object; 13 | } 14 | ``` 15 | 16 | ## $wujie.bus 17 | 18 | 同 [bus](/api/bus.html) 19 | 20 | ## $wujie.shadowRoot 21 | 22 | - **类型**:[ShadowRoot](https://developer.mozilla.org/en-US/docs/Web/API/ShadowRoot) 23 | 24 | 子应用的渲染容器`shadow DOM` 25 | 26 | ## $wujie.props 27 | 28 | - **类型:**`{ [key: string]: any }` 29 | 30 | 主应用注入的数据 31 | 32 | ## $wujie.location 33 | 34 | - **类型:**`Object` 35 | 36 | - 由于子应用的`location.host`拿到的是主应用的`host`,无界提供了一个正确的`location`挂载到挂载到`$wujie`上 37 | 38 | - 当采用`vite`编译框架时,由于`script`的标签`type`为`module`,所以无法采用[闭包](/guide/information.html#iframe-数据劫持和注入)的方式将 `location` 劫持代理,子应用所有采用`window.location.host`的代码需要统一修改成`$wujie.location.host` 39 | 40 | - 当子应用发生降级时,由于`proxy`无法正常工作导致`location`无法代理,子应用所有采用`window.location.host`的代码需要统一修改成`$wujie.location.host` 41 | 42 | - 当采用非`vite`编译框架时,`proxy`代理了`window.location`,子应用代码无需做任何更改 43 | 44 | -------------------------------------------------------------------------------- /docs/documate.json: -------------------------------------------------------------------------------- 1 | { 2 | "root": ".", 3 | "include": [ "**/*.md", "**/*.mdx" ], 4 | "backend": "https://6gxr8z72bh.us.aircode.run/upload" 5 | } 6 | -------------------------------------------------------------------------------- /docs/guide/communication.md: -------------------------------------------------------------------------------- 1 | # 无界提供三种方式进行通信 2 | 3 | ## props 通信 4 | 5 | 主应用可以通过[props](/api/startApp.html#props)注入数据和方法: 6 | 7 | ```vue 8 | 9 | ``` 10 | 11 | 子应用可以通过[$wujie](/api/wujie.html#wujie-props)来获取: 12 | 13 | ```javascript 14 | const props = window.$wujie?.props; // {data: xxx, methods: xxx} 15 | ``` 16 | 17 | ## window 通信 18 | 19 | 由于子应用运行的`iframe`的`src`和主应用是同域的,所以相互可以直接通信 20 | 21 | 主应用调用子应用的全局数据 22 | 23 | ```javascript 24 | window.document.querySelector("iframe[name=子应用id]").contentWindow.xxx; 25 | ``` 26 | 27 | 子应用调用主应用的全局数据 28 | 29 | ```javascript 30 | window.parent.xxx; 31 | ``` 32 | 33 | ## eventBus 通信 34 | 35 | 无界提供一套去中心化的通信方案,主应用和子应用、子应用和子应用都可以通过这种方式方便的进行通信, 详见 [api](/api/bus.html#bus) 36 | 37 | 主应用使用方式: 38 | 39 | ```javascript 40 | // 如果使用wujie 41 | import { bus } from "wujie"; 42 | 43 | // 如果使用wujie-vue 44 | import WujieVue from "wujie-vue"; 45 | const { bus } = WujieVue; 46 | 47 | // 如果使用wujie-react 48 | import WujieReact from "wujie-react"; 49 | const { bus } = WujieReact; 50 | 51 | // 主应用监听事件 52 | bus.$on("事件名字", function (arg1, arg2, ...) {}); 53 | // 主应用发送事件 54 | bus.$emit("事件名字", arg1, arg2, ...); 55 | // 主应用取消事件监听 56 | bus.$off("事件名字", function (arg1, arg2, ...) {}); 57 | ``` 58 | 59 | 子应用使用方式: 60 | 61 | ```javascript 62 | // 子应用监听事件 63 | window.$wujie?.bus.$on("事件名字", function (arg1, arg2, ...) {}); 64 | // 子应用发送事件 65 | window.$wujie?.bus.$emit("事件名字", arg1, arg2, ...); 66 | // 子应用取消事件监听 67 | window.$wujie?.bus.$off("事件名字", function (arg1, arg2, ...) {}); 68 | ``` 69 | -------------------------------------------------------------------------------- /docs/guide/degrade.md: -------------------------------------------------------------------------------- 1 | # 降级处理 2 | 3 | 无界提供无感知的降级方案 4 | 5 | 在非降级场景下,子应用的`dom`在`webcomponent`中,运行环境在`iframe`中,`iframe`对`dom`的操作通过`proxy`来代理到`webcomponent`上,而`webcomponent`和`proxy` `IE`都无法支持,这里采用另一个的`iframe`替换`webcomponent`,用`Object.defineProperty`替换`proxy`来做代理的方案 6 | 7 | ::: warning 注意 8 | 9 | 无界并没有对 es6 代码进行 polyfill,因为每个用户对浏览器的兼容程度是不一样的引入的 polyfill 也不一致,如果需要在较低版本的浏览器中运行,需要用户自行 通过 babel 来添加 polyfill。 10 | 11 | ::: 12 | ## 优点 13 | 14 | 1. 降级的行为由框架判断,当浏览器不支持时自动降级 15 | 16 | 2. 降级后,应用之间也保证了绝对的隔离度 17 | 18 | 3. 代码无需做任何改动,之前的预加载、保活还有通信的代码都生效,用户不需要为了降级做额外的代码改动导致降级前后运行的代码不一致 19 | 20 | 4. 用户也可以强制降级,比如说当前浏览器对 webcomponent 和 proxy 是支持的,但是用户还是想将 dom 运行在 iframe 中,就可以将 [degrade](/api/startApp.html#degrade) 设置为 true 21 | 22 | ## 缺点 23 | 24 | 1. 弹窗只能在子应用内部 25 | 26 | 2. 由于无法使用`proxy`,无法劫持子应用的`location`,导致访问`window.location.host`的时候拿到的是主应用的`host`,子应用可以从 [$wujie.location](/api/wujie.html#wujie-location) 中拿到子应用正确的`host` 27 | -------------------------------------------------------------------------------- /docs/guide/demo.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebarDepth: 2 3 | --- 4 | 5 | # 定制化 WujieDemo 6 | 7 | ## 快速开始 8 | 9 | :::tip 10 | wujie 可以通过脚手架来定制需要的主子应用框架的Demo,以及其他特性 11 | ::: 12 | 13 | ### 安装 create-wujie 14 | 15 | ```js 16 | npx create-wujie@latest 17 | ``` 18 | 19 | ### 支持包管理器 20 | 21 | WujieDemo 采用 TurboRepo 进行管理 支持多种包管理器 22 | 23 | - npm 24 | - pnpm 25 | - yarn 26 | 27 | ### 支持路由定制 28 | 29 | 可以选择主应用跟子应用的不同路由模式 `hash | history` 30 | 31 | ### 支持主应用框架 32 | 33 | | MainFramework | finish | 34 | | ----------------- | ------ | 35 | | React17 + Webpack | ✅ 🆕 | 36 | | Vue2 + Webpack | ✅ | 37 | | Vue3 + Vite3 | ✅ | 38 | 39 | ### 支持子应用框架 40 | 41 | | SubFramework | finish | 42 | | ----------------- | ------ | 43 | | React16 + Webpack | ✅ 🆕 | 44 | | React17 + Webpack | ✅ 🆕 | 45 | | React18 + Webpack | 🚧 | 46 | | Vue3 + Vite | ✅ | 47 | | Vue2 + Webpack | ✅ | 48 | | Vue3 + Webpack | ✅ | 49 | | Angular12 | ✅ | 50 | -------------------------------------------------------------------------------- /docs/guide/install.md: -------------------------------------------------------------------------------- 1 | # 创建一个新项目 2 | 3 | ### 介绍 4 | 5 | `create-wujie` 用来帮助快速启动示例项目,方便开发者快速上手。 6 | 7 | - 支持选择一个或多个子应用来创建一个新的项目,便于针对特定框架进行开发测试。 8 | - 支持主,子应用路由模式(`hash`, `history`)选择。 9 | 10 | 后续会支持更多功能以及其他框架,版本的支持, 便于快速上手 `wujie`。 11 | 12 | 如在使用过程中遇到任何问题, 请在 [issues](https://github.com/wujie-micro/create-wujie/issues) 进行说明。 13 | 14 | ### 快速开始 15 | 16 | 开发环境配置: 17 | 18 | - [Node.js](https://nodejs.org/en/) 版本 < 18.0.0 19 | - [pnpm](https://pnpm.io/) 脚手架示例模版基于 pnpm + [turborepo](https://turborepo.org/docs/getting-started) 管理项目 20 | 21 | 如果您的当前环境中需要切换 node.js 版本, 可以使用 [nvm](https://github.com/nvm-sh/nvm) or [fnm](https://github.com/Schniz/fnm) 进行安装. 22 | 23 | 以下是通过 nvm 安装 Node.js 16 LTS 版本的示例: 24 | 25 | ```bash 26 | # Install the LTS version of Node.js 16 27 | nvm install 16 --lts 28 | 29 | # Make the newly installed Node.js 16 as the default version 30 | nvm alias default 16 31 | 32 | # Switch to the newly installed Node.js 16 33 | nvm use 16 34 | ``` 35 | 36 | ### 安装 37 | 38 | 打开一个终端并使用以下命令创建一个新的`wujie demo` 示例: 39 | 40 | ```bash 41 | # Create a new wujie-app project 42 | npx create-wujie@latest 43 | ``` 44 | 45 | ### 模版列表 46 | 47 | - 主应用列表 48 | 49 | | 主应用框架 | | 50 | | ----------------- | --- | 51 | | Webpack + Vue2 | ✅ | 52 | | Webpack + React17 | ✅ | 53 | | Vite + Vue3 | 🚧 | 54 | 55 | - 子应用列表 56 | 57 | | 子应用框架 | | 58 | | ----------------- | --- | 59 | | Vite + Vue3 | ✅ | 60 | | Webpack + Vue2 | ✅ | 61 | | Webpack + Vue3 | ✅ | 62 | | Webpack + React16 | ✅ | 63 | | Webpack + React17 | ✅ | 64 | | Angular12 | ✅ | 65 | -------------------------------------------------------------------------------- /docs/guide/lifecycle.md: -------------------------------------------------------------------------------- 1 | 2 | # 生命周期 3 | 4 | ::: tip 提示 5 | 无界提供一整套的生命周期钩子供开发者调用 6 | ::: 7 | 8 | ::: warning 警告 9 | 如果子应用没有做[生命周期的改造](/guide/start.html#生命周期改造),那么 beforeMount、afterMount、beforeUnmount、afterUnmount 这四个生命周期将不会调用 10 | ::: 11 | 12 | ## beforeLoad 13 | 14 | - 类型: `type lifecycle = (appWindow: Window) => any;` 15 | 16 | 子应用开始加载静态资源前触发 17 | 18 | ## beforeMount 19 | 20 | - 类型: `type lifecycle = (appWindow: Window) => any;` 21 | 22 | 子应用渲染(调用`window.__WUJIE_MOUNT`)前触发 23 | 24 | ## afterMount 25 | 26 | - 类型: `type lifecycle = (appWindow: Window) => any;` 27 | 28 | 子应用渲染(调用`window.__WUJIE_MOUNT`)后触发 29 | 30 | ## beforeUnmount 31 | 32 | - 类型: `type lifecycle = (appWindow: Window) => any;` 33 | 34 | 子应用卸载(调用`window.__WUJIE_UNMOUNT`)前触发 35 | 36 | ## afterUnmount 37 | 38 | - 类型: `type lifecycle = (appWindow: Window) => any;` 39 | 40 | 子应用卸载(调用`window.__WUJIE_UNMOUNT`)后触发 41 | 42 | ## activated 43 | 44 | - 类型: `type lifecycle = (appWindow: Window) => any;` 45 | 46 | 子应用[保活模式](/api/startApp.html#alive)下,进入时触发 47 | 48 | ## deactivated 49 | 50 | - 类型: `type lifecycle = (appWindow: Window) => any;` 51 | 52 | 子应用[保活模式](/api/startApp.html#alive)下,离开时触发 53 | 54 | ## loadError 55 | 56 | - 类型: `type loadErrorHandler = (url: string, e: Error) => any;` 57 | 58 | 子应用加载资源失败后触发 59 | -------------------------------------------------------------------------------- /docs/guide/mode.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebarDepth: 2 3 | collapsable: false 4 | --- 5 | 6 | # 运行模式 7 | 8 | ![无界流程图.jpeg](https://vfiles.gtimg.cn/wuji_dashboard/xy/test_wuji_damy/F0NYfpHl.jpeg) 9 | 10 | 在微前端框架中,子应用放置在主应用页面中随着主应用页面的打开和关闭反复的激活和销毁,而在无界微前端框架中子应用是否保活以及是否进行生命周期的改造会进入完全不同的处理流程 11 | 12 | ## 保活模式 13 | 14 | 子应用的 [alive](/api/startApp.html#alive) 设置为`true`时进入保活模式,内部的数据和路由的状态不会随着页面切换而丢失。 15 | 16 | 在保活模式下,子应用只会进行一次渲染,页面发生切换时承载子应用`dom`的`webcomponent`会保留在内存中,当子应用重新激活时无界会将内存中的`webcomponent`重新挂载到容器上 17 | 18 | 保活模式下改变 [url](/api/startApp.html#url) 子应用的路由不会发生变化,需要采用 [通信](/guide/communication.html) 的方式对子应用路由进行跳转 19 | 20 | ::: warning 注意 21 | 22 | 保活的子应用的实例不会销毁,子应用被切走了也可以响应 bus 事件,非保活的子应用切走了监听的事件也会全部销毁,需要等下次重新 mount 后重新监听。 23 | 24 | ::: 25 | 26 | ## 单例模式 27 | 28 | 子应用的`alive`为`false`且进行了[生命周期改造](/guide/start.html#生命周期改造)时进入单例模式。 29 | 30 | 子应用页面如果切走,会调用`window.__WUJIE_UNMOUNT`销毁子应用当前实例,子应用页面如果切换回来,会调用`window.__WUJIE_MOUNT`渲染子应用新的子应用实例 31 | 32 | 在单例式下,改变 [url](/api/startApp.html#url) 子应用的路由会发生跳转到对应路由 33 | 34 | 如果主应用上有多个菜单栏用到了子应用的不同页面,在每个页面启动该子应用的时候将`name`设置为同一个,这样可以共享一个`wujie`实例,承载子应用`js`的`iframe`也实现了共享,不同页面子应用的`url`不同,切换这个子应用的过程相当于:销毁当前应用实例 => 同步新路由 => 创建新应用实例 35 | 36 | ## 重建模式 37 | 38 | 子应用既没有设置为保活模式,也没有进行生命周期的改造则进入了重建模式,每次页面切换不仅会销毁承载子应用`dom`的`webcomponent`,还会销毁承载子应用`js`的`iframe`,相应的`wujie`实例和子应用实例都会被销毁 39 | 40 | 重建模式下改变 [url](/api/startApp.html#url) 子应用的路由会跳转对应路由,但是在 [路由同步](/guide/sync.html) 场景并且子应用的路由同步参数已经同步到主应用`url`上时则无法生效,因为改变`url`后会导致子应用销毁重新渲染,此时如果有同步参数则同步参数的优先级最高 41 | -------------------------------------------------------------------------------- /docs/guide/nest.md: -------------------------------------------------------------------------------- 1 | 无界支持应用嵌套,嵌套的应用和正常应用一致,支持预加载、保活、路由同步、通信等能力 2 | 3 | [bus](/api/bus.html#bus) 可以在所有应用(包括嵌套子应用)中进行去中心化的通信,[destroyApp](/api/destroyApp.html#destroyapp) 可以销毁任何子应用(包括嵌套子应用) 4 | 5 | ::: warning 警告 6 | 嵌套的应用的 name 原则上也应该保持唯一性,除非用户想复用已经渲染的子应用 7 | ::: 8 | -------------------------------------------------------------------------------- /docs/guide/preload.md: -------------------------------------------------------------------------------- 1 | # 预加载 2 | 3 | ::: tip 4 | 预加载能力可以极大的提升子应用打开的首屏时间 5 | ::: 6 | ## 预加载 7 | 8 | 预加载指的是在应用空闲的时候`requestIdleCallback`将所需要的静态资源提前从网络中加载到内存中,详见[preloadApp](/api/preloadApp.html) 9 | 10 | ## 预执行 11 | 12 | 预执行指的是在应用空闲的时候将子应用提前渲染出来,可以进一步提升子应用打开时间 13 | 14 | 只需要在`preloadApp`中将 [exec](/api/preloadApp.html#exec) 设置为`true`即可 15 | 16 | 由于子应用提前渲染可能会导致阻塞主应用的线程,所以无界提供了类似 [react-fiber](https://github.com/acdlite/react-fiber-architecture) 方式来防止阻塞线程,详见 [fiber](/api/startApp.html#fiber) 17 | -------------------------------------------------------------------------------- /docs/guide/share.md: -------------------------------------------------------------------------------- 1 | 2 | # 应用共享 3 | 4 | 一个微前端系统可能同时运行多个子应用,不同子应用之间可能存在相同的包依赖,那么这个依赖就会在不同子应用中重复打包、重复执行造成性能和内存的浪费 5 | 6 | 这里提供一种工程上的策略结合无界的插件能力,可以有效的解决这个问题 7 | 8 | 以这个场景举例:主应用使用到了`lodash`,子应用 A 也使用到了相同版本的`lodash` 9 | 10 | ::: warning 警告 11 | 应用共享原理是主应用和子应用运行iframe沙箱同域可以共享内存,对于组件库这样有副作用的第三方包,可能无法共享 12 | ::: 13 | 14 | 15 | ## 子应用只运行在微前端框架 16 | 17 | 主应用: 18 | 19 | 1. 修改主应用的`index.js`,将共享包挂载到主应用的`window`对象上 20 | 21 | ```javascript 22 | // index.js 23 | import lodash from "lodash"; 24 | 25 | // 将需要共享的包挂载到主应用全局 26 | window.lodash = lodash; 27 | ``` 28 | 29 | 2. 加载子应用时注入插件,将主应用的`lodash`赋值到子应用的`window`对象上 30 | 31 | ```vue 32 | 37 | ``` 38 | 39 | 子应用: `webpack` 设置 `externals` 40 | 41 | ```javascript 42 | module.exports = { 43 | externals: { 44 | "lodash": { 45 | root: "lodash", 46 | commonjs: "lodash", 47 | commonjs2: "lodash", 48 | amd: "lodash", 49 | }, 50 | }, 51 | }; 52 | ``` 53 | 54 | ## 子应用需要单独运行 55 | 56 | 子应用如果需要单独运行的话,由于上面步骤将`lodash` `externals` 掉了所以子应用运行会报错,为了让子应用可以单独运行需要做如下步骤: 57 | 58 | 1. 此时需要将子应用 `externals` 掉的包单独打成一个包(比如:`A.bundle.js`),这个包需要打包`lodash`并将其注入到`window`中 59 | 60 | 2. 在子应用的`html`的`head`中将`A.bundle.js`放进去 61 | 62 | ```html 63 | 64 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /examples/angular12/.browserslistrc: -------------------------------------------------------------------------------- 1 | # This file is used by the build system to adjust CSS and JS output to support the specified browsers below. 2 | # For additional information regarding the format and rule options, please see: 3 | # https://github.com/browserslist/browserslist#queries 4 | 5 | # For the full list of supported browsers by the Angular framework, please see: 6 | # https://angular.io/guide/browser-support 7 | 8 | # You can see what browsers were selected by your queries by running: 9 | # npx browserslist 10 | 11 | last 1 Chrome version 12 | last 1 Firefox version 13 | last 2 Edge major versions 14 | last 2 Safari major versions 15 | last 2 iOS major versions 16 | Firefox ESR 17 | IE 11 # Angular supports IE 11 only as an opt-in. To opt-in, remove the 'not' prefix on this line. 18 | -------------------------------------------------------------------------------- /examples/angular12/.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see https://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.ts] 12 | quote_type = single 13 | 14 | [*.md] 15 | max_line_length = off 16 | trim_trailing_whitespace = false 17 | -------------------------------------------------------------------------------- /examples/angular12/.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # compiled output 4 | /dist 5 | /tmp 6 | /out-tsc 7 | # Only exists if Bazel was run 8 | /bazel-out 9 | 10 | # dependencies 11 | /node_modules 12 | 13 | # profiling files 14 | chrome-profiler-events*.json 15 | 16 | # IDEs and editors 17 | /.idea 18 | .project 19 | .classpath 20 | .c9/ 21 | *.launch 22 | .settings/ 23 | *.sublime-workspace 24 | 25 | # IDE - VSCode 26 | .vscode/* 27 | !.vscode/settings.json 28 | !.vscode/tasks.json 29 | !.vscode/launch.json 30 | !.vscode/extensions.json 31 | .history/* 32 | 33 | # misc 34 | /.sass-cache 35 | /connect.lock 36 | /coverage 37 | /libpeerconnection.log 38 | npm-debug.log 39 | yarn-error.log 40 | testem.log 41 | /typings 42 | 43 | # System Files 44 | .DS_Store 45 | Thumbs.db 46 | -------------------------------------------------------------------------------- /examples/angular12/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to this project will be documented in this file. 4 | See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. 5 | 6 | ## [1.0.23](https://github.com/Tencent/wujie/compare/v1.0.22...v1.0.23) (2024-11-24) 7 | 8 | ### Features 9 | 10 | * unmount hook support promise ([#645](https://github.com/Tencent/wujie/issues/645)) ([18be78b](https://github.com/Tencent/wujie/commit/18be78b336c2ab90fb0e85096c4281be3a1d49cb)) 11 | 12 | # [1.0.0](https://github.com/Tencent/wujie/compare/v1.0.0-rc.25...v1.0.0) (2022-11-10) 13 | 14 | ### Features 15 | 16 | * ie11 compatibility ([#248](https://github.com/Tencent/wujie/issues/248)) ([f6fd307](https://github.com/Tencent/wujie/commit/f6fd307c3365801a300ea22050aca1447f81b197)), closes [#185](https://github.com/Tencent/wujie/issues/185) [#185](https://github.com/Tencent/wujie/issues/185) 17 | 18 | # 1.0.0-rc.0 (2022-08-26) 19 | 20 | ### Features 21 | 22 | * init ([30397aa](https://github.com/Tencent/wujie/commit/30397aaa675a4d07bde278aa9d30447c7efe6625)) 23 | -------------------------------------------------------------------------------- /examples/angular12/README.md: -------------------------------------------------------------------------------- 1 | # Angular12 2 | 3 | This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 12.2.9. 4 | 5 | ## Development server 6 | 7 | Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files. 8 | 9 | ## Code scaffolding 10 | 11 | Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`. 12 | 13 | ## Build 14 | 15 | Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. 16 | 17 | ## Running unit tests 18 | 19 | Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io). 20 | 21 | ## Running end-to-end tests 22 | 23 | Run `ng e2e` to execute the end-to-end tests via a platform of your choice. To use this command, you need to first add a package that implements end-to-end testing capabilities. 24 | 25 | ## Further help 26 | 27 | To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.io/cli) page. 28 | -------------------------------------------------------------------------------- /examples/angular12/karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration file, see link for more information 2 | // https://karma-runner.github.io/1.0/config/configuration-file.html 3 | 4 | module.exports = function (config) { 5 | config.set({ 6 | basePath: '', 7 | frameworks: ['jasmine', '@angular-devkit/build-angular'], 8 | plugins: [ 9 | require('karma-jasmine'), 10 | require('karma-chrome-launcher'), 11 | require('karma-jasmine-html-reporter'), 12 | require('karma-coverage'), 13 | require('@angular-devkit/build-angular/plugins/karma') 14 | ], 15 | client: { 16 | jasmine: { 17 | // you can add configuration options for Jasmine here 18 | // the possible options are listed at https://jasmine.github.io/api/edge/Configuration.html 19 | // for example, you can disable the random execution with `random: false` 20 | // or set a specific seed with `seed: 4321` 21 | }, 22 | clearContext: false // leave Jasmine Spec Runner output visible in browser 23 | }, 24 | jasmineHtmlReporter: { 25 | suppressAll: true // removes the duplicated traces 26 | }, 27 | coverageReporter: { 28 | dir: require('path').join(__dirname, './coverage/angular12'), 29 | subdir: '.', 30 | reporters: [ 31 | { type: 'html' }, 32 | { type: 'text-summary' } 33 | ] 34 | }, 35 | reporters: ['progress', 'kjhtml'], 36 | port: 9876, 37 | colors: true, 38 | logLevel: config.LOG_INFO, 39 | autoWatch: true, 40 | browsers: ['Chrome'], 41 | singleRun: false, 42 | restartOnFileChange: true 43 | }); 44 | }; 45 | -------------------------------------------------------------------------------- /examples/angular12/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular12", 3 | "version": "1.0.23", 4 | "scripts": { 5 | "ng": "ng", 6 | "start": "ng serve", 7 | "build": "ng build --deploy-url='/demo-angular12/'", 8 | "watch": "ng build --watch --configuration development", 9 | "test": "ng test" 10 | }, 11 | "private": true, 12 | "dependencies": { 13 | "@angular/animations": "~12.2.0", 14 | "@angular/common": "~12.2.0", 15 | "@angular/compiler": "~12.2.0", 16 | "@angular/core": "~12.2.0", 17 | "@angular/forms": "~12.2.0", 18 | "@angular/platform-browser": "~12.2.0", 19 | "@angular/platform-browser-dynamic": "~12.2.0", 20 | "@angular/router": "~12.2.0", 21 | "rxjs": "~6.6.0", 22 | "tslib": "^2.3.0", 23 | "zone.js": "~0.11.4" 24 | }, 25 | "devDependencies": { 26 | "@angular-devkit/build-angular": "~12.2.9", 27 | "@angular/cli": "~12.2.9", 28 | "@angular/compiler-cli": "~12.2.0", 29 | "@types/jasmine": "~3.8.0", 30 | "@types/node": "^12.11.1", 31 | "jasmine-core": "~3.8.0", 32 | "karma": "~6.3.0", 33 | "karma-chrome-launcher": "~3.1.0", 34 | "karma-coverage": "~2.0.3", 35 | "karma-jasmine": "~4.0.0", 36 | "karma-jasmine-html-reporter": "~1.7.0", 37 | "typescript": "~4.3.5" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /examples/angular12/src/app/app-routing.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { RouterModule, Routes } from '@angular/router'; 3 | 4 | const routes: Routes = [{ path: '**', children: [] }]; 5 | 6 | @NgModule({ 7 | imports: [RouterModule.forRoot(routes)], 8 | exports: [RouterModule], 9 | }) 10 | export class AppRoutingModule {} 11 | -------------------------------------------------------------------------------- /examples/angular12/src/app/app.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Tencent/wujie/b9e435a0ae229103608ab9b05be20fde428c9957/examples/angular12/src/app/app.component.scss -------------------------------------------------------------------------------- /examples/angular12/src/app/app.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | import { RouterTestingModule } from '@angular/router/testing'; 3 | import { AppComponent } from './app.component'; 4 | 5 | describe('AppComponent', () => { 6 | beforeEach(async () => { 7 | await TestBed.configureTestingModule({ 8 | imports: [ 9 | RouterTestingModule 10 | ], 11 | declarations: [ 12 | AppComponent 13 | ], 14 | }).compileComponents(); 15 | }); 16 | 17 | it('should create the app', () => { 18 | const fixture = TestBed.createComponent(AppComponent); 19 | const app = fixture.componentInstance; 20 | expect(app).toBeTruthy(); 21 | }); 22 | 23 | it(`should have as title 'angular12'`, () => { 24 | const fixture = TestBed.createComponent(AppComponent); 25 | const app = fixture.componentInstance; 26 | expect(app.title).toEqual('angular12'); 27 | }); 28 | 29 | it('should render title', () => { 30 | const fixture = TestBed.createComponent(AppComponent); 31 | fixture.detectChanges(); 32 | const compiled = fixture.nativeElement as HTMLElement; 33 | expect(compiled.querySelector('.content span')?.textContent).toContain('angular12 app is running!'); 34 | }); 35 | }); 36 | -------------------------------------------------------------------------------- /examples/angular12/src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-root', 5 | templateUrl: './app.component.html', 6 | styleUrls: ['./app.component.scss'] 7 | }) 8 | export class AppComponent { 9 | title = 'angular12'; 10 | } 11 | -------------------------------------------------------------------------------- /examples/angular12/src/app/app.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { BrowserModule } from '@angular/platform-browser'; 3 | 4 | import { AppRoutingModule } from './app-routing.module'; 5 | import { AppComponent } from './app.component'; 6 | 7 | @NgModule({ 8 | declarations: [ 9 | AppComponent 10 | ], 11 | imports: [ 12 | BrowserModule, 13 | AppRoutingModule 14 | ], 15 | providers: [], 16 | bootstrap: [AppComponent] 17 | }) 18 | export class AppModule { } 19 | -------------------------------------------------------------------------------- /examples/angular12/src/assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Tencent/wujie/b9e435a0ae229103608ab9b05be20fde428c9957/examples/angular12/src/assets/.gitkeep -------------------------------------------------------------------------------- /examples/angular12/src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true 3 | }; 4 | -------------------------------------------------------------------------------- /examples/angular12/src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | // This file can be replaced during build by using the `fileReplacements` array. 2 | // `ng build` replaces `environment.ts` with `environment.prod.ts`. 3 | // The list of file replacements can be found in `angular.json`. 4 | 5 | export const environment = { 6 | production: false 7 | }; 8 | 9 | /* 10 | * For easier debugging in development mode, you can import the following file 11 | * to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`. 12 | * 13 | * This import should be commented out in production mode because it will have a negative impact 14 | * on performance if an error is thrown. 15 | */ 16 | // import 'zone.js/plugins/zone-error'; // Included with Angular CLI. 17 | -------------------------------------------------------------------------------- /examples/angular12/src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Tencent/wujie/b9e435a0ae229103608ab9b05be20fde428c9957/examples/angular12/src/favicon.ico -------------------------------------------------------------------------------- /examples/angular12/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Angular12 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /examples/angular12/src/main.ts: -------------------------------------------------------------------------------- 1 | import { enableProdMode } from '@angular/core' 2 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic' 3 | 4 | import { AppModule } from './app/app.module' 5 | import { environment } from './environments/environment' 6 | 7 | declare global { 8 | interface Window { 9 | // 是否存在无界 10 | __POWERED_BY_WUJIE__?: boolean; 11 | // 子应用公共加载路径 12 | __WUJIE_PUBLIC_PATH__: string; 13 | // 子应用mount函数 14 | __WUJIE_MOUNT: () => void; 15 | // 子应用unmount函数 16 | __WUJIE_UNMOUNT: () => void | Promise; 17 | } 18 | } 19 | 20 | if (environment.production) { 21 | enableProdMode() 22 | } 23 | 24 | if (window.__POWERED_BY_WUJIE__) { 25 | let instance: any 26 | window.__WUJIE_MOUNT = async () => { 27 | instance = await platformBrowserDynamic().bootstrapModule(AppModule) 28 | } 29 | window.__WUJIE_UNMOUNT = () => { 30 | instance.destroy() 31 | } 32 | } else { 33 | platformBrowserDynamic().bootstrapModule(AppModule) 34 | .catch(err => console.error(err)) 35 | } 36 | -------------------------------------------------------------------------------- /examples/angular12/src/styles.scss: -------------------------------------------------------------------------------- 1 | /* You can add global styles to this file, and also import other style files */ 2 | -------------------------------------------------------------------------------- /examples/angular12/src/test.ts: -------------------------------------------------------------------------------- 1 | // This file is required by karma.conf.js and loads recursively all the .spec and framework files 2 | 3 | import 'zone.js/testing'; 4 | import { getTestBed } from '@angular/core/testing'; 5 | import { 6 | BrowserDynamicTestingModule, 7 | platformBrowserDynamicTesting 8 | } from '@angular/platform-browser-dynamic/testing'; 9 | 10 | declare const require: { 11 | context(path: string, deep?: boolean, filter?: RegExp): { 12 | keys(): string[]; 13 | (id: string): T; 14 | }; 15 | }; 16 | 17 | // First, initialize the Angular testing environment. 18 | getTestBed().initTestEnvironment( 19 | BrowserDynamicTestingModule, 20 | platformBrowserDynamicTesting(), 21 | { teardown: { destroyAfterEach: true }}, 22 | ); 23 | 24 | // Then we find all the tests. 25 | const context = require.context('./', true, /\.spec\.ts$/); 26 | // And load the modules. 27 | context.keys().map(context); 28 | -------------------------------------------------------------------------------- /examples/angular12/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */ 2 | { 3 | "extends": "./tsconfig.json", 4 | "compilerOptions": { 5 | "outDir": "./out-tsc/app", 6 | "types": [] 7 | }, 8 | "files": [ 9 | "src/main.ts", 10 | "src/polyfills.ts" 11 | ], 12 | "include": [ 13 | "src/**/*.d.ts" 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /examples/angular12/tsconfig.json: -------------------------------------------------------------------------------- 1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */ 2 | { 3 | "compileOnSave": false, 4 | "compilerOptions": { 5 | "baseUrl": "./", 6 | "outDir": "./dist/out-tsc", 7 | "forceConsistentCasingInFileNames": true, 8 | "strict": true, 9 | "noImplicitReturns": true, 10 | "noFallthroughCasesInSwitch": true, 11 | "sourceMap": true, 12 | "declaration": false, 13 | "downlevelIteration": true, 14 | "experimentalDecorators": true, 15 | "moduleResolution": "node", 16 | "importHelpers": true, 17 | "target": "es5", 18 | "module": "es2020", 19 | "lib": [ 20 | "es2018", 21 | "dom" 22 | ] 23 | }, 24 | "angularCompilerOptions": { 25 | "enableI18nLegacyMessageIdFormat": false, 26 | "strictInjectionParameters": true, 27 | "strictInputAccessModifiers": true, 28 | "strictTemplates": true 29 | } 30 | } -------------------------------------------------------------------------------- /examples/angular12/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */ 2 | { 3 | "extends": "./tsconfig.json", 4 | "compilerOptions": { 5 | "outDir": "./out-tsc/spec", 6 | "types": [ 7 | "jasmine" 8 | ] 9 | }, 10 | "files": [ 11 | "src/test.ts", 12 | "src/polyfills.ts" 13 | ], 14 | "include": [ 15 | "src/**/*.spec.ts", 16 | "src/**/*.d.ts" 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /examples/main-react/.env: -------------------------------------------------------------------------------- 1 | SKIP_PREFLIGHT_CHECK=true 2 | PORT=7700 3 | WDS_SOCKET_PORT=7700 -------------------------------------------------------------------------------- /examples/main-react/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | -------------------------------------------------------------------------------- /examples/main-react/config/jest/babelTransform.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const babelJest = require('babel-jest').default; 4 | 5 | const hasJsxRuntime = (() => { 6 | if (process.env.DISABLE_NEW_JSX_TRANSFORM === 'true') { 7 | return false; 8 | } 9 | 10 | try { 11 | require.resolve('react/jsx-runtime'); 12 | return true; 13 | } catch (e) { 14 | return false; 15 | } 16 | })(); 17 | 18 | module.exports = babelJest.createTransformer({ 19 | presets: [ 20 | [ 21 | require.resolve('babel-preset-react-app'), 22 | { 23 | runtime: hasJsxRuntime ? 'automatic' : 'classic', 24 | }, 25 | ], 26 | ], 27 | babelrc: false, 28 | configFile: false, 29 | }); 30 | -------------------------------------------------------------------------------- /examples/main-react/config/jest/cssTransform.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // This is a custom Jest transformer turning style imports into empty objects. 4 | // http://facebook.github.io/jest/docs/en/webpack.html 5 | 6 | module.exports = { 7 | process() { 8 | return 'module.exports = {};'; 9 | }, 10 | getCacheKey() { 11 | // The output is always the same. 12 | return 'cssTransform'; 13 | }, 14 | }; 15 | -------------------------------------------------------------------------------- /examples/main-react/config/jest/fileTransform.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const path = require('path'); 4 | const camelcase = require('camelcase'); 5 | 6 | // This is a custom Jest transformer turning file imports into filenames. 7 | // http://facebook.github.io/jest/docs/en/webpack.html 8 | 9 | module.exports = { 10 | process(src, filename) { 11 | const assetFilename = JSON.stringify(path.basename(filename)); 12 | 13 | if (filename.match(/\.svg$/)) { 14 | // Based on how SVGR generates a component name: 15 | // https://github.com/smooth-code/svgr/blob/01b194cf967347d43d4cbe6b434404731b87cf27/packages/core/src/state.js#L6 16 | const pascalCaseFilename = camelcase(path.parse(filename).name, { 17 | pascalCase: true, 18 | }); 19 | const componentName = `Svg${pascalCaseFilename}`; 20 | return `const React = require('react'); 21 | module.exports = { 22 | __esModule: true, 23 | default: ${assetFilename}, 24 | ReactComponent: React.forwardRef(function ${componentName}(props, ref) { 25 | return { 26 | $$typeof: Symbol.for('react.element'), 27 | type: 'svg', 28 | ref: ref, 29 | key: null, 30 | props: Object.assign({}, props, { 31 | children: ${assetFilename} 32 | }) 33 | }; 34 | }), 35 | };`; 36 | } 37 | 38 | return `module.exports = ${assetFilename};`; 39 | }, 40 | }; 41 | -------------------------------------------------------------------------------- /examples/main-react/config/webpack/persistentCache/createEnvironmentHash.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | const { createHash } = require('crypto'); 3 | 4 | module.exports = env => { 5 | const hash = createHash('md5'); 6 | hash.update(JSON.stringify(env)); 7 | 8 | return hash.digest('hex'); 9 | }; 10 | -------------------------------------------------------------------------------- /examples/main-react/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Tencent/wujie/b9e435a0ae229103608ab9b05be20fde428c9957/examples/main-react/public/favicon.ico -------------------------------------------------------------------------------- /examples/main-react/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 15 | 16 | 25 | 无界react-demo展示 26 | 27 | 28 | 29 | 30 |
31 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /examples/main-react/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Tencent/wujie/b9e435a0ae229103608ab9b05be20fde428c9957/examples/main-react/public/logo192.png -------------------------------------------------------------------------------- /examples/main-react/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Tencent/wujie/b9e435a0ae229103608ab9b05be20fde428c9957/examples/main-react/public/logo512.png -------------------------------------------------------------------------------- /examples/main-react/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "logo192.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "logo512.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /examples/main-react/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /examples/main-react/scripts/test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // Do this as the first thing so that any code reading it knows the right env. 4 | process.env.BABEL_ENV = 'test'; 5 | process.env.NODE_ENV = 'test'; 6 | process.env.PUBLIC_URL = ''; 7 | 8 | // Makes the script crash on unhandled rejections instead of silently 9 | // ignoring them. In the future, promise rejections that are not handled will 10 | // terminate the Node.js process with a non-zero exit code. 11 | process.on('unhandledRejection', err => { 12 | throw err; 13 | }); 14 | 15 | // Ensure environment variables are read. 16 | require('../config/env'); 17 | 18 | const jest = require('jest'); 19 | const execSync = require('child_process').execSync; 20 | let argv = process.argv.slice(2); 21 | 22 | function isInGitRepository() { 23 | try { 24 | execSync('git rev-parse --is-inside-work-tree', { stdio: 'ignore' }); 25 | return true; 26 | } catch (e) { 27 | return false; 28 | } 29 | } 30 | 31 | function isInMercurialRepository() { 32 | try { 33 | execSync('hg --cwd . root', { stdio: 'ignore' }); 34 | return true; 35 | } catch (e) { 36 | return false; 37 | } 38 | } 39 | 40 | // Watch unless on CI or explicitly running all tests 41 | if ( 42 | !process.env.CI && 43 | argv.indexOf('--watchAll') === -1 && 44 | argv.indexOf('--watchAll=false') === -1 45 | ) { 46 | // https://github.com/facebook/create-react-app/issues/5210 47 | const hasSourceControl = isInGitRepository() || isInMercurialRepository(); 48 | argv.push(hasSourceControl ? '--watch' : '--watchAll'); 49 | } 50 | 51 | 52 | jest.run(argv); 53 | -------------------------------------------------------------------------------- /examples/main-react/src/App.test.js: -------------------------------------------------------------------------------- 1 | import { render, screen } from '@testing-library/react'; 2 | import App from './App'; 3 | 4 | test('renders learn react link', () => { 5 | render(); 6 | const linkElement = screen.getByText(/learn react/i); 7 | expect(linkElement).toBeInTheDocument(); 8 | }); 9 | -------------------------------------------------------------------------------- /examples/main-react/src/fetch.js: -------------------------------------------------------------------------------- 1 | // 携带登录态credentials必须为include 2 | export default function fetch(url, options) { 3 | return window.fetch(url, { ...options, credentials: "omit" }); 4 | } 5 | -------------------------------------------------------------------------------- /examples/main-react/src/hostMap.js: -------------------------------------------------------------------------------- 1 | const map = { 2 | "//localhost:7100/": "//wujie-micro.github.io/demo-react17/", 3 | "//localhost:7200/": "//wujie-micro.github.io/demo-vue2/", 4 | "//localhost:7300/": "//wujie-micro.github.io/demo-vue3/", 5 | "//localhost:7400/": "//wujie-micro.github.io/demo-angular12/", 6 | "//localhost:7500/": "//wujie-micro.github.io/demo-vite/", 7 | "//localhost:7600/": "//wujie-micro.github.io/demo-react16/", 8 | "//localhost:7700/": "//wujie-micro.github.io/demo-main-react/", 9 | "//localhost:8000/": "//wujie-micro.github.io/demo-main-vue/", 10 | }; 11 | 12 | export default function hostMap(host) { 13 | if (process.env.NODE_ENV === "production") return map[host]; 14 | return host; 15 | } 16 | -------------------------------------------------------------------------------- /examples/main-react/src/lifecycle.js: -------------------------------------------------------------------------------- 1 | const lifecycles = { 2 | beforeLoad: (appWindow) => console.log(`${appWindow.__WUJIE.id} beforeLoad 生命周期`), 3 | beforeMount: (appWindow) => console.log(`${appWindow.__WUJIE.id} beforeMount 生命周期`), 4 | afterMount: (appWindow) => console.log(`${appWindow.__WUJIE.id} afterMount 生命周期`), 5 | beforeUnmount: (appWindow) => console.log(`${appWindow.__WUJIE.id} beforeUnmount 生命周期`), 6 | afterUnmount: (appWindow) => console.log(`${appWindow.__WUJIE.id} afterUnmount 生命周期`), 7 | activated: (appWindow) => console.log(`${appWindow.__WUJIE.id} activated 生命周期`), 8 | deactivated: (appWindow) => console.log(`${appWindow.__WUJIE.id} deactivated 生命周期`), 9 | loadError: (url, e) => console.log(`${url} 加载失败`, e), 10 | }; 11 | 12 | export default lifecycles; 13 | -------------------------------------------------------------------------------- /examples/main-react/src/pages/Angular12.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import hostMap from "../hostMap"; 3 | import WujieReact from "wujie-react"; 4 | import { useNavigate } from "react-router-dom"; 5 | 6 | export default function Angular12() { 7 | const navigation = useNavigate(); 8 | const angular12Url = hostMap("//localhost:7400/"); 9 | const props = { 10 | jump: (name) => { 11 | navigation(`/${name}`); 12 | }, 13 | }; 14 | return ( 15 | 23 | ); 24 | } 25 | -------------------------------------------------------------------------------- /examples/main-react/src/pages/React16.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import hostMap from "../hostMap"; 3 | import WujieReact from "wujie-react"; 4 | import { useNavigate, useLocation } from "react-router-dom"; 5 | 6 | export default function React16() { 7 | const navigation = useNavigate(); 8 | const location = useLocation(); 9 | const path = location.pathname.replace("/react16-sub", "").replace("/react16", "").replace("/",""); //// 10 | const react16Url = hostMap("//localhost:7600/") + path; 11 | const props = { 12 | jump: (name) => { 13 | navigation(`/${name}`); 14 | }, 15 | }; 16 | return ( 17 | // 单例模式,name相同则复用一个无界实例,改变url则子应用重新渲染实例到对应路由 18 | 26 | ); 27 | } 28 | -------------------------------------------------------------------------------- /examples/main-react/src/pages/React17.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import hostMap from "../hostMap"; 3 | import WujieReact from "wujie-react"; 4 | import { useNavigate, useLocation } from "react-router-dom"; 5 | 6 | export default function React17() { 7 | const location = useLocation(); 8 | const navigation = useNavigate(); 9 | const react17Url = hostMap("//localhost:7100/"); 10 | const path = location.pathname.replace("/react17-sub", "").replace("/react17", "");//// 11 | // 告诉子应用要跳转哪个路由 12 | path && WujieReact.bus.$emit("react17-router-change", path); 13 | const props = { 14 | jump: (name) => { 15 | navigation(`/${name}`); 16 | }, 17 | }; 18 | return ( 19 | // 保活模式,name相同则复用一个子应用实例,改变url无效,必须采用通信的方式告知路由变化 20 | 28 | ); 29 | } 30 | -------------------------------------------------------------------------------- /examples/main-react/src/pages/Vite.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import hostMap from "../hostMap"; 3 | import WujieReact from "wujie-react"; 4 | import { useNavigate, useLocation } from "react-router-dom"; 5 | 6 | export default function Vite() { 7 | const location = useLocation(); 8 | const navigation = useNavigate(); 9 | const path = location.pathname.replace("/vite-sub", "").replace("/vite", "").replace("/", "");//// 10 | const viteUrl = hostMap("//localhost:7500/") + path; 11 | const props = { 12 | jump: (name) => { 13 | navigation(`/${name}`); 14 | }, 15 | }; 16 | return ( 17 | // 单例模式,name相同则复用一个无界实例,改变url则子应用重新渲染实例到对应路由 18 | 26 | ); 27 | } 28 | -------------------------------------------------------------------------------- /examples/main-react/src/pages/Vue2.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import hostMap from "../hostMap"; 3 | import WujieReact from "wujie-react"; 4 | import { useNavigate, useLocation } from "react-router-dom"; 5 | 6 | export default function Vue2() { 7 | const location = useLocation(); 8 | const navigation = useNavigate(); 9 | const path = location.pathname.replace("/vue2-sub", "").replace("/vue2", "");//// 10 | const vue2Url = hostMap("//localhost:7200/") + "#" + path; 11 | const props = { 12 | jump: (name) => { 13 | navigation(`/${name}`); 14 | }, 15 | }; 16 | return ( 17 | // 单例模式,name相同则复用一个无界实例,改变url则子应用重新渲染实例到对应路由 18 | 26 | ); 27 | } 28 | -------------------------------------------------------------------------------- /examples/main-react/src/pages/Vue3.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import hostMap from "../hostMap"; 3 | import WujieReact from "wujie-react"; 4 | import { useNavigate, useLocation } from "react-router-dom"; 5 | 6 | export default function Vue3() { 7 | const location = useLocation(); 8 | const navigation = useNavigate(); 9 | const path = location.pathname.replace("/vue3-sub", "").replace("/vue3", "");//// 10 | const vue3Url = hostMap("//localhost:7300/"); 11 | // 告诉子应用要跳转哪个路由 12 | path && WujieReact.bus.$emit("vue3-router-change", path); 13 | const props = { 14 | jump: (name) => { 15 | navigation(`/${name}`); 16 | }, 17 | }; 18 | return ( 19 | 27 | ); 28 | } 29 | -------------------------------------------------------------------------------- /examples/main-react/src/plugin.js: -------------------------------------------------------------------------------- 1 | const plugins = [ 2 | { 3 | htmlLoader: (code) => { 4 | console.log("html-loader"); 5 | return code; 6 | }, 7 | jsBeforeLoaders: [ 8 | { 9 | callback(appWindow) { 10 | console.log("js-before-loader-callback", appWindow.__WUJIE.id); 11 | }, 12 | }, 13 | ], 14 | jsLoader: (code, url) => { 15 | console.log("js-loader", url); 16 | return code; 17 | }, 18 | jsAfterLoaders: [ 19 | { 20 | callback(appWindow) { 21 | console.log("js-after-loader-callback", appWindow.__WUJIE.id); 22 | }, 23 | }, 24 | ], 25 | cssBeforeLoaders: [ 26 | //在加载html所有的样式之前添加一个外联样式 27 | { src: "https://vfiles.gtimg.cn/wuji_dashboard/xy/test_wuji_damy/HDaBURp7.css" }, 28 | //在加载html所有的样式之前添加一个内联样式 29 | { content: "img{width: 300px}" }, 30 | ], 31 | cssLoader: (code, url) => { 32 | console.log("css-loader", url, code.slice(0, 50) + "..."); 33 | return code; 34 | }, 35 | cssAfterLoaders: [ 36 | //在加载html所有样式之后添加一个外联样式 37 | { src: "https://vfiles.gtimg.cn/wuji_dashboard/xy/test_wuji_damy/FQsK8IN6.css" }, 38 | //在加载html所有样式之后添加一个内联样式 39 | { content: "img{height: 300px}" }, 40 | ], 41 | }, 42 | ]; 43 | 44 | export default plugins; 45 | -------------------------------------------------------------------------------- /examples/main-react/src/reportWebVitals.js: -------------------------------------------------------------------------------- 1 | const reportWebVitals = onPerfEntry => { 2 | if (onPerfEntry && onPerfEntry instanceof Function) { 3 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { 4 | getCLS(onPerfEntry); 5 | getFID(onPerfEntry); 6 | getFCP(onPerfEntry); 7 | getLCP(onPerfEntry); 8 | getTTFB(onPerfEntry); 9 | }); 10 | } 11 | }; 12 | 13 | export default reportWebVitals; 14 | -------------------------------------------------------------------------------- /examples/main-react/src/setupTests.js: -------------------------------------------------------------------------------- 1 | // jest-dom adds custom jest matchers for asserting on DOM nodes. 2 | // allows you to do things like: 3 | // expect(element).toHaveTextContent(/react/i) 4 | // learn more: https://github.com/testing-library/jest-dom 5 | import '@testing-library/jest-dom'; 6 | -------------------------------------------------------------------------------- /examples/main-vue/.browserslistrc: -------------------------------------------------------------------------------- 1 | > 1% 2 | last 2 versions 3 | ie >= 11 4 | -------------------------------------------------------------------------------- /examples/main-vue/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | env: { 4 | node: true, 5 | }, 6 | extends: ["plugin:vue/essential", "eslint:recommended", "@vue/prettier"], 7 | parserOptions: { 8 | parser: "babel-eslint", 9 | }, 10 | ignorePatterns: ["**/*.ts", "node_modules"], 11 | rules: { 12 | "no-console": process.env.NODE_ENV === "production" ? "warn" : "off", 13 | "no-debugger": process.env.NODE_ENV === "production" ? "warn" : "off", 14 | "no-prototype-builtins": "off", 15 | }, 16 | }; 17 | -------------------------------------------------------------------------------- /examples/main-vue/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | 5 | 6 | # local env files 7 | .env.local 8 | .env.*.local 9 | 10 | # Log files 11 | npm-debug.log* 12 | yarn-debug.log* 13 | yarn-error.log* 14 | pnpm-debug.log* 15 | 16 | # Editor directories and files 17 | .idea 18 | .vscode 19 | *.suo 20 | *.ntvs* 21 | *.njsproj 22 | *.sln 23 | *.sw? 24 | -------------------------------------------------------------------------------- /examples/main-vue/README.md: -------------------------------------------------------------------------------- 1 | # multiple 2 | 3 | ## Project setup 4 | ``` 5 | yarn install 6 | ``` 7 | 8 | ### Compiles and hot-reloads for development 9 | ``` 10 | yarn serve 11 | ``` 12 | 13 | ### Compiles and minifies for production 14 | ``` 15 | yarn build 16 | ``` 17 | 18 | ### Lints and fixes files 19 | ``` 20 | yarn lint 21 | ``` 22 | 23 | ### Customize configuration 24 | See [Configuration Reference](https://cli.vuejs.org/config/). 25 | -------------------------------------------------------------------------------- /examples/main-vue/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: ["@vue/cli-plugin-babel/preset"], 3 | }; 4 | -------------------------------------------------------------------------------- /examples/main-vue/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "main-vue", 3 | "version": "1.0.28", 4 | "private": true, 5 | "scripts": { 6 | "start": "vue-cli-service serve", 7 | "build": "vue-cli-service build", 8 | "lint": "vue-cli-service lint" 9 | }, 10 | "dependencies": { 11 | "ant-design-vue": "^1.7.8", 12 | "core-js": "^3.6.5", 13 | "custom-event-polyfill": "^1.0.7", 14 | "vue": "^2.6.11", 15 | "vue-router": "^3.2.0", 16 | "whatwg-fetch": "^3.6.2", 17 | "wujie": "workspace:^1.0.28", 18 | "wujie-vue2": "workspace:^1.0.28" 19 | }, 20 | "devDependencies": { 21 | "@vue/cli-plugin-babel": "~4.5.0", 22 | "@vue/cli-plugin-eslint": "~4.5.0", 23 | "@vue/cli-plugin-router": "~4.5.0", 24 | "@vue/cli-service": "~4.5.0", 25 | "@vue/eslint-config-prettier": "^6.0.0", 26 | "babel-eslint": "^10.1.0", 27 | "eslint": "7.12.0", 28 | "eslint-plugin-prettier": "^3.3.1", 29 | "eslint-plugin-vue": "^6.2.2", 30 | "prettier": "^2.2.1", 31 | "vue-template-compiler": "^2.6.11" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /examples/main-vue/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Tencent/wujie/b9e435a0ae229103608ab9b05be20fde428c9957/examples/main-vue/public/favicon.ico -------------------------------------------------------------------------------- /examples/main-vue/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 无界vue-demo展示 10 | 11 | 12 | 13 | 16 |
17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /examples/main-vue/src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Tencent/wujie/b9e435a0ae229103608ab9b05be20fde428c9957/examples/main-vue/src/assets/logo.png -------------------------------------------------------------------------------- /examples/main-vue/src/fetch.js: -------------------------------------------------------------------------------- 1 | // 携带登录态credentials必须为include 2 | export default function fetch(url, options) { 3 | console.log("fetch", url, options); 4 | return window.fetch(url, { ...options, credentials: "omit" }); 5 | } 6 | -------------------------------------------------------------------------------- /examples/main-vue/src/hostMap.js: -------------------------------------------------------------------------------- 1 | const map = { 2 | "//localhost:7100/": "//wujie-micro.github.io/demo-react17/", 3 | "//localhost:7200/": "//wujie-micro.github.io/demo-vue2/", 4 | "//localhost:7300/": "//wujie-micro.github.io/demo-vue3/", 5 | "//localhost:7400/": "//wujie-micro.github.io/demo-angular12/", 6 | "//localhost:7500/": "//wujie-micro.github.io/demo-vite/", 7 | "//localhost:7600/": "//wujie-micro.github.io/demo-react16/", 8 | "//localhost:7700/": "//wujie-micro.github.io/demo-main-react/", 9 | "//localhost:8000/": "//wujie-micro.github.io/demo-main-vue/", 10 | }; 11 | 12 | export default function hostMap(host) { 13 | if (process.env.NODE_ENV === "production") return map[host]; 14 | return host; 15 | } 16 | -------------------------------------------------------------------------------- /examples/main-vue/src/lifecycle.js: -------------------------------------------------------------------------------- 1 | const lifecycles = { 2 | beforeLoad: (appWindow) => console.log(`${appWindow.__WUJIE.id} beforeLoad 生命周期`), 3 | beforeMount: (appWindow) => console.log(`${appWindow.__WUJIE.id} beforeMount 生命周期`), 4 | afterMount: (appWindow) => console.log(`${appWindow.__WUJIE.id} afterMount 生命周期`), 5 | beforeUnmount: (appWindow) => console.log(`${appWindow.__WUJIE.id} beforeUnmount 生命周期`), 6 | afterUnmount: (appWindow) => console.log(`${appWindow.__WUJIE.id} afterUnmount 生命周期`), 7 | activated: (appWindow) => console.log(`${appWindow.__WUJIE.id} activated 生命周期`), 8 | deactivated: (appWindow) => console.log(`${appWindow.__WUJIE.id} deactivated 生命周期`), 9 | loadError: (url, e) => console.log(`${url} 加载失败`, e), 10 | }; 11 | 12 | export default lifecycles; 13 | -------------------------------------------------------------------------------- /examples/main-vue/src/plugin.js: -------------------------------------------------------------------------------- 1 | const plugins = [ 2 | { 3 | htmlLoader: (code) => { 4 | console.log("html-loader"); 5 | return code; 6 | }, 7 | jsBeforeLoaders: [ 8 | { 9 | callback(appWindow) { 10 | console.log("js-before-loader-callback", appWindow.__WUJIE.id); 11 | }, 12 | }, 13 | ], 14 | jsLoader: (code, url) => { 15 | console.log("js-loader", url); 16 | return code; 17 | }, 18 | jsAfterLoaders: [ 19 | { 20 | callback(appWindow) { 21 | console.log("js-after-loader-callback", appWindow.__WUJIE.id); 22 | }, 23 | }, 24 | ], 25 | cssBeforeLoaders: [ 26 | //在加载html所有的样式之前添加一个外联样式 27 | { src: "https://vfiles.gtimg.cn/wuji_dashboard/xy/test_wuji_damy/HDaBURp7.css" }, 28 | //在加载html所有的样式之前添加一个内联样式 29 | { content: "img{width: 300px}" }, 30 | ], 31 | cssLoader: (code, url) => { 32 | console.log("css-loader", url, code.slice(0, 50) + "..."); 33 | return code; 34 | }, 35 | cssAfterLoaders: [ 36 | //在加载html所有样式之后添加一个外联样式 37 | { src: "https://vfiles.gtimg.cn/wuji_dashboard/xy/test_wuji_damy/FQsK8IN6.css" }, 38 | //在加载html所有样式之后添加一个内联样式 39 | { content: "img{height: 300px}" }, 40 | ], 41 | }, 42 | ]; 43 | 44 | export default plugins; 45 | -------------------------------------------------------------------------------- /examples/main-vue/src/views/Angular12.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 18 | 19 | 25 | -------------------------------------------------------------------------------- /examples/main-vue/src/views/Multiple.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 33 | 34 | 45 | -------------------------------------------------------------------------------- /examples/main-vue/src/views/React16-sub.vue: -------------------------------------------------------------------------------- 1 | 5 | 6 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /examples/main-vue/src/views/React16.vue: -------------------------------------------------------------------------------- 1 | 5 | 6 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /examples/main-vue/src/views/React17-sub.vue: -------------------------------------------------------------------------------- 1 | 5 | 6 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /examples/main-vue/src/views/React17.vue: -------------------------------------------------------------------------------- 1 | 5 | 6 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /examples/main-vue/src/views/Vite-sub.vue: -------------------------------------------------------------------------------- 1 | 5 | 6 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /examples/main-vue/src/views/Vite.vue: -------------------------------------------------------------------------------- 1 | 5 | 6 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /examples/main-vue/src/views/Vue2-sub.vue: -------------------------------------------------------------------------------- 1 | 5 | 6 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /examples/main-vue/src/views/Vue2.vue: -------------------------------------------------------------------------------- 1 | 5 | 6 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /examples/main-vue/src/views/Vue3-sub.vue: -------------------------------------------------------------------------------- 1 | 5 | 6 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /examples/main-vue/src/views/Vue3.vue: -------------------------------------------------------------------------------- 1 | 5 | 6 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /examples/main-vue/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es6", 4 | "module": "esnext", 5 | "lib": ["es2018", "dom"], 6 | "declaration": true, 7 | "outDir": "./esm", 8 | "rootDir": "../../../wujie", 9 | "importHelpers": true, 10 | "downlevelIteration": true, 11 | "strict": true, 12 | "noImplicitAny": true, 13 | "strictNullChecks": true, 14 | "resolveJsonModule": true, 15 | "strictFunctionTypes": true, 16 | "strictPropertyInitialization": true, 17 | "noImplicitThis": true, 18 | "alwaysStrict": true, 19 | "noUnusedLocals": true, 20 | "noUnusedParameters": true, 21 | "noImplicitReturns": true, 22 | "noFallthroughCasesInSwitch": true, 23 | "moduleResolution": "node", 24 | "typeRoots": ["typings", "node_modules/@types"], 25 | "allowSyntheticDefaultImports": true, 26 | "esModuleInterop": true, 27 | "experimentalDecorators": true, 28 | "sourceMap": true 29 | }, 30 | "exclude": ["node_modules", "examples", "**/*.test.ts"], 31 | "include": ["../../src"] 32 | } -------------------------------------------------------------------------------- /examples/main-vue/vue.config.js: -------------------------------------------------------------------------------- 1 | // vue.config.js 2 | 3 | /** 4 | * @type {import('@vue/cli-service').ProjectOptions} 5 | */ 6 | module.exports = { 7 | publicPath: process.env.NODE_ENV === "production" ? "/demo-main-vue/" : "/", 8 | devServer: { 9 | headers: { 10 | "Access-Control-Allow-Origin": "*", 11 | }, 12 | open: process.env.NODE_ENV === "development", 13 | port: "8000", 14 | }, 15 | transpileDependencies: [ 16 | "sockjs-client", 17 | ], 18 | }; 19 | -------------------------------------------------------------------------------- /examples/react16/.env: -------------------------------------------------------------------------------- 1 | SKIP_PREFLIGHT_CHECK=true 2 | PORT=7600 3 | WDS_SOCKET_PORT=7600 -------------------------------------------------------------------------------- /examples/react16/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | -------------------------------------------------------------------------------- /examples/react16/config/getHttpsConfig.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const fs = require('fs'); 4 | const path = require('path'); 5 | const crypto = require('crypto'); 6 | const chalk = require('react-dev-utils/chalk'); 7 | const paths = require('./paths'); 8 | 9 | // Ensure the certificate and key provided are valid and if not 10 | // throw an easy to debug error 11 | function validateKeyAndCerts({ cert, key, keyFile, crtFile }) { 12 | let encrypted; 13 | try { 14 | // publicEncrypt will throw an error with an invalid cert 15 | encrypted = crypto.publicEncrypt(cert, Buffer.from('test')); 16 | } catch (err) { 17 | throw new Error( 18 | `The certificate "${chalk.yellow(crtFile)}" is invalid.\n${err.message}` 19 | ); 20 | } 21 | 22 | try { 23 | // privateDecrypt will throw an error with an invalid key 24 | crypto.privateDecrypt(key, encrypted); 25 | } catch (err) { 26 | throw new Error( 27 | `The certificate key "${chalk.yellow(keyFile)}" is invalid.\n${ 28 | err.message 29 | }` 30 | ); 31 | } 32 | } 33 | 34 | // Read file and throw an error if it doesn't exist 35 | function readEnvFile(file, type) { 36 | if (!fs.existsSync(file)) { 37 | throw new Error( 38 | `You specified ${chalk.cyan( 39 | type 40 | )} in your env, but the file "${chalk.yellow(file)}" can't be found.` 41 | ); 42 | } 43 | return fs.readFileSync(file); 44 | } 45 | 46 | // Get the https config 47 | // Return cert files if provided in env, otherwise just true or false 48 | function getHttpsConfig() { 49 | const { SSL_CRT_FILE, SSL_KEY_FILE, HTTPS } = process.env; 50 | const isHttps = HTTPS === 'true'; 51 | 52 | if (isHttps && SSL_CRT_FILE && SSL_KEY_FILE) { 53 | const crtFile = path.resolve(paths.appPath, SSL_CRT_FILE); 54 | const keyFile = path.resolve(paths.appPath, SSL_KEY_FILE); 55 | const config = { 56 | cert: readEnvFile(crtFile, 'SSL_CRT_FILE'), 57 | key: readEnvFile(keyFile, 'SSL_KEY_FILE'), 58 | }; 59 | 60 | validateKeyAndCerts({ ...config, keyFile, crtFile }); 61 | return config; 62 | } 63 | return isHttps; 64 | } 65 | 66 | module.exports = getHttpsConfig; 67 | -------------------------------------------------------------------------------- /examples/react16/config/jest/babelTransform.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const babelJest = require('babel-jest').default; 4 | 5 | const hasJsxRuntime = (() => { 6 | if (process.env.DISABLE_NEW_JSX_TRANSFORM === 'true') { 7 | return false; 8 | } 9 | 10 | try { 11 | require.resolve('react/jsx-runtime'); 12 | return true; 13 | } catch (e) { 14 | return false; 15 | } 16 | })(); 17 | 18 | module.exports = babelJest.createTransformer({ 19 | presets: [ 20 | [ 21 | require.resolve('babel-preset-react-app'), 22 | { 23 | runtime: hasJsxRuntime ? 'automatic' : 'classic', 24 | }, 25 | ], 26 | ], 27 | babelrc: false, 28 | configFile: false, 29 | }); 30 | -------------------------------------------------------------------------------- /examples/react16/config/jest/cssTransform.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // This is a custom Jest transformer turning style imports into empty objects. 4 | // http://facebook.github.io/jest/docs/en/webpack.html 5 | 6 | module.exports = { 7 | process() { 8 | return 'module.exports = {};'; 9 | }, 10 | getCacheKey() { 11 | // The output is always the same. 12 | return 'cssTransform'; 13 | }, 14 | }; 15 | -------------------------------------------------------------------------------- /examples/react16/config/jest/fileTransform.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const path = require('path'); 4 | const camelcase = require('camelcase'); 5 | 6 | // This is a custom Jest transformer turning file imports into filenames. 7 | // http://facebook.github.io/jest/docs/en/webpack.html 8 | 9 | module.exports = { 10 | process(src, filename) { 11 | const assetFilename = JSON.stringify(path.basename(filename)); 12 | 13 | if (filename.match(/\.svg$/)) { 14 | // Based on how SVGR generates a component name: 15 | // https://github.com/smooth-code/svgr/blob/01b194cf967347d43d4cbe6b434404731b87cf27/packages/core/src/state.js#L6 16 | const pascalCaseFilename = camelcase(path.parse(filename).name, { 17 | pascalCase: true, 18 | }); 19 | const componentName = `Svg${pascalCaseFilename}`; 20 | return `const React = require('react'); 21 | module.exports = { 22 | __esModule: true, 23 | default: ${assetFilename}, 24 | ReactComponent: React.forwardRef(function ${componentName}(props, ref) { 25 | return { 26 | $$typeof: Symbol.for('react.element'), 27 | type: 'svg', 28 | ref: ref, 29 | key: null, 30 | props: Object.assign({}, props, { 31 | children: ${assetFilename} 32 | }) 33 | }; 34 | }), 35 | };`; 36 | } 37 | 38 | return `module.exports = ${assetFilename};`; 39 | }, 40 | }; 41 | -------------------------------------------------------------------------------- /examples/react16/config/webpack/persistentCache/createEnvironmentHash.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | const { createHash } = require('crypto'); 3 | 4 | module.exports = env => { 5 | const hash = createHash('md5'); 6 | hash.update(JSON.stringify(env)); 7 | 8 | return hash.digest('hex'); 9 | }; 10 | -------------------------------------------------------------------------------- /examples/react16/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Tencent/wujie/b9e435a0ae229103608ab9b05be20fde428c9957/examples/react16/public/favicon.ico -------------------------------------------------------------------------------- /examples/react16/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 17 | 18 | 27 | 无界react-demo展示 28 | 29 | 30 | 31 |
32 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /examples/react16/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Tencent/wujie/b9e435a0ae229103608ab9b05be20fde428c9957/examples/react16/public/logo192.png -------------------------------------------------------------------------------- /examples/react16/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Tencent/wujie/b9e435a0ae229103608ab9b05be20fde428c9957/examples/react16/public/logo512.png -------------------------------------------------------------------------------- /examples/react16/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "logo192.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "logo512.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /examples/react16/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /examples/react16/scripts/test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // Do this as the first thing so that any code reading it knows the right env. 4 | process.env.BABEL_ENV = 'test'; 5 | process.env.NODE_ENV = 'test'; 6 | process.env.PUBLIC_URL = ''; 7 | 8 | // Makes the script crash on unhandled rejections instead of silently 9 | // ignoring them. In the future, promise rejections that are not handled will 10 | // terminate the Node.js process with a non-zero exit code. 11 | process.on('unhandledRejection', err => { 12 | throw err; 13 | }); 14 | 15 | // Ensure environment variables are read. 16 | require('../config/env'); 17 | 18 | const jest = require('jest'); 19 | const execSync = require('child_process').execSync; 20 | let argv = process.argv.slice(2); 21 | 22 | function isInGitRepository() { 23 | try { 24 | execSync('git rev-parse --is-inside-work-tree', { stdio: 'ignore' }); 25 | return true; 26 | } catch (e) { 27 | return false; 28 | } 29 | } 30 | 31 | function isInMercurialRepository() { 32 | try { 33 | execSync('hg --cwd . root', { stdio: 'ignore' }); 34 | return true; 35 | } catch (e) { 36 | return false; 37 | } 38 | } 39 | 40 | // Watch unless on CI or explicitly running all tests 41 | if ( 42 | !process.env.CI && 43 | argv.indexOf('--watchAll') === -1 && 44 | argv.indexOf('--watchAll=false') === -1 45 | ) { 46 | // https://github.com/facebook/create-react-app/issues/5210 47 | const hasSourceControl = isInGitRepository() || isInMercurialRepository(); 48 | argv.push(hasSourceControl ? '--watch' : '--watchAll'); 49 | } 50 | 51 | 52 | jest.run(argv); 53 | -------------------------------------------------------------------------------- /examples/react16/src/Communication.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Button from "antd/es/button"; 3 | 4 | export default class Communication extends React.Component { 5 | state = { visible: false }; 6 | 7 | jump = () => { 8 | window.$wujie && window.$wujie.props.jump("vue3"); 9 | }; 10 | 11 | handleAlert = () => { 12 | window.parent && window.parent.alert("主应用alert"); 13 | }; 14 | 15 | handleEmit = () => { 16 | window.$wujie && window.$wujie.bus.$emit("click", "react16"); 17 | }; 18 | render() { 19 | return ( 20 |
21 |

通信处理

22 |
23 |

应用可以有三种方式进行通信

24 |

1、主应用通过 props 属性注入的方法

25 |

主应用通过 props 注入 jump(跳转页面)方法,子应用通过 $wujie.props.jump(xxx) 来使用

26 |

27 | 28 |

29 |

2、通过 window.parent 方法拿到主应用的全局方法

30 |

子应用调用 window.parent.alert 来调用主应用的 alert方法

31 |

32 | 33 |

34 |

3、通过 bus 方法发送去中心化的事件

35 |

主应用 bus.$on("click", (msg) ={">"} window.alert(msg)) 监听子应用的 click 事件

36 |

子应用点击按钮 $wujie.bus.$emit('click', 'react16') 发送 click 事件

37 |

38 | 39 |

40 |
41 |
42 | ); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /examples/react16/src/Font.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { IconFont } from "tdesign-icons-react"; 3 | 4 | export default class Font extends React.Component { 5 | componentDidMount() { 6 | console.log("react16 font mounted"); 7 | } 8 | render() { 9 | return ( 10 |
11 |

字体处理

12 |
13 |

背景

14 |

15 | 子应用的 dom 挂载在 Web Component 的 shadowRoot 内, 16 | 17 | shadowRoot 内部的字体文件不会加载 18 | 19 |

20 |

解决

21 |

22 | 框架加载子应用时将自定义字体样式提取到 shadowRoot 的外部,注意主应用和子应用的 @font-face 的 font-family 23 | 不要重名,否则会有字体覆盖的问题。 24 |

25 |

IconFont 图标示例

26 |

TDesign icon

27 |

28 | 29 | 30 | 31 |

32 |

相对地址

33 |

框架会将子应用的 css 文件中的相对地址换成绝对地址

34 |

比如 TDesign icon 的 css 文件地址为:

35 |

https://tdesign.gtimg.com/icon/0.1.1/fonts/index.css

36 |

index.css 文件中 @font-face 中 url('./t.woff') 最终转换为:

37 |

https://tdesign.gtimg.com/icon/0.1.1/fonts/t.woff

38 |
39 |
40 | ); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /examples/react16/src/Location.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Button from "antd/es/button"; 3 | 4 | export default class Location extends React.Component { 5 | handleClick() { 6 | if (window.__WUJIE?.degrade || !window.Proxy || !window.CustomElementRegistry) { 7 | window.$wujie.location.href = "https://v2.vuejs.org/"; 8 | } else window.location.href = "https://wujicode.cn/xy/app/prod/official/index"; 9 | } 10 | componentDidMount() { 11 | console.log("react16 location mounted") 12 | } 13 | 14 | render() { 15 | return ( 16 |
17 |

路由处理

18 |
19 |

1、路由同步

20 |

路由同步意味着浏览器的刷新、前进、后退都可以作用到子应用上

21 |

子应用同步路由到主应用url的query参数上且 key值为子应用的name

22 |

2、location劫持

23 |

当用户访问location来获取当前的url时,wujie统一拦截并回填子应用正确的地址

24 |

3、获取window.location.host的值

25 |

{window.location.host}

26 |

4、修改window.location.href

27 |
28 | 31 |

子应用修改location.href,会将当前的子应用的shadow删除并且替换成一个iframe

32 |

如果子应用配置路由同步,浏览器可通过回退回到子应用

33 |
34 |
35 |
36 | ); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /examples/react16/src/hostMap.js: -------------------------------------------------------------------------------- 1 | const map = { 2 | "//localhost:7100/": "//wujie-micro.github.io/demo-react17/", 3 | "//localhost:7200/": "//wujie-micro.github.io/demo-vue2/", 4 | "//localhost:7300/": "//wujie-micro.github.io/demo-vue3/", 5 | "//localhost:7400/": "//wujie-micro.github.io/demo-angular12/", 6 | "//localhost:7500/": "//wujie-micro.github.io/demo-vite/", 7 | "//localhost:7600/": "//wujie-micro.github.io/demo-react16/", 8 | }; 9 | 10 | export default function hostMap(host) { 11 | if (process.env.NODE_ENV === "production") return map[host]; 12 | return host; 13 | } 14 | -------------------------------------------------------------------------------- /examples/react16/src/index.js: -------------------------------------------------------------------------------- 1 | import "react-app-polyfill/stable"; 2 | import "react-app-polyfill/ie11"; 3 | 4 | import React from "react"; 5 | import ReactDOM from "react-dom"; 6 | import App from "./App"; 7 | import { BrowserRouter } from "react-router-dom"; 8 | import "./styles.css"; 9 | 10 | const basename = process.env.NODE_ENV === "production" ? "/demo-react16/" : ""; 11 | 12 | if (window.__POWERED_BY_WUJIE__) { 13 | // eslint-disable-next-line no-undef 14 | window.__WUJIE_MOUNT = () => { 15 | ReactDOM.render( 16 | 17 | 18 | , 19 | document.getElementById("root") 20 | ); 21 | }; 22 | window.__WUJIE_UNMOUNT = () => { 23 | ReactDOM.unmountComponentAtNode(document.getElementById("root")); 24 | }; 25 | } else { 26 | ReactDOM.render( 27 | 28 | 29 | , 30 | document.getElementById("root") 31 | ); 32 | } 33 | -------------------------------------------------------------------------------- /examples/react16/src/lifecycle.js: -------------------------------------------------------------------------------- 1 | const lifecycles = { 2 | beforeLoad: (appWindow) => console.log(`${appWindow.__WUJIE.id} beforeLoad 生命周期`), 3 | beforeMount: (appWindow) => console.log(`${appWindow.__WUJIE.id} beforeMount 生命周期`), 4 | afterMount: (appWindow) => console.log(`${appWindow.__WUJIE.id} afterMount 生命周期`), 5 | beforeUnmount: (appWindow) => console.log(`${appWindow.__WUJIE.id} beforeUnmount 生命周期`), 6 | afterUnmount: (appWindow) => console.log(`${appWindow.__WUJIE.id} afterUnmount 生命周期`), 7 | }; 8 | 9 | export default lifecycles; 10 | -------------------------------------------------------------------------------- /examples/react16/src/nest.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import WujieReact from "wujie-react"; 3 | import lifecycles from "./lifecycle"; 4 | import hostMap from "./hostMap" 5 | 6 | function selfFetch(url, options) { 7 | const includeFlag = process.env.NODE_ENV === "production"; 8 | return window.fetch(url, { ...options, credentials: includeFlag ? "include" : "omit" }); 9 | } 10 | 11 | export default function React17() { 12 | const react17Url = hostMap("//localhost:7100/"); 13 | const degrade = window.localStorage.getItem("degrade") === "true"; 14 | const props = { 15 | jump: (name) => { 16 | window?.$wujie.props.jump(name); 17 | }, 18 | }; 19 | return ( 20 |
21 |

子应用嵌套

22 |
23 | 39 |
40 |
41 | ); 42 | } 43 | -------------------------------------------------------------------------------- /examples/react16/src/styles.css: -------------------------------------------------------------------------------- 1 | #root { 2 | font-family: Avenir, Helvetica, Arial, sans-serif; 3 | -webkit-font-smoothing: antialiased; 4 | -moz-osx-font-smoothing: grayscale; 5 | text-align: center; 6 | color: #2c3e50; 7 | } 8 | 9 | iframe { 10 | border: none; 11 | } 12 | 13 | nav { 14 | padding: 30px; 15 | text-align: center; 16 | font-size: 20px; 17 | line-height: 1; 18 | } 19 | nav a { 20 | font-weight: bold; 21 | color: #2c3e50; 22 | text-decoration: none; 23 | } 24 | 25 | nav .active { 26 | color: #0239d0; 27 | } 28 | 29 | .App-logo { 30 | height: 20vmin; 31 | pointer-events: none; 32 | animation: App-logo-spin infinite 20s linear; 33 | } 34 | 35 | @keyframes App-logo-spin { 36 | from { 37 | transform: rotate(0deg); 38 | } 39 | to { 40 | transform: rotate(360deg); 41 | } 42 | } 43 | 44 | .content { 45 | text-align: left; 46 | max-width: 740px; 47 | margin: 0 auto; 48 | overflow: hidden; 49 | } 50 | 51 | p, div.p { 52 | margin: 30px 0; 53 | } 54 | 55 | h3 { 56 | padding-bottom: 0.3rem; 57 | border-bottom: 1px solid #eaecef; 58 | font-weight: 600; 59 | } 60 | 61 | body { 62 | width: auto; 63 | margin: 0 15px; 64 | font-size: 17.5px; 65 | position: relative; 66 | } 67 | -------------------------------------------------------------------------------- /examples/react17/.env: -------------------------------------------------------------------------------- 1 | SKIP_PREFLIGHT_CHECK=true 2 | PORT=7100 3 | WDS_SOCKET_PORT=7100 -------------------------------------------------------------------------------- /examples/react17/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | -------------------------------------------------------------------------------- /examples/react17/config/jest/babelTransform.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const babelJest = require('babel-jest'); 4 | 5 | const hasJsxRuntime = (() => { 6 | if (process.env.DISABLE_NEW_JSX_TRANSFORM === 'true') { 7 | return false; 8 | } 9 | 10 | try { 11 | require.resolve('react/jsx-runtime'); 12 | return true; 13 | } catch (e) { 14 | return false; 15 | } 16 | })(); 17 | 18 | module.exports = babelJest.createTransformer({ 19 | presets: [ 20 | [ 21 | require.resolve('babel-preset-react-app'), 22 | { 23 | runtime: hasJsxRuntime ? 'automatic' : 'classic', 24 | }, 25 | ], 26 | ], 27 | babelrc: false, 28 | configFile: false, 29 | }); 30 | -------------------------------------------------------------------------------- /examples/react17/config/jest/cssTransform.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // This is a custom Jest transformer turning style imports into empty objects. 4 | // http://facebook.github.io/jest/docs/en/webpack.html 5 | 6 | module.exports = { 7 | process() { 8 | return 'module.exports = {};'; 9 | }, 10 | getCacheKey() { 11 | // The output is always the same. 12 | return 'cssTransform'; 13 | }, 14 | }; 15 | -------------------------------------------------------------------------------- /examples/react17/config/jest/fileTransform.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const path = require('path'); 4 | const camelcase = require('camelcase'); 5 | 6 | // This is a custom Jest transformer turning file imports into filenames. 7 | // http://facebook.github.io/jest/docs/en/webpack.html 8 | 9 | module.exports = { 10 | process(src, filename) { 11 | const assetFilename = JSON.stringify(path.basename(filename)); 12 | 13 | if (filename.match(/\.svg$/)) { 14 | // Based on how SVGR generates a component name: 15 | // https://github.com/smooth-code/svgr/blob/01b194cf967347d43d4cbe6b434404731b87cf27/packages/core/src/state.js#L6 16 | const pascalCaseFilename = camelcase(path.parse(filename).name, { 17 | pascalCase: true, 18 | }); 19 | const componentName = `Svg${pascalCaseFilename}`; 20 | return `const React = require('react'); 21 | module.exports = { 22 | __esModule: true, 23 | default: ${assetFilename}, 24 | ReactComponent: React.forwardRef(function ${componentName}(props, ref) { 25 | return { 26 | $$typeof: Symbol.for('react.element'), 27 | type: 'svg', 28 | ref: ref, 29 | key: null, 30 | props: Object.assign({}, props, { 31 | children: ${assetFilename} 32 | }) 33 | }; 34 | }), 35 | };`; 36 | } 37 | 38 | return `module.exports = ${assetFilename};`; 39 | }, 40 | }; 41 | -------------------------------------------------------------------------------- /examples/react17/config/pnpTs.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const { resolveModuleName } = require('ts-pnp'); 4 | 5 | exports.resolveModuleName = ( 6 | typescript, 7 | moduleName, 8 | containingFile, 9 | compilerOptions, 10 | resolutionHost 11 | ) => { 12 | return resolveModuleName( 13 | moduleName, 14 | containingFile, 15 | compilerOptions, 16 | resolutionHost, 17 | typescript.resolveModuleName 18 | ); 19 | }; 20 | 21 | exports.resolveTypeReferenceDirective = ( 22 | typescript, 23 | moduleName, 24 | containingFile, 25 | compilerOptions, 26 | resolutionHost 27 | ) => { 28 | return resolveModuleName( 29 | moduleName, 30 | containingFile, 31 | compilerOptions, 32 | resolutionHost, 33 | typescript.resolveTypeReferenceDirective 34 | ); 35 | }; 36 | -------------------------------------------------------------------------------- /examples/react17/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Tencent/wujie/b9e435a0ae229103608ab9b05be20fde428c9957/examples/react17/public/favicon.ico -------------------------------------------------------------------------------- /examples/react17/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 17 | 18 | 27 | React App 28 | 29 | 30 | 31 |
32 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /examples/react17/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Tencent/wujie/b9e435a0ae229103608ab9b05be20fde428c9957/examples/react17/public/logo192.png -------------------------------------------------------------------------------- /examples/react17/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Tencent/wujie/b9e435a0ae229103608ab9b05be20fde428c9957/examples/react17/public/logo512.png -------------------------------------------------------------------------------- /examples/react17/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "logo192.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "logo512.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /examples/react17/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /examples/react17/scripts/test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // Do this as the first thing so that any code reading it knows the right env. 4 | process.env.BABEL_ENV = 'test'; 5 | process.env.NODE_ENV = 'test'; 6 | process.env.PUBLIC_URL = ''; 7 | 8 | // Makes the script crash on unhandled rejections instead of silently 9 | // ignoring them. In the future, promise rejections that are not handled will 10 | // terminate the Node.js process with a non-zero exit code. 11 | process.on('unhandledRejection', err => { 12 | throw err; 13 | }); 14 | 15 | // Ensure environment variables are read. 16 | require('../config/env'); 17 | 18 | 19 | const jest = require('jest'); 20 | const execSync = require('child_process').execSync; 21 | let argv = process.argv.slice(2); 22 | 23 | function isInGitRepository() { 24 | try { 25 | execSync('git rev-parse --is-inside-work-tree', { stdio: 'ignore' }); 26 | return true; 27 | } catch (e) { 28 | return false; 29 | } 30 | } 31 | 32 | function isInMercurialRepository() { 33 | try { 34 | execSync('hg --cwd . root', { stdio: 'ignore' }); 35 | return true; 36 | } catch (e) { 37 | return false; 38 | } 39 | } 40 | 41 | // Watch unless on CI or explicitly running all tests 42 | if ( 43 | !process.env.CI && 44 | argv.indexOf('--watchAll') === -1 && 45 | argv.indexOf('--watchAll=false') === -1 46 | ) { 47 | // https://github.com/facebook/create-react-app/issues/5210 48 | const hasSourceControl = isInGitRepository() || isInMercurialRepository(); 49 | argv.push(hasSourceControl ? '--watch' : '--watchAll'); 50 | } 51 | 52 | 53 | jest.run(argv); 54 | -------------------------------------------------------------------------------- /examples/react17/src/App.test.js: -------------------------------------------------------------------------------- 1 | import { render, screen } from '@testing-library/react'; 2 | import App from './App'; 3 | 4 | test('renders learn react link', () => { 5 | render(); 6 | const linkElement = screen.getByText(/learn react/i); 7 | expect(linkElement).toBeInTheDocument(); 8 | }); 9 | -------------------------------------------------------------------------------- /examples/react17/src/Communication.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Button from "antd/es/button"; 3 | 4 | export default class Communication extends React.Component { 5 | jump = () => { 6 | window.$wujie && window.$wujie.props.jump("vue3"); 7 | }; 8 | 9 | handleAlert = () => { 10 | window.parent && window.parent.alert("主应用alert"); 11 | }; 12 | 13 | handleEmit = () => { 14 | window.$wujie && window.$wujie.bus.$emit("click", "react17"); 15 | }; 16 | 17 | render() { 18 | return ( 19 |
20 |

通信处理

21 |
22 |

应用可以有三种方式进行通信

23 |

1、主应用通过 props 属性注入的方法

24 |

主应用通过 props 注入 jump(跳转页面)方法,子应用通过 $wujie.props.jump(xxx) 来使用

25 |

26 | 27 | 30 |

31 |

2、通过 window.parent 方法拿到主应用的全局方法

32 |

子应用调用 window.parent.alert 来调用主应用的 alert方法

33 |

34 | 35 |

36 |

3、通过 bus 方法发送去中心化的事件

37 |

主应用 bus.$on("click", (msg) ={">"} window.alert(msg)) 监听子应用的 click 事件

38 |

子应用点击按钮 $wujie.bus.$emit('click', 'react17') 发送 click 事件

39 |

40 | 41 |

42 |
43 |
44 | ); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /examples/react17/src/Location.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Button from "antd/es/button"; 3 | 4 | export default class Location extends React.Component { 5 | handleClick() { 6 | if (window.__WUJIE?.degrade || !window.Proxy || !window.CustomElementRegistry) { 7 | window.$wujie.location.href = "https://v2.vuejs.org/"; 8 | } else window.location.href = "https://wujicode.cn/xy/app/prod/official/index"; 9 | } 10 | 11 | componentDidMount() { 12 | console.log("react17 location mounted") 13 | } 14 | 15 | render() { 16 | return ( 17 |
18 |

路由处理

19 |
20 |

1、路由同步

21 |

路由同步意味着浏览器的刷新、前进、后退都可以作用到子应用上

22 |

子应用同步路由到主应用url的query参数上且 key值为子应用的name

23 |

2、location劫持

24 |

当用户访问location来获取当前的url时,wujie统一拦截并回填子应用正确的地址

25 |

3、获取window.location.host的值

26 |

{window.location.host}

27 |

4、修改window.location.href

28 |
29 | 32 |

子应用修改location.href,会将当前的子应用的shadow删除并且替换成一个iframe

33 |

如果子应用配置路由同步,浏览器可通过回退回到子应用

34 |
35 |
36 |
37 | ); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /examples/react17/src/State.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Button from "antd/es/button"; 3 | import "antd/es/button/style/css"; 4 | 5 | export default class Location extends React.Component { 6 | state = { count: 10 }; 7 | handleClick() { 8 | window.location.href = "https://wujicode.cn/xy/app/prod/official/index"; 9 | } 10 | 11 | componentDidMount() { 12 | console.log("react17 state mounted") 13 | } 14 | 15 | render() { 16 | return ( 17 |
18 |

子应用保活

19 |
20 |

设置保活模式,切换应用时,子应用的路由和state都可以得到保留

21 |

1、改动实例的状态,切换到vue,点击按钮再回来看看

22 |

23 | 24 | {this.state.count} 25 | 26 | 35 |

36 |
37 |
38 | ); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /examples/react17/src/index.css: -------------------------------------------------------------------------------- 1 | #root { 2 | font-family: Avenir, Helvetica, Arial, sans-serif; 3 | -webkit-font-smoothing: antialiased; 4 | -moz-osx-font-smoothing: grayscale; 5 | text-align: center; 6 | color: #2c3e50; 7 | } 8 | 9 | nav { 10 | padding: 30px; 11 | text-align: center; 12 | font-size: 20px; 13 | line-height: 1; 14 | } 15 | nav a { 16 | font-weight: bold; 17 | color: #2c3e50; 18 | text-decoration: none; 19 | } 20 | 21 | nav .active { 22 | color: #0239d0; 23 | } 24 | 25 | .App-logo { 26 | height: 20vmin; 27 | pointer-events: none; 28 | animation: App-logo-spin infinite 20s linear; 29 | } 30 | 31 | .app-jump { 32 | margin: 10px 33 | } 34 | 35 | @keyframes App-logo-spin { 36 | from { 37 | transform: rotate(0deg); 38 | } 39 | to { 40 | transform: rotate(360deg); 41 | } 42 | } 43 | 44 | .content { 45 | text-align: left; 46 | max-width: 740px; 47 | margin: 0 auto; 48 | } 49 | 50 | p, div.p { 51 | margin: 30px 0; 52 | } 53 | 54 | h3 { 55 | padding-bottom: 0.3rem; 56 | border-bottom: 1px solid #eaecef; 57 | font-weight: 600; 58 | } 59 | 60 | body { 61 | width: auto; 62 | margin: 0 15px; 63 | font-size: 17.5px; 64 | position: relative; 65 | } 66 | 67 | .number { 68 | display: inline-block; 69 | margin: 0 20px; 70 | width: 100px; 71 | text-align: center; 72 | font-size: 50px; 73 | font-weight: bold; 74 | color: #0239d0; 75 | } 76 | 77 | .number-content { 78 | text-align: left; 79 | display: flex; 80 | align-items: center; 81 | justify-content: center; 82 | } 83 | -------------------------------------------------------------------------------- /examples/react17/src/index.js: -------------------------------------------------------------------------------- 1 | import "react-app-polyfill/stable"; 2 | import "react-app-polyfill/ie11"; 3 | 4 | import React from "react"; 5 | import ReactDOM from "react-dom"; 6 | import App from "./App"; 7 | import reportWebVitals from "./reportWebVitals"; 8 | import "./index.css"; 9 | 10 | ReactDOM.render( 11 | // 严格模式,antd的弹窗会warning 12 | , 13 | document.getElementById("root") 14 | ); 15 | // If you want to start measuring performance in your app, pass a function 16 | // to log results (for example: reportWebVitals(console.log)) 17 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals 18 | reportWebVitals(); 19 | -------------------------------------------------------------------------------- /examples/react17/src/reportWebVitals.js: -------------------------------------------------------------------------------- 1 | const reportWebVitals = onPerfEntry => { 2 | if (onPerfEntry && onPerfEntry instanceof Function) { 3 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { 4 | getCLS(onPerfEntry); 5 | getFID(onPerfEntry); 6 | getFCP(onPerfEntry); 7 | getLCP(onPerfEntry); 8 | getTTFB(onPerfEntry); 9 | }); 10 | } 11 | }; 12 | 13 | export default reportWebVitals; 14 | -------------------------------------------------------------------------------- /examples/react17/src/setupTests.js: -------------------------------------------------------------------------------- 1 | // jest-dom adds custom jest matchers for asserting on DOM nodes. 2 | // allows you to do things like: 3 | // expect(element).toHaveTextContent(/react/i) 4 | // learn more: https://github.com/testing-library/jest-dom 5 | import '@testing-library/jest-dom'; 6 | -------------------------------------------------------------------------------- /examples/vite/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .DS_Store 3 | dist 4 | dist-ssr 5 | *.local 6 | -------------------------------------------------------------------------------- /examples/vite/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to this project will be documented in this file. 4 | See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. 5 | 6 | ## [1.0.23](https://github.com/Tencent/wujie/compare/v1.0.22...v1.0.23) (2024-11-24) 7 | 8 | ### Features 9 | 10 | * unmount hook support promise ([#645](https://github.com/Tencent/wujie/issues/645)) ([18be78b](https://github.com/Tencent/wujie/commit/18be78b336c2ab90fb0e85096c4281be3a1d49cb)) 11 | 12 | # [1.0.0](https://github.com/Tencent/wujie/compare/v1.0.0-rc.25...v1.0.0) (2022-11-10) 13 | 14 | **Note:** Version bump only for package vite 15 | 16 | # [1.0.0-rc.20](https://github.com/Tencent/wujie/compare/v1.0.0-rc.19...v1.0.0-rc.20) (2022-09-30) 17 | 18 | **Note:** Version bump only for package vite 19 | 20 | # [1.0.0-rc.16](https://github.com/Tencent/wujie/compare/v1.0.0-rc.14...v1.0.0-rc.16) (2022-09-12) 21 | 22 | **Note:** Version bump only for package vite 23 | 24 | # [1.0.0-rc.13](https://github.com/Tencent/wujie/compare/v1.0.0-rc.12...v1.0.0-rc.13) (2022-09-02) 25 | 26 | **Note:** Version bump only for package vite 27 | 28 | # 1.0.0-rc.9 (2022-08-15) 29 | 30 | # 1.0.0-rc.4 (2022-07-15) 31 | 32 | ### Bug Fixes 33 | 34 | * 修复vite子应用css3变量没有生效 ([#12](https://github.com/Tencent/wujie/issues/12)) ([261bc01](https://github.com/Tencent/wujie/commit/261bc01a135fe2a91b679c18313ec143454c00e0)) 35 | 36 | # 1.0.0-rc.1 (2022-07-05) 37 | 38 | ### Features 39 | 40 | * init ([30397aa](https://github.com/Tencent/wujie/commit/30397aaa675a4d07bde278aa9d30447c7efe6625)) 41 | -------------------------------------------------------------------------------- /examples/vite/README.md: -------------------------------------------------------------------------------- 1 | # Vue 3 + Typescript + Vite 2 | 3 | This template should help get you started developing with Vue 3 and Typescript in Vite. The template uses Vue 3 ` 12 | 13 | 14 | -------------------------------------------------------------------------------- /examples/vite/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vite", 3 | "version": "1.0.23", 4 | "private": true, 5 | "scripts": { 6 | "start": "vite", 7 | "build": "vue-tsc --noEmit && vite build" 8 | }, 9 | "dependencies": { 10 | "ant-design-vue": "2.2.8", 11 | "core-js": "^3.6.5", 12 | "element-plus": "2.2.6", 13 | "vue": "^3.2.25", 14 | "vue-router": "^4.0.0-0" 15 | }, 16 | "devDependencies": { 17 | "@types/node": "^18.0.0", 18 | "@vitejs/plugin-vue": "^2.0.0", 19 | "typescript": "^4.4.4", 20 | "vite": "^2.7.2", 21 | "vue-tsc": "^0.29.8" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /examples/vite/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Tencent/wujie/b9e435a0ae229103608ab9b05be20fde428c9957/examples/vite/public/favicon.ico -------------------------------------------------------------------------------- /examples/vite/src/App.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 21 | -------------------------------------------------------------------------------- /examples/vite/src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Tencent/wujie/b9e435a0ae229103608ab9b05be20fde428c9957/examples/vite/src/assets/logo.png -------------------------------------------------------------------------------- /examples/vite/src/components/AppendBody.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /examples/vite/src/components/HelloWorld.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 16 | 17 | 18 | 31 | -------------------------------------------------------------------------------- /examples/vite/src/env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | declare module '*.vue' { 4 | import { DefineComponent } from 'vue' 5 | // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/ban-types 6 | const component: DefineComponent<{}, {}, any> 7 | export default component 8 | } 9 | -------------------------------------------------------------------------------- /examples/vite/src/index.css: -------------------------------------------------------------------------------- 1 | html, 2 | body { 3 | font-size: 17.5px; 4 | margin: 0 15px; 5 | padding: 0px; 6 | width: auto; 7 | height: 100%; 8 | position: relative; 9 | } 10 | #app { 11 | font-family: Avenir, Helvetica, Arial, sans-serif; 12 | -webkit-font-smoothing: antialiased; 13 | -moz-osx-font-smoothing: grayscale; 14 | overflow: auto; 15 | padding: 0 20px; 16 | color: #2c3e50; 17 | --el-color-primary: #0239d0; 18 | } 19 | 20 | #nav { 21 | padding: 30px; 22 | text-align: center; 23 | font-size: 20px; 24 | line-height: 1; 25 | } 26 | 27 | .content { 28 | max-width: 740px; 29 | margin: 0 auto; 30 | } 31 | .content > p { 32 | margin: 30px 0; 33 | } 34 | 35 | h3 { 36 | padding-bottom: 0.3rem; 37 | border-bottom: 1px solid #eaecef; 38 | font-weight: 600; 39 | } 40 | 41 | #nav a { 42 | font-weight: bold; 43 | color: #2c3e50; 44 | } 45 | 46 | #nav a.router-link-exact-active { 47 | color: #0239d0; 48 | } -------------------------------------------------------------------------------- /examples/vite/src/router/index.ts: -------------------------------------------------------------------------------- 1 | import Home from "../views/Home.vue"; 2 | import { defineAsyncComponent } from "vue"; 3 | const _import = (name: string) => defineAsyncComponent(() => import(`../views/${name}.vue`)); 4 | 5 | const routes = [ 6 | { 7 | path: "/", 8 | redirect: "/home", 9 | }, 10 | { 11 | path: "/home", 12 | component: Home, 13 | }, 14 | { 15 | path: "/dialog", 16 | name: "Dialog", 17 | // route level code-splitting 18 | // this generates a separate chunk (about.[hash].js) for this route 19 | // which is lazy-loaded when the route is visited. 20 | component: _import("Dialog"), 21 | }, 22 | { 23 | path: "/location", 24 | name: "Location", 25 | // route level code-splitting 26 | // this generates a separate chunk (about.[hash].js) for this route 27 | // which is lazy-loaded when the route is visited. 28 | component: _import("Location"), 29 | }, 30 | // { 31 | // path: "/state", 32 | // name: "State", 33 | // // route level code-splitting 34 | // // this generates a separate chunk (about.[hash].js) for this route 35 | // // which is lazy-loaded when the route is visited. 36 | // component: _import('State') 37 | // }, 38 | { 39 | path: "/contact", 40 | name: "Contact", 41 | // route level code-splitting 42 | // this generates a separate chunk (about.[hash].js) for this route 43 | // which is lazy-loaded when the route is visited. 44 | component: _import("Communication"), 45 | }, 46 | ]; 47 | 48 | export default routes; 49 | -------------------------------------------------------------------------------- /examples/vite/src/views/Communication.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 42 | -------------------------------------------------------------------------------- /examples/vite/src/views/Home.vue: -------------------------------------------------------------------------------- 1 | 26 | 27 | 40 | 41 | 46 | -------------------------------------------------------------------------------- /examples/vite/src/views/Location.vue: -------------------------------------------------------------------------------- 1 | 21 | 22 | 48 | 49 | 58 | -------------------------------------------------------------------------------- /examples/vite/src/views/State.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 36 | 37 | 60 | -------------------------------------------------------------------------------- /examples/vite/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "esnext", 4 | "useDefineForClassFields": true, 5 | "module": "esnext", 6 | "moduleResolution": "node", 7 | "strict": true, 8 | "skipLibCheck": true, 9 | "jsx": "preserve", 10 | "sourceMap": true, 11 | "resolveJsonModule": true, 12 | "esModuleInterop": true, 13 | "lib": ["esnext", "dom"] 14 | }, 15 | "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"] 16 | } 17 | -------------------------------------------------------------------------------- /examples/vite/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "vite"; 2 | import vue from "@vitejs/plugin-vue"; 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | base:'./', 7 | server: { 8 | cors: true, 9 | host: '0.0.0.0', 10 | port: 7500 11 | }, 12 | plugins: [ 13 | vue(), 14 | ], 15 | }); 16 | -------------------------------------------------------------------------------- /examples/vue2/.browserslistrc: -------------------------------------------------------------------------------- 1 | > 1% 2 | last 2 versions 3 | ie >= 11 4 | -------------------------------------------------------------------------------- /examples/vue2/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | env: { 4 | node: true, 5 | }, 6 | extends: ["plugin:vue/essential", "eslint:recommended", "@vue/prettier"], 7 | parserOptions: { 8 | parser: "babel-eslint", 9 | }, 10 | rules: { 11 | "no-console": process.env.NODE_ENV === "production" ? "warn" : "off", 12 | "no-debugger": process.env.NODE_ENV === "production" ? "warn" : "off", 13 | }, 14 | }; 15 | -------------------------------------------------------------------------------- /examples/vue2/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | 5 | 6 | # local env files 7 | .env.local 8 | .env.*.local 9 | 10 | # Log files 11 | npm-debug.log* 12 | yarn-debug.log* 13 | yarn-error.log* 14 | pnpm-debug.log* 15 | 16 | # Editor directories and files 17 | .idea 18 | .vscode 19 | *.suo 20 | *.ntvs* 21 | *.njsproj 22 | *.sln 23 | *.sw? 24 | -------------------------------------------------------------------------------- /examples/vue2/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to this project will be documented in this file. 4 | See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. 5 | 6 | ## [1.0.23](https://github.com/Tencent/wujie/compare/v1.0.22...v1.0.23) (2024-11-24) 7 | 8 | ### Features 9 | 10 | * 添加postmessage通信示例 ([da2c99f](https://github.com/Tencent/wujie/commit/da2c99f38afae8fbe0c1ab8e2eb3ff7cb2eaece2)) 11 | 12 | # [1.0.0](https://github.com/Tencent/wujie/compare/v1.0.0-rc.25...v1.0.0) (2022-11-10) 13 | 14 | ### Features 15 | 16 | * ie11 compatibility ([#248](https://github.com/Tencent/wujie/issues/248)) ([f6fd307](https://github.com/Tencent/wujie/commit/f6fd307c3365801a300ea22050aca1447f81b197)), closes [#185](https://github.com/Tencent/wujie/issues/185) [#185](https://github.com/Tencent/wujie/issues/185) 17 | 18 | # [1.0.0-rc.20](https://github.com/Tencent/wujie/compare/v1.0.0-rc.19...v1.0.0-rc.20) (2022-09-30) 19 | 20 | **Note:** Version bump only for package vue2 21 | 22 | # [1.0.0-rc.16](https://github.com/Tencent/wujie/compare/v1.0.0-rc.14...v1.0.0-rc.16) (2022-09-12) 23 | 24 | **Note:** Version bump only for package vue2 25 | 26 | # [1.0.0-rc.13](https://github.com/Tencent/wujie/compare/v1.0.0-rc.12...v1.0.0-rc.13) (2022-09-02) 27 | 28 | **Note:** Version bump only for package vue2 29 | 30 | # 1.0.0-rc.12 (2022-08-25) 31 | 32 | ### Bug Fixes 33 | 34 | * 修复子应用加载页面生命周期无法触发 ([#85](https://github.com/Tencent/wujie/issues/85)) ([ea8efcb](https://github.com/Tencent/wujie/commit/ea8efcb2c8ac0c2378f9154e684d883497ef9a45)) 35 | 36 | # 1.0.0-rc.9 (2022-08-15) 37 | 38 | # 1.0.0-rc.1 (2022-07-05) 39 | 40 | ### Features 41 | 42 | * init ([30397aa](https://github.com/Tencent/wujie/commit/30397aaa675a4d07bde278aa9d30447c7efe6625)) 43 | -------------------------------------------------------------------------------- /examples/vue2/README.md: -------------------------------------------------------------------------------- 1 | # vue2 2 | 3 | ## Project setup 4 | ``` 5 | yarn install 6 | ``` 7 | 8 | ### Compiles and hot-reloads for development 9 | ``` 10 | yarn serve 11 | ``` 12 | 13 | ### Compiles and minifies for production 14 | ``` 15 | yarn build 16 | ``` 17 | 18 | ### Lints and fixes files 19 | ``` 20 | yarn lint 21 | ``` 22 | 23 | ### Customize configuration 24 | See [Configuration Reference](https://cli.vuejs.org/config/). 25 | -------------------------------------------------------------------------------- /examples/vue2/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: ["@vue/cli-plugin-babel/preset"], 3 | plugins: ["@babel/plugin-proposal-nullish-coalescing-operator", "@babel/plugin-proposal-optional-chaining"], 4 | }; 5 | -------------------------------------------------------------------------------- /examples/vue2/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue2", 3 | "version": "1.0.23", 4 | "private": true, 5 | "scripts": { 6 | "start": "vue-cli-service serve --mode:development", 7 | "build": "vue-cli-service build", 8 | "lint": "vue-cli-service lint" 9 | }, 10 | "dependencies": { 11 | "ant-design-vue": "1.7.8", 12 | "core-js": "^3.6.5", 13 | "element-ui": "2.15.6", 14 | "vue": "^2.6.11", 15 | "vue-router": "^3.2.0" 16 | }, 17 | "devDependencies": { 18 | "@babel/plugin-proposal-nullish-coalescing-operator": "^7.17.12", 19 | "@babel/plugin-proposal-optional-chaining": "^7.17.12", 20 | "@vue/cli-plugin-babel": "~4.5.0", 21 | "@vue/cli-plugin-eslint": "~4.5.0", 22 | "@vue/cli-plugin-router": "~4.5.0", 23 | "@vue/cli-service": "~4.5.0", 24 | "@vue/eslint-config-prettier": "^6.0.0", 25 | "babel-eslint": "^10.1.0", 26 | "eslint": "^6.7.2", 27 | "eslint-plugin-prettier": "^3.3.1", 28 | "eslint-plugin-vue": "^6.2.2", 29 | "prettier": "^2.2.1", 30 | "vue-template-compiler": "^2.6.11" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /examples/vue2/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Tencent/wujie/b9e435a0ae229103608ab9b05be20fde428c9957/examples/vue2/public/favicon.ico -------------------------------------------------------------------------------- /examples/vue2/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | <%= htmlWebpackPlugin.options.title %> 9 | 10 | 11 | 14 |
15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /examples/vue2/src/App.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 21 | -------------------------------------------------------------------------------- /examples/vue2/src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Tencent/wujie/b9e435a0ae229103608ab9b05be20fde428c9957/examples/vue2/src/assets/logo.png -------------------------------------------------------------------------------- /examples/vue2/src/components/AppendBody.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /examples/vue2/src/components/HelloWorld.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 16 | 17 | 18 | 33 | -------------------------------------------------------------------------------- /examples/vue2/src/hostMap.js: -------------------------------------------------------------------------------- 1 | const map = { 2 | "//localhost:7100/": "//wujie-micro.github.io/demo-react17/", 3 | "//localhost:7200/": "//wujie-micro.github.io/demo-vue2/", 4 | "//localhost:7300/": "//wujie-micro.github.io/demo-vue3/", 5 | "//localhost:7400/": "//wujie-micro.github.io/demo-angular12/", 6 | "//localhost:7500/": "//wujie-micro.github.io/demo-vite/", 7 | "//localhost:7600/": "//wujie-micro.github.io/demo-react16/", 8 | "//localhost:7700/": "//wujie-micro.github.io/demo-main-react/", 9 | "//localhost:8000/": "//wujie-micro.github.io/demo-main-vue/", 10 | }; 11 | 12 | export default function hostMap(host) { 13 | if (process.env.NODE_ENV === "production") return map[host]; 14 | return host; 15 | } 16 | -------------------------------------------------------------------------------- /examples/vue2/src/index.css: -------------------------------------------------------------------------------- 1 | html, 2 | body { 3 | font-size: 17.5px; 4 | margin: 0 15px; 5 | padding: 0px; 6 | width: auto; 7 | position: relative; 8 | } 9 | #app { 10 | font-family: Avenir, Helvetica, Arial, sans-serif; 11 | -webkit-font-smoothing: antialiased; 12 | -moz-osx-font-smoothing: grayscale; 13 | color: #2c3e50; 14 | } 15 | 16 | #nav { 17 | text-align: center; 18 | padding: 30px; 19 | font-size: 20px; 20 | line-height: 1; 21 | } 22 | 23 | .content { 24 | max-width: 740px; 25 | margin: 0 auto; 26 | } 27 | .content > p { 28 | margin: 30px 0; 29 | } 30 | 31 | #nav a { 32 | font-weight: bold; 33 | color: #2c3e50; 34 | text-decoration: none; 35 | } 36 | 37 | h3 { 38 | padding-bottom: 0.3rem; 39 | border-bottom: 1px solid #eaecef; 40 | font-weight: 600; 41 | } 42 | 43 | #nav a.router-link-exact-active { 44 | color: #0239d0; 45 | } -------------------------------------------------------------------------------- /examples/vue2/src/main.js: -------------------------------------------------------------------------------- 1 | import "core-js/modules/es.array.find"; 2 | 3 | import Vue from "vue"; 4 | import App from "./App.vue"; 5 | import routes from "./router"; 6 | import VueRouter from "vue-router"; 7 | import Tag from "element-ui/lib/tag"; 8 | import Button from "element-ui/lib/button"; 9 | import Select from "element-ui/lib/select"; 10 | import Option from "element-ui/lib/option"; 11 | import Popover from "element-ui/lib/popover"; 12 | import Dialog from "element-ui/lib/dialog"; 13 | import AButton from "ant-design-vue/es/button"; 14 | import ASelect from "ant-design-vue/es/select"; 15 | import AModal from "ant-design-vue/es/modal"; 16 | import APopover from "ant-design-vue/es/popover"; 17 | import "./pageLifeTest"; 18 | import "element-ui/lib/theme-chalk/base.css"; 19 | import "element-ui/lib/theme-chalk/tag.css"; 20 | import "element-ui/lib/theme-chalk/button.css"; 21 | import "element-ui/lib/theme-chalk/select.css"; 22 | import "element-ui/lib/theme-chalk/option.css"; 23 | import "element-ui/lib/theme-chalk/popover.css"; 24 | import "element-ui/lib/theme-chalk/dialog.css"; 25 | import "ant-design-vue/es/style/index.css"; 26 | import "ant-design-vue/es/button/style/index.css"; 27 | import "ant-design-vue/es/select/style/index.css"; 28 | import "ant-design-vue/es/modal/style/index.css"; 29 | import "ant-design-vue/es/popover/style/index.css"; 30 | import "./index.css"; 31 | 32 | const base = process.env.NODE_ENV === "production" ? "/demo-vue2/" : ""; 33 | 34 | [Tag, Button, Select, Option, Popover, Dialog].forEach((element) => Vue.use(element)); 35 | [AButton, ASelect, AModal, APopover].forEach((element) => Vue.use(element)); 36 | 37 | Vue.use(VueRouter); 38 | 39 | Vue.config.productionTip = false; 40 | 41 | if (window.__POWERED_BY_WUJIE__) { 42 | let instance; 43 | window.__WUJIE_MOUNT = () => { 44 | const router = new VueRouter({ base, routes }); 45 | instance = new Vue({ router, render: (h) => h(App) }).$mount("#app"); 46 | }; 47 | window.__WUJIE_UNMOUNT = () => { 48 | instance.$destroy(); 49 | }; 50 | } else { 51 | new Vue({ router: new VueRouter({ base, routes }), render: (h) => h(App) }).$mount("#app"); 52 | } 53 | -------------------------------------------------------------------------------- /examples/vue2/src/pageLifeTest.js: -------------------------------------------------------------------------------- 1 | // 测试页面加载生命周期,集成测试使用 2 | document.addEventListener("DOMContentLoaded", () => { 3 | console.log("vue2 document DOMContentLoaded trigger"); 4 | }); 5 | 6 | window.addEventListener("DOMContentLoaded", () => { 7 | console.log("vue2 window DOMContentLoaded trigger"); 8 | }); 9 | 10 | document.onreadystatechange = function () { 11 | console.log("vue2 document onreadystatechange trigger"); 12 | }; 13 | 14 | document.addEventListener("readystatechange", () => { 15 | console.log("vue2 document readystatechange trigger"); 16 | }); 17 | 18 | window.onload = () => console.log("vue2 window onload trigger"); 19 | 20 | window.addEventListener("load", () => { 21 | console.log("vue2 window load trigger"); 22 | }); 23 | -------------------------------------------------------------------------------- /examples/vue2/src/router/index.js: -------------------------------------------------------------------------------- 1 | import Home from "../views/Home.vue"; 2 | 3 | const routes = [ 4 | { 5 | path: "/", 6 | redirect: "/home", 7 | }, 8 | { 9 | path: "/home", 10 | component: Home, 11 | }, 12 | { 13 | path: "/dialog", 14 | name: "dialog", 15 | component: () => import(/* webpackChunkName: "Page1" */ "../views/Dialog.vue"), 16 | }, 17 | { 18 | path: "/communication", 19 | name: "communication", 20 | component: () => import(/* webpackChunkName: "Page2" */ "../views/Communication.vue"), 21 | }, 22 | { 23 | path: "/location", 24 | name: "location", 25 | component: () => import(/* webpackChunkName: "Page3" */ "../views/Location.vue"), 26 | }, 27 | { 28 | path: "/postmessage", 29 | name: "postmessage", 30 | component: () => import(/* webpackChunkName: "Page3" */ "../views/PostMessage.vue"), 31 | }, 32 | ]; 33 | 34 | export default routes; 35 | -------------------------------------------------------------------------------- /examples/vue2/src/views/Communication.vue: -------------------------------------------------------------------------------- 1 | 23 | 24 | 48 | -------------------------------------------------------------------------------- /examples/vue2/src/views/Home.vue: -------------------------------------------------------------------------------- 1 | 23 | 24 | 37 | 38 | -------------------------------------------------------------------------------- /examples/vue2/src/views/Location.vue: -------------------------------------------------------------------------------- 1 | 23 | 24 | 52 | 53 | 62 | -------------------------------------------------------------------------------- /examples/vue2/src/views/PostMessage.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 55 | 56 | 68 | -------------------------------------------------------------------------------- /examples/vue2/vue.config.js: -------------------------------------------------------------------------------- 1 | // vue.config.js 2 | 3 | /** 4 | * @type {import('@vue/cli-service').ProjectOptions} 5 | */ 6 | module.exports = { 7 | publicPath: "./", 8 | devServer: { 9 | headers: { 10 | "Access-Control-Allow-Origin": "*", 11 | "Access-Control-Allow-Headers": "*", 12 | "Access-Control-Allow-Methods": "*", 13 | }, 14 | port: "7200", 15 | }, 16 | transpileDependencies: [ 17 | "sockjs-client", 18 | ], 19 | }; 20 | -------------------------------------------------------------------------------- /examples/vue3/.browserslistrc: -------------------------------------------------------------------------------- 1 | > 1% 2 | last 2 versions 3 | not dead 4 | -------------------------------------------------------------------------------- /examples/vue3/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | env: { 4 | node: true, 5 | }, 6 | extends: ["plugin:vue/vue3-essential", "eslint:recommended", "@vue/prettier"], 7 | parserOptions: { 8 | parser: "babel-eslint", 9 | }, 10 | rules: { 11 | "no-console": process.env.NODE_ENV === "production" ? "warn" : "off", 12 | "no-debugger": process.env.NODE_ENV === "production" ? "warn" : "off", 13 | }, 14 | }; 15 | -------------------------------------------------------------------------------- /examples/vue3/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | 5 | 6 | # local env files 7 | .env.local 8 | .env.*.local 9 | 10 | # Log files 11 | npm-debug.log* 12 | yarn-debug.log* 13 | yarn-error.log* 14 | pnpm-debug.log* 15 | 16 | # Editor directories and files 17 | .idea 18 | .vscode 19 | *.suo 20 | *.ntvs* 21 | *.njsproj 22 | *.sln 23 | *.sw? 24 | -------------------------------------------------------------------------------- /examples/vue3/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to this project will be documented in this file. 4 | See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. 5 | 6 | ## [1.0.23](https://github.com/Tencent/wujie/compare/v1.0.22...v1.0.23) (2024-11-24) 7 | 8 | ### Features 9 | 10 | * 添加postmessage通信示例 ([da2c99f](https://github.com/Tencent/wujie/commit/da2c99f38afae8fbe0c1ab8e2eb3ff7cb2eaece2)) 11 | 12 | # [1.0.0](https://github.com/Tencent/wujie/compare/v1.0.0-rc.25...v1.0.0) (2022-11-10) 13 | 14 | **Note:** Version bump only for package vue3 15 | 16 | # [1.0.0-rc.20](https://github.com/Tencent/wujie/compare/v1.0.0-rc.19...v1.0.0-rc.20) (2022-09-30) 17 | 18 | **Note:** Version bump only for package vue3 19 | 20 | # [1.0.0-rc.16](https://github.com/Tencent/wujie/compare/v1.0.0-rc.14...v1.0.0-rc.16) (2022-09-12) 21 | 22 | **Note:** Version bump only for package vue3 23 | 24 | # [1.0.0-rc.13](https://github.com/Tencent/wujie/compare/v1.0.0-rc.12...v1.0.0-rc.13) (2022-09-02) 25 | 26 | **Note:** Version bump only for package vue3 27 | 28 | # 1.0.0-rc.9 (2022-08-15) 29 | 30 | # 1.0.0-rc.1 (2022-07-05) 31 | 32 | ### Features 33 | 34 | * init ([30397aa](https://github.com/Tencent/wujie/commit/30397aaa675a4d07bde278aa9d30447c7efe6625)) 35 | -------------------------------------------------------------------------------- /examples/vue3/README.md: -------------------------------------------------------------------------------- 1 | # vue3 2 | 3 | ## Project setup 4 | ``` 5 | yarn install 6 | ``` 7 | 8 | ### Compiles and hot-reloads for development 9 | ``` 10 | yarn serve 11 | ``` 12 | 13 | ### Compiles and minifies for production 14 | ``` 15 | yarn build 16 | ``` 17 | 18 | ### Lints and fixes files 19 | ``` 20 | yarn lint 21 | ``` 22 | 23 | ### Customize configuration 24 | See [Configuration Reference](https://cli.vuejs.org/config/). 25 | -------------------------------------------------------------------------------- /examples/vue3/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: ["@vue/cli-plugin-babel/preset"], 3 | plugins: ["@babel/plugin-proposal-nullish-coalescing-operator", "@babel/plugin-proposal-optional-chaining"], 4 | }; 5 | -------------------------------------------------------------------------------- /examples/vue3/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue3", 3 | "version": "1.0.23", 4 | "private": true, 5 | "scripts": { 6 | "start": "vue-cli-service serve", 7 | "build": "vue-cli-service build", 8 | "lint": "vue-cli-service lint" 9 | }, 10 | "dependencies": { 11 | "ant-design-vue": "2.2.8", 12 | "core-js": "^3.6.5", 13 | "element-plus": "2.2.6", 14 | "vue": "^3.0.0", 15 | "vue-router": "^4.0.0-0" 16 | }, 17 | "devDependencies": { 18 | "@babel/plugin-proposal-nullish-coalescing-operator": "^7.17.12", 19 | "@babel/plugin-proposal-optional-chaining": "^7.17.12", 20 | "@vue/cli-plugin-babel": "~4.5.0", 21 | "@vue/cli-plugin-eslint": "~4.5.0", 22 | "@vue/cli-plugin-router": "~4.5.0", 23 | "@vue/cli-service": "~4.5.0", 24 | "@vue/compiler-sfc": "^3.0.0", 25 | "@vue/eslint-config-prettier": "^6.0.0", 26 | "babel-eslint": "^10.1.0", 27 | "eslint": "^6.7.2", 28 | "eslint-plugin-prettier": "^3.3.1", 29 | "eslint-plugin-vue": "^7.0.0", 30 | "prettier": "^2.2.1", 31 | "vue-loader-v16": "^16.0.0-beta.5.4" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /examples/vue3/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Tencent/wujie/b9e435a0ae229103608ab9b05be20fde428c9957/examples/vue3/public/favicon.ico -------------------------------------------------------------------------------- /examples/vue3/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | <%= htmlWebpackPlugin.options.title %> 10 | 11 | 12 | 15 |
16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /examples/vue3/src/App.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 23 | -------------------------------------------------------------------------------- /examples/vue3/src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Tencent/wujie/b9e435a0ae229103608ab9b05be20fde428c9957/examples/vue3/src/assets/logo.png -------------------------------------------------------------------------------- /examples/vue3/src/components/AppendBody.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /examples/vue3/src/components/HelloWorld.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 16 | 17 | 18 | 32 | -------------------------------------------------------------------------------- /examples/vue3/src/index.css: -------------------------------------------------------------------------------- 1 | html, 2 | body { 3 | font-size: 17.5px; 4 | margin: 0 15px; 5 | padding: 0px; 6 | width: auto; 7 | height: 100%; 8 | position: relative; 9 | } 10 | #app { 11 | font-family: Avenir, Helvetica, Arial, sans-serif; 12 | -webkit-font-smoothing: antialiased; 13 | -moz-osx-font-smoothing: grayscale; 14 | overflow: auto; 15 | padding: 0 20px; 16 | color: #2c3e50; 17 | --el-color-primary: #0239d0; 18 | } 19 | 20 | #nav { 21 | padding: 30px; 22 | text-align: center; 23 | font-size: 20px; 24 | line-height: 1; 25 | } 26 | 27 | .content { 28 | max-width: 740px; 29 | margin: 0 auto; 30 | } 31 | .content > p { 32 | margin: 30px 0; 33 | } 34 | 35 | h3 { 36 | padding-bottom: 0.3rem; 37 | border-bottom: 1px solid #eaecef; 38 | font-weight: 600; 39 | } 40 | 41 | #nav a { 42 | font-weight: bold; 43 | color: #2c3e50; 44 | } 45 | 46 | #nav a.router-link-exact-active { 47 | color: #0239d0; 48 | } -------------------------------------------------------------------------------- /examples/vue3/src/main.js: -------------------------------------------------------------------------------- 1 | import { createApp } from "vue"; 2 | import App from "./App.vue"; 3 | import router from "./router"; 4 | import Tag from "element-plus/es/components/tag/index"; 5 | import Button from "element-plus/es/components/button/index"; 6 | import Dialog from "element-plus/es/components/dialog/index"; 7 | import Select from "element-plus/es/components/select/index"; 8 | import Popover from "element-plus/es/components/popover/index"; 9 | import AButton from "ant-design-vue/es/button"; 10 | import ASelect from "ant-design-vue/es/select"; 11 | import AModal from "ant-design-vue/es/modal"; 12 | import APopover from "ant-design-vue/es/popover"; 13 | import "element-plus/es/components/button/style/css"; 14 | import "element-plus/es/components/tag/style/css"; 15 | import "element-plus/es/components/dialog/style/css"; 16 | import "element-plus/es/components/select/style/css"; 17 | import "element-plus/es/components/popover/style/css"; 18 | import "ant-design-vue/es/style/index.css"; 19 | import "ant-design-vue/es/button/style/index.css"; 20 | import "ant-design-vue/es/select/style/index.css"; 21 | import "ant-design-vue/es/modal/style/index.css"; 22 | import "ant-design-vue/es/popover/style/index.css"; 23 | import "./index.css"; 24 | 25 | createApp(App) 26 | .use(Tag) 27 | .use(Button) 28 | .use(Dialog) 29 | .use(Select) 30 | .use(Popover) 31 | .use(AButton) 32 | .use(ASelect) 33 | .use(AModal) 34 | .use(APopover) 35 | .use(router) 36 | .mount("#app"); 37 | -------------------------------------------------------------------------------- /examples/vue3/src/views/Communication.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 42 | -------------------------------------------------------------------------------- /examples/vue3/src/views/Home.vue: -------------------------------------------------------------------------------- 1 | 25 | 26 | 39 | 40 | 45 | -------------------------------------------------------------------------------- /examples/vue3/src/views/Location.vue: -------------------------------------------------------------------------------- 1 | 21 | 22 | 50 | 51 | 60 | -------------------------------------------------------------------------------- /examples/vue3/src/views/PostMessage.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 57 | 58 | 66 | -------------------------------------------------------------------------------- /examples/vue3/src/views/State.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 37 | 38 | 61 | -------------------------------------------------------------------------------- /examples/vue3/vue.config.js: -------------------------------------------------------------------------------- 1 | // vue.config.js 2 | 3 | /** 4 | * @type {import('@vue/cli-service').ProjectOptions} 5 | */ 6 | module.exports = { 7 | publicPath: "./", 8 | devServer: { 9 | headers: { 10 | "Access-Control-Allow-Origin": "*", 11 | }, 12 | port: "7300", 13 | }, 14 | }; 15 | -------------------------------------------------------------------------------- /lerna.json: -------------------------------------------------------------------------------- 1 | { 2 | "packages": [ 3 | "packages/*", 4 | "examples/*", 5 | "docs" 6 | ], 7 | "npmClient": "pnpm", 8 | "command": { 9 | "version": { 10 | "allowBranch": "master" 11 | }, 12 | "bootstrap": { 13 | "npmClientArgs": [ 14 | "--no-package-lock", 15 | "--legacy-peer-deps" 16 | ] 17 | } 18 | }, 19 | "version": "1.0.28" 20 | } 21 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "wujie-project", 3 | "version": "0.0.0", 4 | "description": "极致的微前端框架", 5 | "private": true, 6 | "scripts": { 7 | "start": "lerna run start --parallel", 8 | "doc": "lerna run docs:dev", 9 | "clean": "rimraf node_modules **/*/node_modules", 10 | "test": "lerna run test --scope wujie", 11 | "commitlint": "commitlint -E COMMIT_EDITMSG_PATH", 12 | "husky-commitlint": "commitlint -e", 13 | "prepare": "husky install" 14 | }, 15 | "repository": { 16 | "type": "git", 17 | "url": "https://github.com/Tencent/wujie.git" 18 | }, 19 | "author": "yiludege", 20 | "license": "MIT", 21 | "devDependencies": { 22 | "@commitlint/cli": "^16.2.3", 23 | "@commitlint/config-conventional": "^16.2.1", 24 | "@lerna-lite/cli": "^1.11.1", 25 | "@lerna-lite/run": "^1.11.1", 26 | "husky": "^7.0.4", 27 | "lint-staged": "^12.4.1", 28 | "rimraf": "^3.0.2" 29 | }, 30 | "dependencies": {} 31 | } 32 | -------------------------------------------------------------------------------- /packages/wujie-core/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["@babel/preset-env", "@babel/preset-typescript"], 3 | "plugins": ["@babel/plugin-transform-runtime"], 4 | "env": { 5 | "esm": { 6 | "presets": [ 7 | [ 8 | "@babel/preset-env", 9 | { 10 | "modules": false 11 | } 12 | ] 13 | ] 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /packages/wujie-core/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | browser: true, 4 | es2021: true, 5 | node: true, 6 | }, 7 | extends: ["eslint:recommended", "plugin:prettier/recommended", "prettier"], 8 | parser: "@typescript-eslint/parser", 9 | parserOptions: { 10 | ecmaVersion: 12, 11 | sourceType: "module", 12 | }, 13 | plugins: ["@typescript-eslint"], 14 | overrides: [ 15 | { 16 | files: ["*.ts"], 17 | rules: { 18 | "no-undef": "off", 19 | }, 20 | }, 21 | ], 22 | rules: { 23 | "no-unused-vars": "off", 24 | "@typescript-eslint/no-unused-vars": ["warn"], 25 | "no-debugger": process.env.NODE_ENV === "production" ? "warn" : "off", 26 | "no-prototype-builtins": "off", 27 | "no-self-assign": "off", 28 | "no-empty": ["error", { allowEmptyCatch: true }], 29 | "prettier/prettier": ["error", { endOfLine: "auto" }], 30 | }, 31 | ignorePatterns: ["esm/*.js", "__test__/apps/*/*.html"], 32 | }; 33 | -------------------------------------------------------------------------------- /packages/wujie-core/__test__/integration/degrade.test.ts: -------------------------------------------------------------------------------- 1 | import { awaitConsoleLogMessage, getTextContentByJsSelector } from "./utils"; 2 | import { reactMainAppInfoList, vueMainAppInfoList } from "./common"; 3 | 4 | describe("main react degrade", () => { 5 | beforeAll(async () => { 6 | await page.evaluateOnNewDocument(() => { 7 | // 开启主动降级 8 | localStorage.clear(); 9 | localStorage.setItem("preload", "false"); 10 | localStorage.setItem("degrade", "true"); 11 | }); 12 | await page.goto("http://localhost:7700/"); 13 | await page.waitForNavigation(); 14 | }); 15 | 16 | reactMainAppInfoList.forEach((appInfo) => 17 | it(`${appInfo.name} degrade`, async () => { 18 | const appInfoMountedPromise = awaitConsoleLogMessage(page, appInfo.mountedMessage); 19 | await page.click(appInfo.linkSelector); 20 | await appInfoMountedPromise; 21 | expect(await getTextContentByJsSelector(page, appInfo.degradeTitleJsSelector)).toBe(appInfo.titleText); 22 | }) 23 | ); 24 | }); 25 | 26 | describe("main vue degrade", () => { 27 | beforeAll(async () => { 28 | await page.evaluateOnNewDocument(() => { 29 | // 开启主动降级 30 | localStorage.clear(); 31 | localStorage.setItem("preload", "false"); 32 | localStorage.setItem("degrade", "true"); 33 | }); 34 | await page.goto("http://localhost:8000/"); 35 | await page.waitForNavigation(); 36 | }); 37 | 38 | vueMainAppInfoList.forEach((appInfo) => 39 | it(`${appInfo.name} degrade`, async () => { 40 | const appInfoMountedPromise = awaitConsoleLogMessage(page, appInfo.mountedMessage); 41 | await page.click(appInfo.linkSelector); 42 | await appInfoMountedPromise; 43 | expect(await getTextContentByJsSelector(page, appInfo.degradeTitleJsSelector)).toBe(appInfo.titleText); 44 | }) 45 | ); 46 | }); 47 | -------------------------------------------------------------------------------- /packages/wujie-core/__test__/integration/jest-preset.js: -------------------------------------------------------------------------------- 1 | const ts_preset = require('ts-jest/jest-preset') 2 | const puppeteer_preset = require('jest-puppeteer/jest-preset') 3 | 4 | 5 | module.exports = Object.assign( 6 | ts_preset, 7 | puppeteer_preset 8 | ) -------------------------------------------------------------------------------- /packages/wujie-core/__test__/integration/preLoadApp.test.ts: -------------------------------------------------------------------------------- 1 | import { reactMainAppInfoList, vueMainAppInfoList } from "./common"; 2 | import { awaitConsoleLogMessage, getTextContentByJsSelector } from "./utils"; 3 | describe("main react preload", () => { 4 | beforeAll(async () => { 5 | await page.evaluateOnNewDocument(() => { 6 | // 开启预加载 7 | localStorage.clear(); 8 | localStorage.setItem("preload", "true"); 9 | localStorage.setItem("degrade", "false"); 10 | }); 11 | let mountedPromiseList: Array> = reactMainAppInfoList.map((appInfo) => 12 | awaitConsoleLogMessage(page, appInfo.mountedMessage) 13 | ); 14 | await page.goto("http://localhost:7700/"); 15 | // 所有预加载完成加载 16 | await Promise.all(mountedPromiseList); 17 | }); 18 | 19 | reactMainAppInfoList.forEach((appInfo) => 20 | it(`${appInfo.name} preload`, async () => { 21 | expect(await getTextContentByJsSelector(page, appInfo.preloadTitleJsSelector)).toBe(appInfo.titleText); 22 | }) 23 | ); 24 | }); 25 | 26 | describe("main vue preload", () => { 27 | beforeAll(async () => { 28 | await page.evaluateOnNewDocument(() => { 29 | // 开启预加载 30 | localStorage.clear(); 31 | localStorage.setItem("preload", "true"); 32 | localStorage.setItem("degrade", "false"); 33 | }); 34 | let mountedPromiseList: Array> = reactMainAppInfoList.map((appInfo) => 35 | awaitConsoleLogMessage(page, appInfo.mountedMessage) 36 | ); 37 | await page.goto("http://localhost:8000/"); 38 | // 所有预加载完成加载 39 | await Promise.all(mountedPromiseList); 40 | }); 41 | 42 | vueMainAppInfoList.forEach((appInfo) => 43 | it(`${appInfo.name} preload`, async () => { 44 | expect(await getTextContentByJsSelector(page, appInfo.preloadTitleJsSelector)).toBe(appInfo.titleText); 45 | }) 46 | ); 47 | }); 48 | -------------------------------------------------------------------------------- /packages/wujie-core/__test__/integration/startApp.test.ts: -------------------------------------------------------------------------------- 1 | import { awaitConsoleLogMessage, getTextContentByJsSelector } from "./utils"; 2 | import { reactMainAppInfoList, vueMainAppInfoList } from "./common"; 3 | 4 | describe("main react startApp", () => { 5 | beforeAll(async () => { 6 | await page.evaluateOnNewDocument(() => { 7 | // 关闭预加载 8 | localStorage.clear(); 9 | localStorage.setItem("preload", "false"); 10 | localStorage.setItem("degrade", "false"); 11 | }); 12 | await page.goto("http://localhost:7700/"); 13 | }); 14 | 15 | reactMainAppInfoList.forEach((appInfo) => 16 | it(`${appInfo.name} startApp`, async () => { 17 | const appInfoMountedPromise = awaitConsoleLogMessage(page, appInfo.mountedMessage); 18 | await page.click(appInfo.linkSelector); 19 | await appInfoMountedPromise; 20 | expect(await getTextContentByJsSelector(page, appInfo.titleJsSelector)).toBe(appInfo.titleText); 21 | }) 22 | ); 23 | }); 24 | 25 | describe("main vue startApp", () => { 26 | beforeAll(async () => { 27 | await page.evaluateOnNewDocument(() => { 28 | // 关闭预加载 29 | localStorage.clear(); 30 | localStorage.setItem("preload", "false"); 31 | localStorage.setItem("degrade", "false"); 32 | }); 33 | await page.goto("http://localhost:8000/"); 34 | }); 35 | 36 | vueMainAppInfoList.forEach((appInfo) => 37 | it(`${appInfo.name} startApp`, async () => { 38 | const appInfoMountedPromise = awaitConsoleLogMessage(page, appInfo.mountedMessage); 39 | await page.click(appInfo.linkSelector); 40 | await appInfoMountedPromise; 41 | expect(await getTextContentByJsSelector(page, appInfo.titleJsSelector)).toBe(appInfo.titleText); 42 | }) 43 | ); 44 | }); 45 | -------------------------------------------------------------------------------- /packages/wujie-core/__test__/integration/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es6", 4 | "rootDir": "../integration", 5 | 6 | /* 额外的检查 */ 7 | "noUnusedLocals": true, 8 | "noUnusedParameters": true, 9 | "noImplicitReturns": true, 10 | "noFallthroughCasesInSwitch": true, 11 | "esModuleInterop": true, 12 | "noEmitOnError": true, 13 | "skipLibCheck": true, 14 | "skipDefaultLibCheck": true, 15 | "moduleResolution": "node", 16 | "downlevelIteration": true, 17 | "experimentalDecorators": true, 18 | "declaration": true, 19 | "types": ["puppeteer", "jest-environment-puppeteer", "jest"] 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /packages/wujie-core/__test__/unit/jestSetup.js: -------------------------------------------------------------------------------- 1 | global.fetch = jest.fn(); 2 | 3 | global.Response = class Response { 4 | constructor(data) { 5 | this.status = 200; 6 | this.data = data 7 | } 8 | text(){ 9 | return this.data 10 | } 11 | } -------------------------------------------------------------------------------- /packages/wujie-core/__test__/unit/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es6", 4 | "rootDirs": ["../src","../unit"], 5 | 6 | /* 额外的检查 */ 7 | "noUnusedLocals": true, 8 | "noUnusedParameters": true, 9 | "noImplicitReturns": true, 10 | "noFallthroughCasesInSwitch": true, 11 | "esModuleInterop": true, 12 | "noEmitOnError": true, 13 | "skipLibCheck": true, 14 | "skipDefaultLibCheck": true, 15 | "moduleResolution": "node", 16 | "downlevelIteration": true, 17 | "experimentalDecorators": true, 18 | "declaration": true, 19 | } 20 | } -------------------------------------------------------------------------------- /packages/wujie-core/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cd $(dirname $0) 4 | 5 | RED='\033[0;31m' 6 | GREEN='\033[0;32m' 7 | NC='\033[0m' 8 | 9 | set -eo pipefail 10 | echo -e "${GREEN}============Wujie开始编译============${NC}" 11 | 12 | rm -rf ./lib ./esm 13 | 14 | npm run lib 15 | 16 | npm run esm 17 | 18 | npx tsc 19 | 20 | echo -e "${GREEN}============Wujie编译成功============${NC}" -------------------------------------------------------------------------------- /packages/wujie-core/jest-puppeteer.config.js: -------------------------------------------------------------------------------- 1 | const { resolve } = require("path"); 2 | const LERNA_EXEC = resolve(__dirname, "../../node_modules/.bin/lerna"); 3 | 4 | module.exports = { 5 | launch: { 6 | headless: true, 7 | devtools: false, 8 | product: "chrome", 9 | }, 10 | server: [ 11 | { 12 | command: LERNA_EXEC + " run start --scope react16", 13 | usedPortAction: "kill", 14 | launchTimeout: 60000, 15 | host: "0.0.0.0", 16 | port: 7600, 17 | }, 18 | { 19 | command: LERNA_EXEC + " run start --scope react17", 20 | usedPortAction: "kill", 21 | launchTimeout: 60000, 22 | host: "0.0.0.0", 23 | port: 7100, 24 | }, 25 | { 26 | command: LERNA_EXEC + " run start --scope vue2", 27 | usedPortAction: "kill", 28 | launchTimeout: 60000, 29 | host: "0.0.0.0", 30 | port: 7200, 31 | }, 32 | { 33 | command: LERNA_EXEC + " run start --scope vue3", 34 | usedPortAction: "kill", 35 | launchTimeout: 60000, 36 | host: "0.0.0.0", 37 | port: 7300, 38 | }, 39 | { 40 | command: LERNA_EXEC + " run start --scope vite", 41 | usedPortAction: "kill", 42 | launchTimeout: 60000, 43 | host: "0.0.0.0", 44 | port: 7500, 45 | }, 46 | { 47 | command: LERNA_EXEC + " run start --scope angular12", 48 | usedPortAction: "kill", 49 | launchTimeout: 60000, 50 | host: "0.0.0.0", 51 | port: 7400, 52 | }, 53 | { 54 | command: LERNA_EXEC + " run integration --scope main-react", 55 | usedPortAction: "kill", 56 | launchTimeout: 60000, 57 | host: "0.0.0.0", 58 | port: 7700, 59 | }, 60 | { 61 | command: LERNA_EXEC + " run start --scope main-vue", 62 | usedPortAction: "kill", 63 | launchTimeout: 60000, 64 | host: "0.0.0.0", 65 | port: 8000, 66 | }, 67 | ], 68 | browserContext: "default", 69 | }; 70 | -------------------------------------------------------------------------------- /packages/wujie-core/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": [ 3 | "./src" 4 | ], 5 | "exclude": [ 6 | "node_modules" 7 | ], 8 | "compilerOptions": { 9 | "outDir": "./esm", 10 | "rootDir": "./src", 11 | /* 额外的检查 */ 12 | "noUnusedLocals": true, 13 | "noUnusedParameters": true, 14 | "noImplicitReturns": true, 15 | "noFallthroughCasesInSwitch": true, 16 | "skipLibCheck": true, 17 | "skipDefaultLibCheck": true, 18 | "downlevelIteration": true, 19 | "declaration": true, 20 | "emitDeclarationOnly": true, 21 | "isolatedModules": true 22 | } 23 | } -------------------------------------------------------------------------------- /packages/wujie-core/webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | 3 | module.exports = { 4 | entry: "./src/index.ts", 5 | target: ["web", "es5"], 6 | output: { 7 | publicPath: "/", 8 | path: path.resolve(__dirname, "./lib"), 9 | filename: "index.js", 10 | library: "wujie", 11 | libraryTarget: "umd", 12 | globalObject: "self", 13 | umdNamedDefine: true, 14 | }, 15 | mode: "production", 16 | resolve: { 17 | extensions: [".ts", ".js"], 18 | }, 19 | devtool: "source-map", 20 | module: { 21 | rules: [ 22 | { 23 | test: /\.ts$/, 24 | exclude: /(node_modules|bower_components)/, 25 | use: { 26 | loader: "babel-loader", 27 | }, 28 | }, 29 | ], 30 | }, 31 | }; 32 | -------------------------------------------------------------------------------- /packages/wujie-react/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["@babel/preset-env", "@babel/preset-react"], 3 | "env": { 4 | "esm": { 5 | "presets": [ 6 | [ 7 | "@babel/preset-env", 8 | { 9 | "modules": false 10 | } 11 | ] 12 | ] 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /packages/wujie-react/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | node: true, 4 | browser: true, 5 | es2021: true, 6 | }, 7 | extends: ["eslint:recommended", "plugin:react/recommended"], 8 | parserOptions: { 9 | ecmaVersion: 2022, 10 | sourceType: "module", 11 | }, 12 | plugins: ["react"], 13 | rules: {}, 14 | ignorePatterns: ["esm/*.js"], 15 | }; 16 | -------------------------------------------------------------------------------- /packages/wujie-react/build.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | cd $(dirname $0) 4 | 5 | set -eo pipefail 6 | 7 | RED='\033[0;31m' 8 | GREEN='\033[0;32m' 9 | NC='\033[0m' 10 | 11 | echo -e "${GREEN}============WujieVue开始编译============${NC}" 12 | 13 | [ -d lib ] && rm -rf lib 14 | [ -d esm ] && rm -rf esm 15 | 16 | npm run lib 17 | 18 | npm run esm 19 | 20 | echo -e "${GREEN}============WujieVue编译成功============${NC}" -------------------------------------------------------------------------------- /packages/wujie-react/index.d.ts: -------------------------------------------------------------------------------- 1 | import { bus, preloadApp, destroyApp, setupApp } from "wujie"; 2 | import PropTypes from "prop-types"; 3 | import React from "react"; 4 | 5 | export default class WujieReact extends React.PureComponent { 6 | static propTypes: { 7 | height: typeof PropTypes.string; 8 | width: typeof PropTypes.string; 9 | name: typeof PropTypes.string; 10 | loading: typeof PropTypes.element; 11 | url: typeof PropTypes.string; 12 | alive: typeof PropTypes.bool; 13 | fetch: typeof PropTypes.func; 14 | props: typeof PropTypes.object; 15 | attrs: typeof PropTypes.object; 16 | replace: typeof PropTypes.func; 17 | sync: typeof PropTypes.bool; 18 | prefix: typeof PropTypes.object; 19 | fiber: typeof PropTypes.bool; 20 | degrade: typeof PropTypes.bool; 21 | plugins: typeof PropTypes.array; 22 | beforeLoad: typeof PropTypes.func; 23 | beforeMount: typeof PropTypes.func; 24 | afterMount: typeof PropTypes.func; 25 | beforeUnmount: typeof PropTypes.func; 26 | afterUnmount: typeof PropTypes.func; 27 | activated: typeof PropTypes.func; 28 | deactivated: typeof PropTypes.func; 29 | loadError: typeof PropTypes.func; 30 | }; 31 | static bus: typeof bus; 32 | static setupApp: typeof setupApp; 33 | static preloadApp: typeof preloadApp; 34 | static destroyApp: typeof destroyApp; 35 | } 36 | -------------------------------------------------------------------------------- /packages/wujie-react/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "wujie-react", 3 | "version": "1.0.28", 4 | "description": "无界微前端React组件封装", 5 | "main": "./lib/index.js", 6 | "module": "./esm/index.js", 7 | "files": [ 8 | "esm", 9 | "lib", 10 | "index.d.ts" 11 | ], 12 | "scripts": { 13 | "lib": "webpack build --config webpack.config.js", 14 | "esm": "cross-env BABEL_ENV=esm babel index.js --out-dir ./esm --source-maps", 15 | "prepack": "bash build.sh", 16 | "start": "cross-env BABEL_ENV=esm babel index.js --out-dir ./esm --source-maps inline --watch", 17 | "test": "echo \"Error: no test specified\" && exit 1" 18 | }, 19 | "publishConfig": { 20 | "access": "public" 21 | }, 22 | "peerDependencies": { 23 | "react": ">=16.0.0" 24 | }, 25 | "config": { 26 | "unsafe-perm": true, 27 | "registry": "https://registry.npmjs.org/" 28 | }, 29 | "author": "yiludege", 30 | "license": "MIT", 31 | "dependencies": { 32 | "prop-types": "^15.8.1", 33 | "wujie": "workspace:1.0.28" 34 | }, 35 | "devDependencies": { 36 | "@babel/cli": "^7.18.6", 37 | "@babel/core": "^7.16.0", 38 | "@babel/preset-env": "^7.16.0", 39 | "@babel/preset-react": "^7.16.7", 40 | "babel-loader": "^8.2.3", 41 | "cross-env": "^7.0.3", 42 | "eslint": "^8.2.0", 43 | "eslint-plugin-react": "^7.29.3", 44 | "webpack": "5.98.0", 45 | "webpack-cli": "^4.9.1" 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /packages/wujie-react/webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | 3 | module.exports = { 4 | entry: "./index.js", 5 | target: ["web", "es5"], 6 | output: { 7 | publicPath: "/", 8 | path: path.resolve(__dirname, "./lib"), 9 | filename: "index.js", 10 | library: "WujieReact", 11 | libraryExport: 'default', 12 | libraryTarget: "umd", 13 | globalObject: "self", 14 | umdNamedDefine: true, 15 | }, 16 | mode: "production", 17 | externals: { 18 | react: { 19 | root: "React", 20 | commonjs: "react", 21 | commonjs2: "react", 22 | amd: "React", 23 | }, 24 | }, 25 | devtool: 'source-map', 26 | resolve: { 27 | extensions: [".js"], 28 | }, 29 | module: { 30 | rules: [ 31 | { 32 | test: /\.js$/, 33 | exclude: /(node_modules|bower_components)/, 34 | use: { 35 | loader: "babel-loader", 36 | }, 37 | }, 38 | ], 39 | }, 40 | }; 41 | -------------------------------------------------------------------------------- /packages/wujie-vue2/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["@babel/preset-env"], 3 | "env": { 4 | "esm": { 5 | "presets": [ 6 | [ 7 | "@babel/preset-env", 8 | { 9 | "modules": false 10 | } 11 | ] 12 | ] 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /packages/wujie-vue2/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | node: true, 4 | browser: true, 5 | es2021: true, 6 | }, 7 | extends: ["eslint:recommended", "plugin:vue/essential"], 8 | parserOptions: { 9 | ecmaVersion: 12, 10 | sourceType: "module", 11 | }, 12 | plugins: ["vue"], 13 | rules: {}, 14 | ignorePatterns: ["esm/*.js"], 15 | }; 16 | -------------------------------------------------------------------------------- /packages/wujie-vue2/build.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | cd $(dirname $0) 4 | 5 | set -eo pipefail 6 | 7 | RED='\033[0;31m' 8 | GREEN='\033[0;32m' 9 | NC='\033[0m' 10 | 11 | echo -e "${GREEN}============WujieVue开始编译============${NC}" 12 | 13 | [ -d lib ] && rm -rf lib 14 | [ -d esm ] && rm -rf esm 15 | 16 | npm run lib 17 | 18 | npm run esm 19 | 20 | echo -e "${GREEN}============WujieVue编译成功============${NC}" -------------------------------------------------------------------------------- /packages/wujie-vue2/index.d.ts: -------------------------------------------------------------------------------- 1 | import { VueConstructor } from "vue"; 2 | import { bus, preloadApp, destroyApp, setupApp } from "wujie"; 3 | 4 | declare const WujieVue: { 5 | bus: typeof bus; 6 | setupApp: typeof setupApp; 7 | preloadApp: typeof preloadApp; 8 | destroyApp: typeof destroyApp; 9 | install: (Vue: VueConstructor) => void; 10 | }; 11 | 12 | export default WujieVue; 13 | -------------------------------------------------------------------------------- /packages/wujie-vue2/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "wujie-vue2", 3 | "version": "1.0.28", 4 | "description": "无界微前端Vue2组件封装", 5 | "main": "./lib/index.js", 6 | "module": "./esm/index.js", 7 | "files": [ 8 | "esm", 9 | "lib", 10 | "index.d.ts" 11 | ], 12 | "scripts": { 13 | "lib": "webpack build --mode=production --config webpack.config.js", 14 | "esm": "cross-env BABEL_ENV=esm babel index.js --out-dir ./esm --source-maps", 15 | "prepack": "bash build.sh", 16 | "start": "cross-env BABEL_ENV=esm babel index.js --out-dir ./esm --source-maps inline --watch", 17 | "test": "echo \"Error: no test specified\" && exit 1" 18 | }, 19 | "author": "yiludege", 20 | "publishConfig": { 21 | "access": "public" 22 | }, 23 | "peerDependencies": { 24 | "vue": "^2.6.0" 25 | }, 26 | "config": { 27 | "unsafe-perm": true, 28 | "registry": "https://registry.npmjs.org/" 29 | }, 30 | "license": "MIT", 31 | "dependencies": { 32 | "wujie": "workspace:1.0.28" 33 | }, 34 | "devDependencies": { 35 | "@babel/cli": "^7.18.6", 36 | "@babel/core": "^7.16.0", 37 | "@babel/preset-env": "^7.16.0", 38 | "babel-loader": "^8.2.3", 39 | "cross-env": "^7.0.3", 40 | "csstype": "^3.1.1", 41 | "eslint": "^8.2.0", 42 | "eslint-plugin-vue": "^8.0.3", 43 | "webpack": "5.98.0", 44 | "webpack-cli": "^4.9.1" 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /packages/wujie-vue2/webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | 3 | module.exports = { 4 | entry: "./index.js", 5 | target: ["web", "es5"], 6 | output: { 7 | publicPath: "/", 8 | path: path.resolve(__dirname, "./lib"), 9 | filename: "index.js", 10 | libraryExport: 'default', 11 | library: "WujieVue", 12 | libraryTarget: "umd", 13 | globalObject: "self", 14 | umdNamedDefine: true, 15 | }, 16 | mode: "production", 17 | externals: { 18 | vue: { 19 | root: "Vue", 20 | commonjs: "vue", 21 | commonjs2: "vue", 22 | amd: "vue", 23 | }, 24 | }, 25 | resolve: { 26 | extensions: [".js"], 27 | }, 28 | devtool: 'source-map', 29 | module: { 30 | rules: [ 31 | { 32 | test: /\.js$/, 33 | exclude: /(node_modules|bower_components)/, 34 | use: { 35 | loader: "babel-loader", 36 | }, 37 | }, 38 | ], 39 | }, 40 | }; 41 | -------------------------------------------------------------------------------- /packages/wujie-vue3/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["@babel/preset-env"], 3 | "env": { 4 | "esm": { 5 | "presets": [ 6 | [ 7 | "@babel/preset-env", 8 | { 9 | "modules": false 10 | } 11 | ] 12 | ] 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /packages/wujie-vue3/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | node: true, 4 | browser: true, 5 | es2021: true, 6 | }, 7 | extends: ["eslint:recommended", "plugin:vue/essential"], 8 | parserOptions: { 9 | ecmaVersion: 12, 10 | sourceType: "module", 11 | }, 12 | plugins: ["vue"], 13 | rules: {}, 14 | ignorePatterns: ["esm/*.js"], 15 | }; 16 | -------------------------------------------------------------------------------- /packages/wujie-vue3/build.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | cd $(dirname $0) 4 | 5 | set -eo pipefail 6 | 7 | RED='\033[0;31m' 8 | GREEN='\033[0;32m' 9 | NC='\033[0m' 10 | 11 | echo -e "${GREEN}============WujieVue开始编译============${NC}" 12 | 13 | [ -d lib ] && rm -rf lib 14 | [ -d esm ] && rm -rf esm 15 | 16 | npm run lib 17 | 18 | npm run esm 19 | 20 | echo -e "${GREEN}============WujieVue编译成功============${NC}" -------------------------------------------------------------------------------- /packages/wujie-vue3/index.d.ts: -------------------------------------------------------------------------------- 1 | import { bus, preloadApp, destroyApp, setupApp } from "wujie"; 2 | import type { DefineComponent, Plugin } from 'vue'; 3 | 4 | declare const WujieVue: DefineComponent & Plugin & { 5 | bus: typeof bus; 6 | setupApp: typeof setupApp; 7 | preloadApp: typeof preloadApp; 8 | destroyApp: typeof destroyApp; 9 | }; 10 | 11 | export default WujieVue; 12 | -------------------------------------------------------------------------------- /packages/wujie-vue3/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "wujie-vue3", 3 | "version": "1.0.28", 4 | "description": "无界微前端Vue3组件封装", 5 | "main": "./lib/index.js", 6 | "module": "./esm/index.js", 7 | "files": [ 8 | "esm", 9 | "lib", 10 | "index.d.ts" 11 | ], 12 | "scripts": { 13 | "lib": "webpack build --mode=production --config webpack.config.js", 14 | "esm": "cross-env BABEL_ENV=esm babel index.js --out-dir ./esm --source-maps", 15 | "prepack": "bash build.sh", 16 | "start": "cross-env BABEL_ENV=esm babel index.js --out-dir ./esm --source-maps inline --watch", 17 | "test": "echo \"Error: no test specified\" && exit 1" 18 | }, 19 | "author": "yiludege", 20 | "publishConfig": { 21 | "access": "public" 22 | }, 23 | "peerDependencies": { 24 | "vue": "^3.0.0" 25 | }, 26 | "config": { 27 | "unsafe-perm": true, 28 | "registry": "https://registry.npmjs.org/" 29 | }, 30 | "license": "MIT", 31 | "dependencies": { 32 | "wujie": "workspace:1.0.28" 33 | }, 34 | "devDependencies": { 35 | "@babel/cli": "^7.18.6", 36 | "@babel/core": "^7.16.0", 37 | "@babel/preset-env": "^7.16.0", 38 | "babel-loader": "^8.2.3", 39 | "cross-env": "^7.0.3", 40 | "csstype": "^3.1.1", 41 | "eslint": "^8.2.0", 42 | "eslint-plugin-vue": "^8.0.3", 43 | "vue": "^3.0.0", 44 | "webpack": "5.98.0", 45 | "webpack-cli": "^4.9.1" 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /packages/wujie-vue3/webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | 3 | module.exports = { 4 | entry: './index.js', 5 | target: ["web", "es5"], 6 | output: { 7 | publicPath: '/', 8 | path: path.resolve(__dirname, './lib'), 9 | filename: 'index.js', 10 | library: 'WujieVue', 11 | libraryExport: 'default', 12 | libraryTarget: 'umd', 13 | globalObject: 'self', 14 | umdNamedDefine: true 15 | }, 16 | mode: "production", 17 | externals: { 18 | vue: { 19 | root: "Vue", 20 | commonjs: "vue", 21 | commonjs2: "vue", 22 | amd: "vue" 23 | } 24 | }, 25 | resolve: { 26 | extensions: ['.js'] 27 | }, 28 | devtool: 'source-map', 29 | module: { 30 | rules: [ 31 | { 32 | test: /\.js$/, 33 | exclude: /(node_modules|bower_components)/, 34 | use: { 35 | loader: 'babel-loader', 36 | options: { 37 | presets: ['@babel/preset-env'] 38 | } 39 | } 40 | } 41 | ] 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /pnpm-workspace.yaml: -------------------------------------------------------------------------------- 1 | 2 | packages: 3 | - 'packages/*' 4 | - 'examples/*' 5 | - 'docs' -------------------------------------------------------------------------------- /scripts/local-angular12-build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cd $(dirname $0)/.. 4 | 5 | set -eo pipefail 6 | 7 | cd ./examples/angular12 8 | 9 | npm run build 10 | 11 | cd ../../ 12 | 13 | rm -rf ../demo-angular12/* 14 | 15 | 16 | mv examples/angular12/dist/* ../demo-angular12/ 17 | cp ../demo-angular12/index.html ../demo-angular12/404.html 18 | cd ../demo-angular12 19 | git add . 20 | git commit -m 'feat: demo修改' 21 | git push 22 | 23 | -------------------------------------------------------------------------------- /scripts/local-doc-build.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | cd $(dirname $0)/.. 4 | 5 | set -eo pipefail 6 | 7 | cd ./docs 8 | 9 | npm run docs:build 10 | 11 | cd ../ 12 | 13 | rm -rf ../doc/* 14 | 15 | mv ./docs/.vitepress/dist/* ../doc/ 16 | cp ../doc/index.html ../doc/404.html 17 | cd ../doc 18 | git add . 19 | git commit -m 'feat: demo修改' 20 | git push 21 | -------------------------------------------------------------------------------- /scripts/local-main-react.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cd $(dirname $0)/.. 4 | 5 | set -eo pipefail 6 | 7 | cd ./examples/main-react 8 | 9 | npm run build 10 | 11 | cd ../../ 12 | 13 | rm -rf ../demo-main-react/* 14 | 15 | 16 | mv examples/main-react/build/* ../demo-main-react/ 17 | cp ../demo-main-react/index.html ../demo-main-react/404.html 18 | cd ../demo-main-react 19 | git add . 20 | git commit -m 'feat: demo修改' 21 | git push 22 | 23 | -------------------------------------------------------------------------------- /scripts/local-main-vue.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cd $(dirname $0)/.. 4 | 5 | set -eo pipefail 6 | 7 | cd ./examples/main-vue 8 | 9 | npm run build 10 | 11 | cd ../../ 12 | 13 | rm -rf ../demo-main-vue/* 14 | 15 | 16 | mv examples/main-vue/dist/* ../demo-main-vue/ 17 | cp ../demo-main-vue/index.html ../demo-main-vue/404.html 18 | cd ../demo-main-vue 19 | git add . 20 | git commit -m 'feat: demo修改' 21 | git push 22 | 23 | -------------------------------------------------------------------------------- /scripts/local-react16-build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cd $(dirname $0)/.. 4 | 5 | set -eo pipefail 6 | 7 | cd ./examples/react16 8 | 9 | npm run build 10 | 11 | cd ../../ 12 | 13 | rm -rf ../demo-react16/* 14 | 15 | 16 | mv examples/react16/build/* ../demo-react16/ 17 | cp ../demo-react16/index.html ../demo-react16/404.html 18 | cd ../demo-react16 19 | git add . 20 | git commit -m 'feat: demo修改' 21 | git push 22 | 23 | -------------------------------------------------------------------------------- /scripts/local-react17-build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cd $(dirname $0)/.. 4 | 5 | set -eo pipefail 6 | 7 | cd ./examples/react17 8 | 9 | npm run build 10 | 11 | cd ../../ 12 | 13 | rm -rf ../demo-react17/* 14 | 15 | 16 | mv examples/react17/build/* ../demo-react17/ 17 | cp ../demo-react17/index.html ../demo-react17/404.html 18 | cd ../demo-react17 19 | git add . 20 | git commit -m 'feat: demo修改' 21 | git push 22 | 23 | -------------------------------------------------------------------------------- /scripts/local-vite-build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cd $(dirname $0)/.. 4 | 5 | set -eo pipefail 6 | 7 | cd ./examples/vite 8 | 9 | npm run build 10 | 11 | cd ../../ 12 | 13 | rm -rf ../demo-vite/* 14 | 15 | 16 | mkdir -p ../demo-vite/ 17 | mv examples/vite/dist/* ../demo-vite/ 18 | sed -i '' 's/crossorigin/crossorigin="use-credentials"/g' ../demo-vite/index.html 19 | cp ../demo-vite/index.html ../demo-vite/404.html 20 | cd ../demo-vite 21 | git add . 22 | git commit -m 'feat: demo修改' 23 | git push 24 | 25 | -------------------------------------------------------------------------------- /scripts/local-vue2-build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cd $(dirname $0)/.. 4 | 5 | set -eo pipefail 6 | 7 | cd ./examples/vue2 8 | 9 | npm run build 10 | 11 | cd ../../ 12 | 13 | rm -rf ../demo-vue2/* 14 | 15 | 16 | mv examples/vue2/dist/* ../demo-vue2 17 | cp ../demo-vue2/index.html ../demo-vue2/404.html 18 | cd ../demo-vue2 19 | git add . 20 | git commit -m 'feat: demo修改' 21 | git push 22 | 23 | -------------------------------------------------------------------------------- /scripts/local-vue3-build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cd $(dirname $0)/.. 4 | 5 | set -eo pipefail 6 | 7 | cd ./examples/vue3 8 | 9 | npm run build 10 | 11 | cd ../../ 12 | 13 | rm -rf ../demo-vue3/* 14 | 15 | 16 | mv examples/vue3/dist/* ../demo-vue3/ 17 | cp ../demo-vue3/index.html ../demo-vue3/404.html 18 | cd ../demo-vue3 19 | git add . 20 | git commit -m 'feat: demo修改' 21 | git push 22 | 23 | --------------------------------------------------------------------------------