Showing preview only (1,582K chars total). Download the full file or copy to clipboard to get everything.
Repository: umijs/qiankun
Branch: next
Commit: 595b93c50292
Files: 382
Total size: 1.4 MB
Directory structure:
gitextract_dfszrfro/
├── .changeset/
│ ├── README.md
│ ├── big-cougars-draw.md
│ ├── clean-walls-hang.md
│ ├── clever-carpets-vanish.md
│ ├── clever-dragons-ring.md
│ ├── config.json
│ ├── empty-jars-vanish.md
│ ├── empty-lions-rescue.md
│ ├── five-papayas-buy.md
│ ├── forty-teachers-taste.md
│ ├── four-worms-think.md
│ ├── friendly-apples-design.md
│ ├── giant-geckos-love.md
│ ├── green-pants-remember.md
│ ├── green-tools-wonder.md
│ ├── hungry-needles-doubt.md
│ ├── itchy-pears-retire.md
│ ├── itchy-snakes-tell.md
│ ├── large-jokes-smile.md
│ ├── lemon-seals-juggle.md
│ ├── long-flies-repair.md
│ ├── loud-berries-watch.md
│ ├── loud-penguins-crash.md
│ ├── loud-teachers-develop.md
│ ├── lovely-colts-decide.md
│ ├── lucky-bikes-scream.md
│ ├── metal-cougars-help.md
│ ├── mighty-nails-pull.md
│ ├── modern-kiwis-tap.md
│ ├── ninety-rivers-check.md
│ ├── orange-boats-allow.md
│ ├── poor-squids-hide.md
│ ├── pre.json
│ ├── rare-lobsters-marry.md
│ ├── real-trees-unite.md
│ ├── red-islands-mate.md
│ ├── red-students-run.md
│ ├── rich-parents-relate.md
│ ├── selfish-lamps-thank.md
│ ├── serious-nails-jog.md
│ ├── shaggy-shrimps-drum.md
│ ├── sharp-files-raise.md
│ ├── shiny-jeans-sip.md
│ ├── short-kings-explain.md
│ ├── shy-mayflies-shave.md
│ ├── silly-books-complain.md
│ ├── slow-timers-heal.md
│ ├── small-experts-hug.md
│ ├── smart-guests-jam.md
│ ├── smart-scissors-press.md
│ ├── smart-scissors-sell.md
│ ├── smooth-pillows-jam.md
│ ├── sour-roses-smile.md
│ ├── spotty-plums-hear.md
│ ├── stale-dolls-push.md
│ ├── strong-rocks-sneeze.md
│ ├── sweet-cars-protect.md
│ ├── sweet-shoes-brake.md
│ ├── swift-squids-vanish.md
│ ├── tall-buttons-pretend.md
│ ├── tasty-donkeys-relax.md
│ ├── tender-dingos-allow.md
│ ├── tender-pots-perform.md
│ ├── thin-ways-allow.md
│ ├── three-hornets-hammer.md
│ ├── tough-beers-grow.md
│ ├── tough-phones-chew.md
│ ├── twelve-donkeys-help.md
│ ├── warm-chefs-chew.md
│ ├── wicked-icons-type.md
│ ├── wise-eagles-tease.md
│ └── wise-ravens-prove.md
├── .dumirc.ts
├── .editorconfig
├── .eslintignore
├── .eslintrc.cjs
├── .fatherrc.cjs
├── .github/
│ ├── CODE_OF_CONDUCT.md
│ ├── CONTRIBUTING.md
│ ├── ISSUE_TEMPLATE/
│ │ ├── bug_report.md
│ │ ├── bug_report_cn.md
│ │ ├── feature_request.md
│ │ └── rfc_cn.md
│ ├── PULL_REQUEST_TEMPLATE.md
│ └── workflows/
│ ├── announcement-notify.yml
│ ├── changeset-prerelease.yml
│ ├── ci.yml
│ ├── emoji-helper.yml
│ ├── github-pages.yml
│ ├── issue-close-inactive.yml
│ ├── issue-reply.yml
│ ├── publish-1.x.yml
│ ├── publish-latest.yml
│ └── release-notify.yml
├── .gitignore
├── .husky/
│ ├── commit-msg
│ ├── pre-commit
│ └── pre-push
├── .prettierignore
├── .prettierrc
├── AGENTS.md
├── LICENSE
├── README.md
├── commitlint.config.js
├── docs/
│ ├── .vitepress/
│ │ ├── config.mjs
│ │ └── theme/
│ │ └── index.js
│ ├── api/
│ │ ├── configuration.md
│ │ ├── index.md
│ │ ├── is-runtime-compatible.md
│ │ ├── lifecycles.md
│ │ ├── load-micro-app.md
│ │ ├── register-micro-apps.md
│ │ ├── start.md
│ │ └── types.md
│ ├── cookbook/
│ │ ├── error-handling.md
│ │ ├── index.md
│ │ ├── performance.md
│ │ └── style-isolation.md
│ ├── ecosystem/
│ │ ├── bundler-plugin.md
│ │ ├── create-qiankun.md
│ │ ├── index.md
│ │ ├── react.md
│ │ └── vue.md
│ ├── faq/
│ │ └── index.md
│ ├── guide/
│ │ ├── index.md
│ │ ├── quick-start.md
│ │ └── tutorial.md
│ ├── index.md
│ └── zh-CN/
│ ├── api/
│ │ ├── configuration.md
│ │ ├── index.md
│ │ ├── is-runtime-compatible.md
│ │ ├── lifecycles.md
│ │ ├── load-micro-app.md
│ │ ├── register-micro-apps.md
│ │ ├── start.md
│ │ └── types.md
│ ├── cookbook/
│ │ ├── error-handling.md
│ │ ├── index.md
│ │ ├── performance.md
│ │ └── style-isolation.md
│ ├── ecosystem/
│ │ ├── create-qiankun.md
│ │ ├── index.md
│ │ ├── react.md
│ │ ├── vue.md
│ │ └── webpack-plugin.md
│ ├── faq/
│ │ └── index.md
│ ├── guide/
│ │ ├── index.md
│ │ ├── quick-start.md
│ │ └── tutorial.md
│ └── index.md
├── examples/
│ ├── main/
│ │ ├── index.html
│ │ ├── package.json
│ │ ├── postcss.config.js
│ │ ├── src/
│ │ │ ├── App.tsx
│ │ │ ├── components/
│ │ │ │ ├── Dashboard.tsx
│ │ │ │ ├── Header.tsx
│ │ │ │ ├── MicroAppContainer.tsx
│ │ │ │ └── Sidebar.tsx
│ │ │ ├── main.tsx
│ │ │ ├── store/
│ │ │ │ └── qiankun.ts
│ │ │ ├── styles/
│ │ │ │ └── index.css
│ │ │ └── vite-env.d.ts
│ │ ├── tailwind.config.js
│ │ ├── tsconfig.json
│ │ ├── tsconfig.node.json
│ │ └── vite.config.ts
│ ├── purehtml/
│ │ ├── entry.js
│ │ ├── index.html
│ │ └── package.json
│ ├── react/
│ │ ├── .gitignore
│ │ ├── README.md
│ │ ├── config/
│ │ │ └── qiankunHtml.ts
│ │ ├── eslint.config.js
│ │ ├── index.html
│ │ ├── package.json
│ │ ├── src/
│ │ │ ├── App.css
│ │ │ ├── App.tsx
│ │ │ ├── index.css
│ │ │ ├── main.tsx
│ │ │ └── vite-env.d.ts
│ │ ├── tsconfig.app.json
│ │ ├── tsconfig.json
│ │ ├── tsconfig.node.json
│ │ └── vite.config.ts
│ ├── vite/
│ │ ├── .eslintrc.cjs
│ │ ├── .gitignore
│ │ ├── index.html
│ │ ├── package.json
│ │ ├── src/
│ │ │ ├── App.css
│ │ │ ├── App.tsx
│ │ │ ├── index.css
│ │ │ ├── main.tsx
│ │ │ └── vite-env.d.ts
│ │ ├── tsconfig.json
│ │ ├── tsconfig.node.json
│ │ └── vite.config.ts
│ └── vue/
│ ├── .gitignore
│ ├── README.md
│ ├── config/
│ │ └── qiankunHtml.ts
│ ├── index.html
│ ├── package.json
│ ├── src/
│ │ ├── App.vue
│ │ ├── components/
│ │ │ └── HelloWorld.vue
│ │ ├── main.ts
│ │ ├── style.css
│ │ └── vite-env.d.ts
│ ├── tsconfig.app.json
│ ├── tsconfig.json
│ ├── tsconfig.node.json
│ └── vite.config.ts
├── package.json
├── packages/
│ ├── bundler-plugin/
│ │ ├── .fatherrc.js
│ │ ├── CHANGELOG.md
│ │ ├── README-zh.md
│ │ ├── README.md
│ │ ├── package.json
│ │ ├── src/
│ │ │ ├── index.ts
│ │ │ └── webpack/
│ │ │ └── index.ts
│ │ └── tests/
│ │ ├── fixtures/
│ │ │ ├── webpack4.html
│ │ │ └── webpack5.html
│ │ ├── plugin.test.ts
│ │ ├── webpack4/
│ │ │ ├── .eslintrc.js
│ │ │ ├── index.html
│ │ │ ├── index.js
│ │ │ ├── package.json
│ │ │ └── webpack.config.js
│ │ └── webpack5/
│ │ ├── .eslintrc.js
│ │ ├── index.html
│ │ ├── index.js
│ │ ├── package.json
│ │ └── webpack.config.js
│ ├── create-qiankun/
│ │ ├── .fatherrc.js
│ │ ├── CHANGELOG.md
│ │ ├── Readme.md
│ │ ├── package.json
│ │ ├── src/
│ │ │ ├── index.ts
│ │ │ └── shared/
│ │ │ ├── generators/
│ │ │ │ └── createVite.ts
│ │ │ ├── patchers/
│ │ │ │ ├── entryFile.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── packageJson.ts
│ │ │ │ ├── qiankunHtmlPlugin.ts
│ │ │ │ └── viteConfig.ts
│ │ │ ├── types.ts
│ │ │ └── utils/
│ │ │ └── index.ts
│ │ ├── tests/
│ │ │ ├── e2e.cli.test.ts
│ │ │ └── fixtures/
│ │ │ ├── react-ts/
│ │ │ │ ├── main.tsx.txt
│ │ │ │ ├── qiankunHtml.ts.txt
│ │ │ │ └── vite.config.ts.txt
│ │ │ └── vue-ts/
│ │ │ ├── main.ts.txt
│ │ │ ├── qiankunHtml.ts.txt
│ │ │ └── vite.config.ts.txt
│ │ ├── tsconfig.json
│ │ ├── vitest.config.ts
│ │ └── vitest.e2e.config.ts
│ ├── loader/
│ │ ├── .fatherrc.js
│ │ ├── AGENTS.md
│ │ ├── CHANGELOG.md
│ │ ├── benchmarks/
│ │ │ └── parser/
│ │ │ ├── html.js
│ │ │ ├── huge-html/
│ │ │ │ ├── huge-html.js
│ │ │ │ ├── import-html-entry.html
│ │ │ │ └── parser.html
│ │ │ ├── import-html-entry.html
│ │ │ ├── parser.html
│ │ │ └── tern/
│ │ │ ├── html.js
│ │ │ ├── import-html-entry.html
│ │ │ └── parser.html
│ │ ├── package.json
│ │ └── src/
│ │ ├── TagTransformStream.ts
│ │ ├── index.ts
│ │ ├── parser.ts
│ │ ├── utils.ts
│ │ └── writable-dom/
│ │ ├── README.md
│ │ └── index.ts
│ ├── qiankun/
│ │ ├── .fatherrc.js
│ │ ├── CHANGELOG.md
│ │ ├── README.md
│ │ ├── package.json
│ │ └── src/
│ │ ├── addons/
│ │ │ ├── engineFlag.ts
│ │ │ ├── index.ts
│ │ │ └── runtimePublicPath.ts
│ │ ├── apis/
│ │ │ ├── __tests__/
│ │ │ │ ├── effects.test.ts
│ │ │ │ └── prefetch.test.ts
│ │ │ ├── effects.ts
│ │ │ ├── errorHandler.ts
│ │ │ ├── isRuntimeCompatible.ts
│ │ │ ├── loadMicroApp.ts
│ │ │ ├── prefetch.ts
│ │ │ └── registerMicroApps.ts
│ │ ├── core/
│ │ │ └── loadApp.ts
│ │ ├── error.ts
│ │ ├── index.ts
│ │ ├── types.ts
│ │ └── utils.ts
│ ├── sandbox/
│ │ ├── .fatherrc.js
│ │ ├── AGENTS.md
│ │ ├── CHANGELOG.md
│ │ ├── package.json
│ │ └── src/
│ │ ├── consts.ts
│ │ ├── core/
│ │ │ ├── compartment/
│ │ │ │ ├── globalProps.ts
│ │ │ │ └── index.ts
│ │ │ ├── globals.ts
│ │ │ ├── membrane/
│ │ │ │ ├── index.ts
│ │ │ │ └── utils.ts
│ │ │ ├── sandbox/
│ │ │ │ ├── StandardSandbox.ts
│ │ │ │ ├── index.ts
│ │ │ │ └── types.ts
│ │ │ └── utils.ts
│ │ ├── index.ts
│ │ ├── patchers/
│ │ │ ├── consts.ts
│ │ │ ├── dynamicAppend/
│ │ │ │ ├── common.ts
│ │ │ │ ├── forStandardSandbox.ts
│ │ │ │ ├── index.ts
│ │ │ │ └── types.ts
│ │ │ ├── historyListener.ts
│ │ │ ├── index.ts
│ │ │ ├── interval.ts
│ │ │ ├── types.ts
│ │ │ └── windowListener.ts
│ │ └── utils.ts
│ ├── shared/
│ │ ├── .fatherrc.js
│ │ ├── AGENTS.md
│ │ ├── CHANGELOG.md
│ │ ├── package.json
│ │ └── src/
│ │ ├── assets-transpilers/
│ │ │ ├── __tests__/
│ │ │ │ └── script.test.ts
│ │ │ ├── index.ts
│ │ │ ├── link.ts
│ │ │ ├── script.ts
│ │ │ ├── types.ts
│ │ │ └── utils.ts
│ │ ├── common.ts
│ │ ├── deferred-queue/
│ │ │ └── index.ts
│ │ ├── fetch-utils/
│ │ │ ├── __tests__/
│ │ │ │ ├── makeFetchCacheable.test.ts
│ │ │ │ ├── makeFetchRetryable.test.ts
│ │ │ │ └── makeFetchThrowable.test.ts
│ │ │ ├── makeFetchCacheable.ts
│ │ │ ├── makeFetchRetryable.ts
│ │ │ ├── makeFetchThrowable.ts
│ │ │ ├── miniLruCache.ts
│ │ │ └── utils.ts
│ │ ├── index.ts
│ │ ├── module-resolver/
│ │ │ ├── __tests__/
│ │ │ │ ├── index.test.ts
│ │ │ │ └── satisfies.test.ts
│ │ │ ├── index.ts
│ │ │ ├── satisfies.ts
│ │ │ └── types.ts
│ │ ├── reporter/
│ │ │ ├── QiankunError.ts
│ │ │ ├── index.ts
│ │ │ └── logger.ts
│ │ ├── typings.d.ts
│ │ └── utils.ts
│ └── ui-bindings/
│ ├── react/
│ │ ├── .eslintrc.cjs
│ │ ├── .fatherrc.js
│ │ ├── CHANGELOG.md
│ │ ├── README.md
│ │ ├── README.zh-CN.md
│ │ ├── package.json
│ │ ├── src/
│ │ │ ├── ErrorBoundary.tsx
│ │ │ ├── MicroApp.tsx
│ │ │ ├── MicroAppLoader.tsx
│ │ │ └── index.ts
│ │ └── tsconfig.json
│ ├── shared/
│ │ ├── .fatherrc.js
│ │ ├── CHANGELOG.md
│ │ ├── package.json
│ │ ├── src/
│ │ │ └── index.ts
│ │ └── tsconfig.json
│ └── vue/
│ ├── .fatherrc.js
│ ├── CHANGELOG.md
│ ├── README.md
│ ├── README.zh-CN.md
│ ├── package.json
│ ├── src/
│ │ ├── ErrorBoundary.ts
│ │ ├── MicroApp.ts
│ │ ├── MicroAppLoader.ts
│ │ └── index.ts
│ └── tsconfig.json
├── pnpm-workspace.yaml
├── scripts/
│ └── generate-release-notes.mjs
├── tsconfig.eslint.json
├── tsconfig.json
├── vitest.config.ts
└── vitest.workspace.ts
================================================
FILE CONTENTS
================================================
================================================
FILE: .changeset/README.md
================================================
# Changesets
Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works
with multi-package repos, or single-package repos to help you version and publish your code. You can
find the full documentation for it [in our repository](https://github.com/changesets/changesets)
We have a quick list of common questions to get you started engaging with this project in
[our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md)
================================================
FILE: .changeset/big-cougars-draw.md
================================================
---
"@qiankunjs/sandbox": patch
---
feat(sandbox): use cloneNode api instead of importNode for compatible
================================================
FILE: .changeset/clean-walls-hang.md
================================================
---
"@qiankunjs/bundler-plugin": patch
---
fix: move cheerio to dependencies
================================================
FILE: .changeset/clever-carpets-vanish.md
================================================
---
"@qiankunjs/sandbox": patch
---
Revert "fix(sandbox): non-hijacking elements should be appended to global document (#2861)"
================================================
FILE: .changeset/clever-dragons-ring.md
================================================
---
"qiankun": patch
"@qiankunjs/loader": patch
"@qiankunjs/sandbox": patch
"@qiankunjs/shared": patch
---
✨support to transform head/body tags to qiankun head/body in stream
================================================
FILE: .changeset/config.json
================================================
{
"$schema": "https://unpkg.com/@changesets/config@2.29.5/schema.json",
"changelog": "@changesets/cli/changelog",
"commit": true,
"fixed": [],
"linked": [],
"access": "public",
"baseBranch": "next",
"updateInternalDependencies": "patch",
"ignore": [],
"___experimentalUnsafeOptions_WILL_CHANGE_IN_PATCH": {
"onlyUpdatePeerDependentsWhenOutOfRange": true
}
}
================================================
FILE: .changeset/empty-jars-vanish.md
================================================
---
'create-qiankun': minor
---
feat: introduce qiankun scaffold
================================================
FILE: .changeset/empty-lions-rescue.md
================================================
---
'@qiankunjs/shared': patch
---
fix: remove inline script source-url
================================================
FILE: .changeset/five-papayas-buy.md
================================================
---
"qiankun": patch
"@qiankunjs/shared": patch
---
fix: optimize types and add a warning for preload
================================================
FILE: .changeset/forty-teachers-taste.md
================================================
---
'@qiankunjs/ui-shared': patch
'@qiankunjs/react': patch
'@qiankunjs/vue': patch
---
feat: refactor the code of microapp
================================================
FILE: .changeset/four-worms-think.md
================================================
---
"@qiankunjs/sandbox": patch
"@qiankunjs/shared": patch
---
feat(sandbox): support dynamic sync scripts executed by order in sandbox
================================================
FILE: .changeset/friendly-apples-design.md
================================================
---
"qiankun": patch
"@qiankunjs/react": patch
"@qiankunjs/ui-shared": patch
"@qiankunjs/vue": patch
---
fix: remove unused umd bundle configuration
================================================
FILE: .changeset/giant-geckos-love.md
================================================
---
"@qiankunjs/sandbox": patch
---
fix: double quote link element href as selector
================================================
FILE: .changeset/green-pants-remember.md
================================================
---
"@qiankunjs/loader": patch
"qiankun": patch
"@qiankunjs/shared": patch
---
feat: add isRuntimeCompatible api to check qiankun3 compatibility
================================================
FILE: .changeset/green-tools-wonder.md
================================================
---
"@qiankunjs/shared": patch
---
🐛fix findDependency logic while peerDeps is undefined
================================================
FILE: .changeset/hungry-needles-doubt.md
================================================
---
"@qiankunjs/loader": patch
"@qiankunjs/sandbox": patch
"@qiankunjs/shared": patch
---
feat: support defer scripts and keep the executing order to consist with browser
================================================
FILE: .changeset/itchy-pears-retire.md
================================================
---
"qiankun": patch
"@qiankunjs/sandbox": patch
---
feat: pass container with parameters rather than getter function
================================================
FILE: .changeset/itchy-snakes-tell.md
================================================
---
"qiankun": patch
"@qiankunjs/sandbox": patch
---
feat(loader): add lru cache for assets fetch by default
================================================
FILE: .changeset/large-jokes-smile.md
================================================
---
"@qiankunjs/shared": patch
---
🐛fix preload is invalid while reused dependency is working
================================================
FILE: .changeset/lemon-seals-juggle.md
================================================
---
"qiankun": patch
"@qiankunjs/shared": patch
---
feat(shared): introduce retryable and throwable to fetch-utils
================================================
FILE: .changeset/long-flies-repair.md
================================================
---
"@qiankunjs/sandbox": patch
---
🔀 merge master
================================================
FILE: .changeset/loud-berries-watch.md
================================================
---
"@qiankunjs/shared": patch
---
refactor(shared): replace semver with compare-versions
================================================
FILE: .changeset/loud-penguins-crash.md
================================================
---
"@qiankunjs/sandbox": patch
---
feat: set proxy appendChild/insertBefore method for every sandbox rather than modify prototype on HTMLElement
================================================
FILE: .changeset/loud-teachers-develop.md
================================================
---
"qiankun": patch
---
feat: enable sandbox by default
================================================
FILE: .changeset/lovely-colts-decide.md
================================================
---
"create-qiankun": patch
---
feat: introduce qiankun scaffold
================================================
FILE: .changeset/lucky-bikes-scream.md
================================================
---
"@qiankunjs/bundler-plugin": patch
---
fix: mv webpack-sources to deps
================================================
FILE: .changeset/metal-cougars-help.md
================================================
---
"@qiankunjs/sandbox": patch
---
🐛parallel sandbox should use different compartment id
================================================
FILE: .changeset/mighty-nails-pull.md
================================================
---
"@qiankunjs/loader": patch
"@qiankunjs/shared": patch
---
feat(loader): compatible with defer entry script
================================================
FILE: .changeset/modern-kiwis-tap.md
================================================
---
"@qiankunjs/bundler-plugin": patch
---
feat: introduce qiankun webpack plugin
================================================
FILE: .changeset/ninety-rivers-check.md
================================================
---
"@qiankunjs/loader": patch
"qiankun": patch
---
feat: add transformer options for app loader
================================================
FILE: .changeset/orange-boats-allow.md
================================================
---
"qiankun": patch
"@qiankunjs/shared": patch
---
feat: remove webpack chunk cache attributes just while there are multi instances loaded on document
================================================
FILE: .changeset/poor-squids-hide.md
================================================
---
"qiankun": patch
---
fix(qiankun): should remove internal cache of loadMicroApp while loading failed
================================================
FILE: .changeset/pre.json
================================================
{
"mode": "pre",
"tag": "rc",
"initialVersions": {
"@qiankunjs/loader": "0.0.1",
"qiankun": "3.0.0",
"@qiankunjs/sandbox": "0.0.1",
"@qiankunjs/shared": "0.0.1",
"@qiankunjs/react": "0.0.1",
"@qiankunjs/bundler-plugin": "0.0.1",
"@qiankunjs/ui-shared": "0.0.0",
"@qiankunjs/vue": "0.0.0",
"create-qiankun": "0.0.0"
},
"changesets": [
"big-cougars-draw",
"clean-walls-hang",
"clever-carpets-vanish",
"clever-dragons-ring",
"empty-jars-vanish",
"empty-lions-rescue",
"five-papayas-buy",
"forty-teachers-taste",
"four-worms-think",
"friendly-apples-design",
"giant-geckos-love",
"green-pants-remember",
"green-tools-wonder",
"hungry-needles-doubt",
"itchy-pears-retire",
"itchy-snakes-tell",
"large-jokes-smile",
"lemon-seals-juggle",
"long-flies-repair",
"loud-berries-watch",
"loud-penguins-crash",
"loud-teachers-develop",
"lovely-colts-decide",
"lucky-bikes-scream",
"metal-cougars-help",
"mighty-nails-pull",
"modern-kiwis-tap",
"ninety-rivers-check",
"orange-boats-allow",
"poor-squids-hide",
"rare-lobsters-marry",
"real-trees-unite",
"red-islands-mate",
"red-students-run",
"rich-parents-relate",
"selfish-lamps-thank",
"serious-nails-jog",
"shaggy-shrimps-drum",
"sharp-files-raise",
"shiny-jeans-sip",
"short-kings-explain",
"shy-mayflies-shave",
"silly-books-complain",
"slow-timers-heal",
"small-experts-hug",
"smart-guests-jam",
"smart-scissors-press",
"smart-scissors-sell",
"smooth-pillows-jam",
"sour-roses-smile",
"spotty-plums-hear",
"stale-dolls-push",
"strong-rocks-sneeze",
"sweet-cars-protect",
"sweet-shoes-brake",
"swift-squids-vanish",
"tall-buttons-pretend",
"tasty-donkeys-relax",
"tender-dingos-allow",
"tender-pots-perform",
"thin-ways-allow",
"three-hornets-hammer",
"tough-beers-grow",
"tough-phones-chew",
"twelve-donkeys-help",
"warm-chefs-chew",
"wicked-icons-type",
"wise-eagles-tease",
"wise-ravens-prove"
]
}
================================================
FILE: .changeset/rare-lobsters-marry.md
================================================
---
"qiankun": patch
---
🐛 fix tsc error
================================================
FILE: .changeset/real-trees-unite.md
================================================
---
"@qiankunjs/sandbox": patch
---
fix(sandbox): compatible with dynamically appending stylesheets to detached containers
================================================
FILE: .changeset/red-islands-mate.md
================================================
---
"@qiankunjs/loader": patch
"qiankun": patch
---
feat(loader): supports passing Response as entry parameter for loadEntry function
================================================
FILE: .changeset/red-students-run.md
================================================
---
"@qiankunjs/loader": patch
"qiankun": patch
"@qiankunjs/sandbox": patch
"@qiankunjs/react": patch
---
fix(sandbox): should get container from getter function in every accessing
================================================
FILE: .changeset/rich-parents-relate.md
================================================
---
"@qiankunjs/vue": patch
---
fix(vue): add unmount hook to unmount application
================================================
FILE: .changeset/selfish-lamps-thank.md
================================================
---
"qiankun": patch
---
fix: should re-init container while app remounted from cache
================================================
FILE: .changeset/serious-nails-jog.md
================================================
---
"@qiankunjs/bundler-plugin": patch
---
fix: correct entry script identification and webpack version detection in Vue CLI 5
================================================
FILE: .changeset/shaggy-shrimps-drum.md
================================================
---
"@qiankunjs/bundler-plugin": patch
"create-qiankun": patch
---
fix: improve QiankunPlugin webpack compatibility and error handling
================================================
FILE: .changeset/sharp-files-raise.md
================================================
---
"qiankun": patch
---
fix(qiankun): remove premature lifecycle check to allow fallback detection
================================================
FILE: .changeset/shiny-jeans-sip.md
================================================
---
"qiankun": patch
---
feat: make loadEntry and beforeLoad runs parallelly
================================================
FILE: .changeset/short-kings-explain.md
================================================
---
"qiankun": patch
---
✨add registerMicroApps api
================================================
FILE: .changeset/shy-mayflies-shave.md
================================================
---
"@qiankunjs/loader": patch
"@qiankunjs/shared": patch
---
feat: change script src before it execute thus we can be more consistent with the native browser logic
================================================
FILE: .changeset/silly-books-complain.md
================================================
---
"@qiankunjs/sandbox": patch
---
feat(sandbox): micro app mounting should wait unit rebuilding link element loaded to avoid unstyleed content flash
================================================
FILE: .changeset/slow-timers-heal.md
================================================
---
"@qiankunjs/sandbox": patch
---
fix(sandbox): createElement hijack must be paired to avoid rewriting leak
================================================
FILE: .changeset/small-experts-hug.md
================================================
---
"@qiankunjs/sandbox": patch
---
feat: support addEventListener with once options to avoid memory leak
================================================
FILE: .changeset/smart-guests-jam.md
================================================
---
"@qiankunjs/sandbox": patch
---
chore: optimize code
================================================
FILE: .changeset/smart-scissors-press.md
================================================
---
'qiankun': patch
'@qiankunjs/sandbox': patch
---
feat: optimize lifecycle validate log
================================================
FILE: .changeset/smart-scissors-sell.md
================================================
---
"@qiankunjs/loader": patch
"qiankun": patch
"@qiankunjs/sandbox": patch
"@qiankunjs/shared": patch
---
fix: dynamic append element should support for the same container between micro apps
================================================
FILE: .changeset/smooth-pillows-jam.md
================================================
---
"qiankun": patch
"@qiankunjs/shared": patch
---
feat: remove lru-cache and move wrapFetch to shared package
================================================
FILE: .changeset/sour-roses-smile.md
================================================
---
"@qiankunjs/sandbox": patch
"@qiankunjs/react": patch
---
feat: not rebind non-native global properties
================================================
FILE: .changeset/spotty-plums-hear.md
================================================
---
"@qiankunjs/loader": patch
"@qiankunjs/shared": patch
---
feat: improve fetch error message by prepending url
================================================
FILE: .changeset/stale-dolls-push.md
================================================
---
"@qiankunjs/shared": patch
---
feat(transpiler): assets transpiler should work well while sandbox disabled
================================================
FILE: .changeset/strong-rocks-sneeze.md
================================================
---
"@qiankunjs/loader": patch
"@qiankunjs/sandbox": patch
"@qiankunjs/shared": patch
---
fix: defer scripts should wait until html loaded
================================================
FILE: .changeset/sweet-cars-protect.md
================================================
---
"create-qiankun": patch
---
fix: include template to publish field
================================================
FILE: .changeset/sweet-shoes-brake.md
================================================
---
"@qiankunjs/shared": patch
---
fix: should not transform URLs that already include a protocol
================================================
FILE: .changeset/swift-squids-vanish.md
================================================
---
"@qiankunjs/sandbox": patch
---
fix(sandbox): fix async script order index calculate
================================================
FILE: .changeset/tall-buttons-pretend.md
================================================
---
"create-qiankun": patch
---
feat: refactor create-qiankun cli
================================================
FILE: .changeset/tasty-donkeys-relax.md
================================================
---
"qiankun": patch
---
[#2823] Add legacy APIs for qiankun 3.0
================================================
FILE: .changeset/tender-dingos-allow.md
================================================
---
"@qiankunjs/bundler-plugin": patch
---
fix(webpack-plugin):fix webpack module not found during webpack-plugin build
================================================
FILE: .changeset/tender-pots-perform.md
================================================
---
"@qiankunjs/loader": patch
---
fix: prefer reading script.dataset.src in script load error message
================================================
FILE: .changeset/thin-ways-allow.md
================================================
---
"@qiankunjs/loader": patch
---
fix(loader): we should invoke our script load listener before its own
================================================
FILE: .changeset/three-hornets-hammer.md
================================================
---
"qiankun": patch
"@qiankunjs/sandbox": patch
---
fix: should invoke getContainer method to get container every time to avoid reference misordering
================================================
FILE: .changeset/tough-beers-grow.md
================================================
---
"@qiankunjs/loader": patch
"qiankun": patch
---
fix: transformer should be generated in every load
================================================
FILE: .changeset/tough-phones-chew.md
================================================
---
"@qiankunjs/loader": patch
"qiankun": patch
"@qiankunjs/sandbox": patch
"@qiankunjs/shared": patch
---
🐛 compatible with webpack chunk cache logic
================================================
FILE: .changeset/twelve-donkeys-help.md
================================================
---
"@qiankunjs/sandbox": patch
---
fix: should patch the container head/body element immediately rather than patch its functions with proxy
================================================
FILE: .changeset/warm-chefs-chew.md
================================================
---
"qiankun": patch
---
✨ set data-name on micro app container
================================================
FILE: .changeset/wicked-icons-type.md
================================================
---
"@qiankunjs/loader": patch
"qiankun": patch
"@qiankunjs/sandbox": patch
"@qiankunjs/shared": patch
---
feat: extract NodeTransformer type to shared package
================================================
FILE: .changeset/wise-eagles-tease.md
================================================
---
"@qiankunjs/sandbox": patch
---
fix(sandbox): compatible with dynamically appending scripts to detached containers
================================================
FILE: .changeset/wise-ravens-prove.md
================================================
---
"@qiankunjs/loader": patch
"qiankun": patch
"@qiankunjs/sandbox": patch
"@qiankunjs/shared": patch
---
feat: support huge inline-script who might be split into multiple chunks during transfer
================================================
FILE: .dumirc.ts
================================================
import { defineConfig } from 'dumi';
export default defineConfig({
publicPath: process.env.NOW_DEPLOY ? '/' : '/qiankun/',
base: process.env.NOW_DEPLOY ? '/' : '/qiankun',
resolve: {
docDirs: ['docs'],
codeBlockMode: 'passive',
},
locales: [
{ id: 'en-US', name: 'English' },
{ id: 'zh-CN', name: '中文' },
],
themeConfig: {
name: 'qiankun',
logo: 'https://gw.alipayobjects.com/zos/bmw-prod/8a74c1d3-16f3-4719-be63-15e467a68a24/km0cv8vn_w500_h500.png',
nav: {
mode: 'append',
value: {
'zh-CN': [
{
title: '版本公告',
children: [
{ title: '发布日志', link: 'https://github.com/umijs/qiankun/releases' },
{ title: '升级指南', link: '/zh/cookbook#从-2x-版本升级到-3x-版本' },
{ title: '2.x 版本', link: 'https://v2.qiankun.umijs.org/zh/' },
],
},
],
'en-US': [
{
title: 'Version Notice',
children: [
{ title: 'Changelog', link: 'https://github.com/umijs/qiankun/releases' },
{ title: 'Upgrade Guide', link: '/cookbook#upgrade-from-2x-version-to-3x-version' },
{ title: '2.x Version', link: 'https://v2.qiankun.umijs.org/' },
],
},
],
},
},
socialLinks: {
github: 'https://github.com/umijs/qiankun',
},
},
metas: [
{
name: 'keywords',
content:
'microfrontend, micro frontend, micro frontends, micro-frontend, micro-frontends, microservice, javascript',
},
],
analytics: {
ga: 'UA-157295698-1',
baidu: '0f738d9b0ac90574c09183ea85bcfa2e',
},
favicons: ['https://gw.alipayobjects.com/mdn/rms_655822/afts/img/A*4sIUQpcos_gAAAAAAAAAAAAAARQnAQ'],
theme: {
'@c-primary': '#6451AB',
},
});
================================================
FILE: .editorconfig
================================================
# http://editorconfig.org
root = true
[*]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
max_line_length = 120
[*.md]
trim_trailing_whitespace = false
================================================
FILE: .eslintignore
================================================
examples
dist
writable-dom
template
# TODO not linting test files temporary
__tests__/
================================================
FILE: .eslintrc.cjs
================================================
// eslint config for js
const jsConfig = {
parserOptions: { ecmaVersion: 'latest', sourceType: 'module' },
extends: ['eslint:recommended', 'prettier'],
rules: {
'no-else-return': ['error', { allowElseIf: false }],
'object-shorthand': ['error', 'properties'],
'no-shadow': 'off',
},
};
// eslint config for cjs
const cjsConfig = {
parserOptions: { sourceType: 'script' },
env: { node: true },
};
// eslint config for ts
const tsConfig = {
extends: ['plugin:@typescript-eslint/recommended', 'plugin:@typescript-eslint/recommended-requiring-type-checking'],
parserOptions: {
tsconfigRootDir: __dirname,
project: ['./tsconfig.eslint.json', './packages/**/tsconfig.json'],
},
rules: {
'@typescript-eslint/no-unnecessary-condition': 'error',
'@typescript-eslint/no-explicit-any': ['error', { fixToUnknown: true }],
'@typescript-eslint/consistent-type-imports': [
'error',
{ prefer: 'type-imports', fixStyle: 'inline-type-imports' },
],
'@typescript-eslint/consistent-type-exports': ['error', { fixMixedExportsWithInlineTypeSpecifier: true }],
'@typescript-eslint/require-await': 'off',
'@typescript-eslint/array-type': ['error', { default: 'array-simple' }],
'@typescript-eslint/no-shadow': ['error', { ignoreFunctionTypeParameterNameValueShadow: true }],
'@typescript-eslint/no-misused-promises': [
'error',
{
checksVoidReturn: {
returns: false,
variables: false,
},
},
],
'@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_' }],
},
};
module.exports = {
root: true,
...jsConfig,
overrides: [
{
files: ['*.ts', '*.tsx'],
...tsConfig,
},
{
files: ['*.cjs', 'packages/webpack-plugin/**/*.js'],
...cjsConfig,
},
],
};
================================================
FILE: .fatherrc.cjs
================================================
module.exports = {
platform: 'browser',
esm: {},
cjs: {},
sourcemap: true,
extraBabelPlugins: [
[
'babel-plugin-import',
{
libraryName: 'lodash',
libraryDirectory: '',
camel2DashComponentName: false,
},
],
],
};
================================================
FILE: .github/CODE_OF_CONDUCT.md
================================================
# Contributor Covenant Code of Conduct
## Our Pledge
We as members, contributors, and leaders pledge to make participation in our community a harassment-free experience for everyone, regardless of age, body size, visible or invisible disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation.
We pledge to act and interact in ways that contribute to an open, welcoming, diverse, inclusive, and healthy community.
## Our Standards
Examples of behavior that contributes to a positive environment for our community include:
- Demonstrating empathy and kindness toward other people
- Being respectful of differing opinions, viewpoints, and experiences
- Giving and gracefully accepting constructive feedback
- Accepting responsibility and apologizing to those affected by our mistakes, and learning from the experience
- Focusing on what is best not just for us as individuals, but for the overall community
Examples of unacceptable behavior include:
- The use of sexualized language or imagery, and sexual attention or advances of any kind
- Trolling, insulting or derogatory comments, and personal or political attacks
- Public or private harassment
- Publishing others' private information, such as a physical or email address, without their explicit permission
- Other conduct which could reasonably be considered inappropriate in a professional setting
## Enforcement Responsibilities
Community leaders are responsible for clarifying and enforcing our standards of acceptable behavior and will take appropriate and fair corrective action in response to any behavior that they deem inappropriate, threatening, offensive, or harmful.
Community leaders have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, and will communicate reasons for moderation decisions when appropriate.
## Scope
This Code of Conduct applies within all community spaces, and also applies when an individual is officially representing the community in public spaces. Examples of representing our community include using an official e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the community leaders responsible for enforcement at [kuitos.lau@gmail.com](mailto:kuitos.lau@gmail.com) or by creating a confidential issue in our [GitHub repository](https://github.com/umijs/qiankun/issues). All complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the reporter of any incident.
## Enforcement Guidelines
Community leaders will follow these Community Impact Guidelines in determining the consequences for any action they deem in violation of this Code of Conduct:
### 1. Correction
**Community Impact**: Use of inappropriate language or other behavior deemed unprofessional or unwelcome in the community.
**Consequence**: A private, written warning from community leaders, providing clarity around the nature of the violation and an explanation of why the behavior was inappropriate. A public apology may be requested.
### 2. Warning
**Community Impact**: A violation through a single incident or series of actions.
**Consequence**: A warning with consequences for continued behavior. No interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, for a specified period of time. This includes avoiding interactions in community spaces as well as external channels like social media. Violating these terms may lead to a temporary or permanent ban.
### 3. Temporary Ban
**Community Impact**: A serious violation of community standards, including sustained inappropriate behavior.
**Consequence**: A temporary ban from any sort of interaction or public communication with the community for a specified period of time. No public or private interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, is allowed during this period. Violating these terms may lead to a permanent ban.
### 4. Permanent Ban
**Community Impact**: Demonstrating a pattern of violation of community standards, including sustained inappropriate behavior, harassment of an individual, or aggression toward or disparagement of classes of individuals.
**Consequence**: A permanent ban from any sort of public interaction within the community.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 2.0, available at https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
Community Impact Guidelines were inspired by [Mozilla's code of conduct enforcement ladder](https://github.com/mozilla/diversity).
[homepage]: https://www.contributor-covenant.org
For answers to common questions about this code of conduct, see the FAQ at https://www.contributor-covenant.org/faq. Translations are available at https://www.contributor-covenant.org/translations.
================================================
FILE: .github/CONTRIBUTING.md
================================================
# Contributing to qiankun
Thank you for your interest in contributing to qiankun! We welcome all types of contributions, including but not limited to:
- 🐛 Bug reports
- ✨ Feature suggestions
- 📝 Documentation improvements
- 🧪 Test cases
- 💻 Code contributions
## Getting Started
Before you begin contributing, please:
1. Read our [Code of Conduct](CODE_OF_CONDUCT.md)
2. Understand the [Developer Certificate of Origin (DCO)](https://developercertificate.org/) requirement - **all commits must be signed off**
3. Check existing [Issues](https://github.com/umijs/qiankun/issues) and [Pull Requests](https://github.com/umijs/qiankun/pulls)
4. Understand the project's technical architecture and code style
## Development Environment Setup
### Requirements
- Node.js >= 16.0.0
- pnpm@9.15.0 (we use pnpm as the package manager, exact version specified in package.json)
### Local Development
1. Fork this repository
2. Clone to local:
```bash
git clone https://github.com/YOUR_USERNAME/qiankun.git
cd qiankun
```
3. Install dependencies:
```bash
pnpm install
```
4. Run tests:
```bash
pnpm test
```
5. Build the project:
```bash
pnpm run build
```
### Development Scripts
- `pnpm run build` - Build all packages using father
- `pnpm test` - Run tests using vitest
- `pnpm run eslint` - Code style check with TypeScript ESLint rules
- `pnpm run prettier` - Format code with prettier
- `pnpm run prettier:check` - Check code formatting
- `pnpm run ci` - Complete CI pipeline (build + lint + format check)
- `pnpm run clean` - Clean node_modules and build artifacts
- `pnpm run start:example` - Start example applications (main + react15)
- `pnpm run docs:dev` - Start documentation development server
- `pnpm run docs:build` - Build documentation
- `pnpm run prepare` - Setup husky git hooks and dumi
## Code Contribution Workflow
### 1. Create an Issue
For major features or breaking changes, please create an Issue first to discuss:
- Clearly describe the problem or feature request
- Provide relevant context information
- For bugs, provide reproduction steps
### 2. Create a Branch
Create a feature branch based on the `next` branch (default development branch):
```bash
git checkout next
git pull origin next
git checkout -b feature/your-feature-name
# or
git checkout -b fix/bug-description
```
Note: The project uses `next` as the main development branch (as configured in changeset).
### 3. Code Development
#### TypeScript Code Standards
- **Strict Type Checking**:
- Enable TypeScript strict mode (already configured in tsconfig.json)
- Avoid using `any` type (ESLint rule enforces `fixToUnknown: true`)
- Use `unknown` instead of `any` when type is uncertain
- Enable all strict options: `strictNullChecks`, `strictFunctionTypes`, `noImplicitReturns`, etc.
- **Type Import/Export**:
- Use `import type` for type-only imports (enforced by ESLint)
- Use consistent type exports with inline type specifiers
- **Naming Conventions**:
- Variables and functions use `camelCase`
- Classes and interfaces use `PascalCase`
- Constants use `UPPER_SNAKE_CASE`
- File names use `kebab-case` or `PascalCase`
- **Comment Standards**:
- Use clear comments to explain complex logic
- Use JSDoc format for public APIs
- Provide usage examples for complex type definitions
- Add type annotations where TypeScript inference is insufficient
#### Code Style
- Follow the project's ESLint configuration
- Use 2-space indentation
- No trailing whitespace
- Keep one empty line at the end of files
#### Architecture Principles
- Follow SOLID principles
- Maintain high cohesion and low coupling
- Prefer composition over inheritance
- Ensure code testability
### 4. Write Tests
- Write corresponding test cases for new features using **vitest**
- Ensure existing tests are not broken
- Maintain reasonable test coverage
- Place test files in appropriate `__tests__` directories or alongside source files with `.test.ts` suffix
- Use vitest's global test APIs (no need to import `describe`, `it`, `expect`)
- Run tests with `pnpm test` or `pnpm -r run test` for all packages
### 5. Commit Code
#### Developer Certificate of Origin (DCO)
All commits **MUST** be signed off with the Developer Certificate of Origin (DCO). This is a legal requirement to ensure you have the right to contribute your code.
**How to sign off commits:**
1. **Manual sign-off for each commit:**
```bash
git commit -s -m "feat: add new feature"
```
2. **Configure automatic sign-off:**
```bash
git config user.name "Your Name"
git config user.email "your.email@example.com"
git config commit.gpgsign true # Optional: GPG signing
```
3. **Sign off existing commits retroactively:**
```bash
# For the last commit
git commit --amend --signoff
# For multiple commits (rebase and sign off)
git rebase --signoff HEAD~n # where n is the number of commits
```
**What is DCO?**
The DCO is a statement that you have the right to contribute the code and that you understand the licensing implications. Please read the full [DCO text](https://developercertificate.org/) for complete details. When you sign off a commit, you're confirming:
- The contribution was created by you, or you have permission to submit it
- You understand and agree that the contribution will be public
- You understand the contribution is licensed under the project's license
**Commit sign-off format:**
Each commit message must end with a "Signed-off-by" line:
```
feat(core): implement new feature
This commit adds support for custom lifecycles.
Signed-off-by: Your Name <your.email@example.com>
```
**⚠️ Important:** Pull requests with unsigned commits will be rejected. Make sure all your commits are properly signed off before submitting a PR.
#### Commit Message Format
We follow [Conventional Commits](https://www.conventionalcommits.org/) specification for commit messages.
**Format:**
```
<type>[optional scope]: <description>
[optional body]
[optional footer(s)]
Signed-off-by: Your Name <your.email@example.com>
```
**Commit Types:**
| Type | Description | Example |
| ---------- | ----------------------- | --------------------------------------------- |
| `feat` | New feature | `feat(sandbox): add new isolation mode` |
| `fix` | Bug fix | `fix(loader): resolve script loading issue` |
| `perf` | Performance improvement | `perf(core): optimize app loading speed` |
| `docs` | Documentation only | `docs: update API reference` |
| `style` | Code formatting | `style: fix ESLint warnings` |
| `refactor` | Code refactoring | `refactor(utils): simplify helper functions` |
| `test` | Adding tests | `test(core): add unit tests for loadMicroApp` |
| `chore` | Build/tooling changes | `chore: update dependencies` |
| `ci` | CI configuration | `ci: add workflow for releases` |
| `build` | Build system changes | `build: configure webpack` |
| `revert` | Revert previous commit | `revert: feat(api): add user auth` |
**Breaking Changes:**
For breaking changes, use one of these approaches:
1. Add `!` after type: `feat!: redesign loadMicroApp API`
2. Add `BREAKING CHANGE:` in footer:
```
feat(api): add new authentication method
BREAKING CHANGE: The old auth method is no longer supported.
Migration guide: replace loadMicroApp() with registerMicroApps()
```
**Scope Guidelines:**
- `core`: Core qiankun functionality
- `sandbox`: Sandbox isolation
- `loader`: Resource loading
- `utils`: Utility functions
- `types`: TypeScript type definitions
- `docs`: Documentation
- `test`: Testing related
- `ci`: CI/CD related
- `build`: Build system related
### 6. Create Pull Request
1. Push your branch to your fork:
```bash
git push origin feature/your-feature-name
```
2. Create a Pull Request on GitHub
3. PR title and description should be clear:
- Title should briefly describe the changes
- Description should detail:
- Motivation and purpose of changes
- Main changes made
- Testing status
- Any breaking changes
- Related issue numbers
4. Ensure all checks pass:
- **DCO sign-off check**: All commits must be signed off
- ESLint code style checks with TypeScript rules
- TypeScript strict type checks (no `any` types, strict null checks)
- All vitest tests pass
- Test coverage meets requirements
- Prettier formatting checks
- Build passes with father bundler
## Documentation Contributions
Documentation improvements are equally important:
- Fix errors or outdated information in documentation
- Improve clarity of existing documentation
- Add examples and use cases
- Translate documentation to other languages
## Bug Reports
When submitting bug reports, please include:
- **Clear Title**: Briefly describe the issue
- **Environment Information**:
- Node.js version (>= 16.0.0)
- pnpm version (should be 9.15.0)
- qiankun version
- Browser version
- Operating system
- Framework versions (React, Vue, Angular, etc.)
- Build tool versions (webpack, vite, etc.)
- Related dependency versions
- **Reproduction Steps**: Detailed step-by-step instructions
- **Expected Behavior**: Describe what should happen
- **Actual Behavior**: Describe what actually happened
- **Minimal Example**: Provide minimal code that reproduces the issue
- **Relevant Logs**: Error messages, stack traces, etc.
## Feature Requests
When submitting feature requests, please:
- Clearly describe the needed functionality
- Explain why this feature is needed
- Provide use cases and examples
- Consider alternative solutions
- Discuss impact on existing APIs
## Release Process
This project uses [Changesets](https://github.com/changesets/changesets) for version management and publishing:
### For Maintainers
1. **Creating a changeset**: After merging PR, create a changeset:
```bash
npx changeset
```
2. **Release process**:
```bash
# Alpha release (for testing)
pnpm run prerelease:alpha # Enter pre-release mode and create changeset
pnpm run release:alpha # Build and publish alpha version
# Production release
npx changeset version # Update package versions
pnpm run build # Build all packages
pnpm run ci:publish # Publish to npm
```
### Build System
- **Build Tool**: [father](https://github.com/umijs/father) - A library build tool
- **Monorepo**: pnpm workspaces with packages in `packages/` directory
- **Documentation**: [dumi](https://d.umijs.org/) for documentation site
- **Testing**: [vitest](https://vitest.dev/) for unit testing
- **Code Quality**: ESLint + Prettier + TypeScript strict mode
## Getting Help
If you have any questions, you can get help through:
- Create a [GitHub Issue](https://github.com/umijs/qiankun/issues)
- Check existing [documentation](https://qiankun.umijs.org/)
- Join our community discussions
## Acknowledgments
Thanks to all developers who contribute to the qiankun project! Your contributions make this project better.
---
Thank you again for your contribution! 🎉
================================================
FILE: .github/ISSUE_TEMPLATE/bug_report.md
================================================
---
name: 'Bug report'
about: 'Report a bug to help us improve'
title: ''
labels: ''
assignees: ''
---
## What happens?
A clear and concise description of what the bug is.
## Mini Showcase Repository(REQUIRED)
> Provide a mini GitHub repository which can reproduce the issue.
<!-- https://github.com/YOUR_REPOSITORY_URL -->
## How To Reproduce
**Steps to reproduce the behavior:** 1. 2.
**Expected behavior** 1. 2.
## Context
- **qiankun Version**:
- **Platform Version**:
- **Browser Version**:
================================================
FILE: .github/ISSUE_TEMPLATE/bug_report_cn.md
================================================
---
name: '缺陷问题反馈'
about: '反馈问题以帮助我们改进'
title: '[Bug]请遵循下文模板提交问题,否则您的问题会被关闭'
labels: ''
assignees: ''
---
# 提问之前强烈建立您能先阅读一下[《如何正确的提出一个 Issue》](https://github.com/umijs/qiankun/issues/1115)
<!--
感谢您向我们反馈问题,为了高效的解决问题,我们期望你能提供以下信息:
-->
## What happens?
<!-- 清晰的描述下遇到的问题。-->
## 最小可复现仓库
为节约大家的时间,无复现步骤的 ISSUE 会被关闭,提供之后再 REOPEN
<!-- https://github.com/YOUR_REPOSITORY_URL -->
## 复现步骤,错误日志以及相关配置
<!-- 请提供复现步骤,错误日志以及相关配置 -->
<!-- 可以尝试不要锁版本,重新安装依赖试试先 -->
## 相关环境信息
- **qiankun 版本**
- **浏览器版本**:
- **操作系统**:
================================================
FILE: .github/ISSUE_TEMPLATE/feature_request.md
================================================
---
name: 'Feature request'
about: 'Suggest an idea for this project'
title: '[Feature Request] say something'
labels: ''
assignees: ''
---
## Background
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
## Proposal
Describe the solution you'd like, better to provide some pseudo code.
## Additional context
Add any other context or screenshots about the feature request here.
================================================
FILE: .github/ISSUE_TEMPLATE/rfc_cn.md
================================================
---
name: 'RFC Proposals'
about: 'Provide a solution for this project'
title: '[RFC] say something'
labels: 'type: proposals'
assignees: ''
---
## 背景
> 描述你希望解决的问题的现状,附上相关的 issue 地址
## 思路
> 描述大概的解决思路,可以包含 API 设计和伪代码等
## 跟进
- [ ] some task
- [ ] PR URL
================================================
FILE: .github/PULL_REQUEST_TEMPLATE.md
================================================
<!--
Thank you for your pull request. Please review below requirements.
Bug fixes and new features should include tests.
Contributors guide: https://github.com/umijs/qiankun/blob/master/CONTRIBUTING.md
感谢您贡献代码。请确认下列 checklist 的完成情况。
Bug 修复和新功能必须包含测试。
Contributors guide: https://github.com/umijs/qiankun/blob/master/CONTRIBUTING.md
-->
##### Checklist
<!-- Remove items that do not apply. For completed items, change [ ] to [x]. -->
- [ ] `npm test` passes
- [ ] tests are included
- [ ] documentation is changed or added
- [ ] commit message follows commit guidelines
##### Description of change
<!-- Provide a description of the change below this comment. -->
- any feature?
- close https://github.com/umijs/qiankun/ISSUE_URL
================================================
FILE: .github/workflows/announcement-notify.yml
================================================
name: Annoucement Notify
on:
discussion:
types: [created]
jobs:
notify:
runs-on: ubuntu-latest
steps:
- name: Send DingGroup1 Anouncement Notify
uses: zcong1993/actions-ding@master
if: github.event.discussion.category.name == 'Announcements'
with:
dingToken: ${{ secrets.DING_GROUP_1_TOKEN }}
secret: ${{ secrets.DING_GROUP_1_SIGN }}
body: |
{
"msgtype": "markdown",
"markdown": {
"title": "Qiankun News",
"text": "# 新闻播报📢 [${{github.event.discussion.title}}](${{github.event.discussion.html_url}}) \n${{github.event.discussion.body}}",
}
}
- name: Send DingGroup2 Anouncement Notify
uses: zcong1993/actions-ding@master
if: github.event.discussion.category.name == 'Announcements'
with:
dingToken: ${{ secrets.DING_GROUP_2_TOKEN }}
secret: ${{ secrets.DING_GROUP_2_SIGN }}
body: |
{
"msgtype": "markdown",
"markdown": {
"title": "Qiankun News",
"text": "# 新闻播报📢 [${{github.event.discussion.title}}](${{github.event.discussion.html_url}}) \n${{github.event.discussion.body}}",
}
}
- name: Send DingGroup3 Anouncement Notify
uses: zcong1993/actions-ding@master
if: github.event.discussion.category.name == 'Announcements'
with:
dingToken: ${{ secrets.DING_GROUP_3_TOKEN }}
secret: ${{ secrets.DING_GROUP_3_SIGN }}
body: |
{
"msgtype": "markdown",
"markdown": {
"title": "Qiankun News",
"text": "# 新闻播报📢 [${{github.event.discussion.title}}](${{github.event.discussion.html_url}}) \n${{github.event.discussion.body}}",
}
}
- name: Send DingGroup4 Anouncement Notify
uses: zcong1993/actions-ding@master
if: github.event.discussion.category.name == 'Announcements'
with:
dingToken: ${{ secrets.DING_GROUP_4_TOKEN }}
secret: ${{ secrets.DING_GROUP_4_SIGN }}
body: |
{
"msgtype": "markdown",
"markdown": {
"title": "Qiankun News",
"text": "# 新闻播报📢 [${{github.event.discussion.title}}](${{github.event.discussion.html_url}}) \n${{github.event.discussion.body}}",
}
}
- name: Send DingGroup5 Anouncement Notify
uses: zcong1993/actions-ding@master
if: github.event.discussion.category.name == 'Announcements'
with:
dingToken: ${{ secrets.DING_GROUP_5_TOKEN }}
secret: ${{ secrets.DING_GROUP_5_SIGN }}
body: |
{
"msgtype": "markdown",
"markdown": {
"title": "Qiankun News",
"text": "# 新闻播报📢 [${{github.event.discussion.title}}](${{github.event.discussion.html_url}}) \n${{github.event.discussion.body}}",
}
}
- name: Send DingGroup6 Anouncement Notify
uses: zcong1993/actions-ding@master
if: github.event.discussion.category.name == 'Announcements'
with:
dingToken: ${{ secrets.DING_GROUP_6_TOKEN }}
secret: ${{ secrets.DING_GROUP_6_SIGN }}
body: |
{
"msgtype": "markdown",
"markdown": {
"title": "Qiankun News",
"text": "# 新闻播报📢 [${{github.event.discussion.title}}](${{github.event.discussion.html_url}}) \n${{github.event.discussion.body}}",
}
}
- name: Send DingGroup7 Anouncement Notify
uses: zcong1993/actions-ding@master
if: github.event.discussion.category.name == 'Announcements'
with:
dingToken: ${{ secrets.DING_GROUP_7_TOKEN }}
secret: ${{ secrets.DING_GROUP_7_SIGN }}
body: |
{
"msgtype": "markdown",
"markdown": {
"title": "Qiankun News",
"text": "# 新闻播报📢 [${{github.event.discussion.title}}](${{github.event.discussion.html_url}}) \n${{github.event.discussion.body}}",
}
}
================================================
FILE: .github/workflows/changeset-prerelease.yml
================================================
name: Changesets
on:
push:
branches:
- next
permissions:
id-token: write
contents: write
pull-requests: write
jobs:
changelog:
timeout-minutes: 15
runs-on: ubuntu-latest
environment: changeset-release
steps:
- uses: actions/checkout@v4
- name: Setup PNPM
uses: pnpm/action-setup@v2
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: 24
cache: "pnpm"
registry-url: "https://registry.npmjs.org"
- name: Install dependencies
run: pnpm install
- name: Build Packages
run: pnpm run build
- name: Create Release Pull Request or Publish
id: changesets
uses: changesets/action@v1
with:
commit: "chore: update versions"
title: "chore: update versions"
publish: pnpm ci:publish
createGithubReleases: false
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NPM_CONFIG_PROVENANCE: true
- name: Create Unified GitHub Release
if: steps.changesets.outputs.published == 'true'
run: |
VERSION=$(jq -r '.version' packages/qiankun/package.json)
TAG="v${VERSION}"
node scripts/generate-release-notes.mjs '${{ steps.changesets.outputs.publishedPackages }}' > /tmp/release-notes.md
gh release create "${TAG}" \
--title "${TAG}" \
--notes-file /tmp/release-notes.md \
--prerelease
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
================================================
FILE: .github/workflows/ci.yml
================================================
name: CI
on:
pull_request:
push:
branches:
- master
- next
- 1.x
jobs:
build-check-and-lint:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [lts/*, latest]
steps:
- uses: actions/checkout@v4
- name: Install pnpm
uses: pnpm/action-setup@v2
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
cache: "pnpm"
- run: corepack enable # https://nodejs.org/api/corepack.html
- run: pnpm install
- name: TS Build Check
run: pnpm run build
- name: Run eslint
run: pnpm run eslint
- name: Run prettier
run: pnpm run prettier:check
- name: Doc Build check
run: pnpm run docs:build
unit-test:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [lts/*, latest]
steps:
- uses: actions/checkout@v4
- name: Install pnpm
uses: pnpm/action-setup@v2
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
cache: "pnpm"
- run: corepack enable # https://nodejs.org/api/corepack.html
- run: pnpm install
- name: Run unit test
run: pnpm run test
================================================
FILE: .github/workflows/emoji-helper.yml
================================================
name: Emoji Helper
on:
release:
types: [published]
jobs:
emoji:
runs-on: ubuntu-latest
steps:
- uses: actions-cool/emoji-helper@v1.0.0
with:
type: "release"
emoji: "+1, laugh, heart, hooray, rocket, eyes"
================================================
FILE: .github/workflows/github-pages.yml
================================================
name: Qiankun Github Pages Deploy
on:
push:
branches:
- master
jobs:
deploy-gh-pages:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: "lts/*"
check-latest: true
registry-url: "https://registry.npmjs.org"
cache: "pnpm"
- name: Install dependencies
run: |
corepack enable
pnpm install --frozen-lockfile
- name: Build docs
run: pnpm run docs:build
- name: Deploy
uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./dist
================================================
FILE: .github/workflows/issue-close-inactive.yml
================================================
name: Issue Close Inactive
on:
schedule:
- cron: "0 0 * * *"
jobs:
close-issues:
runs-on: ubuntu-latest
steps:
- name: close inactive issue without reprodction
uses: actions-cool/issues-helper@v2.2.1
with:
actions: "close-issues"
labels: "Need Reproduction"
inactive-day: 30
body: |
Since the issue was labeled with `Need Reproduction`, but no response in 30 days. This issue will be close. If you have any questions, you can comment and reply.
由于该 issue 被标记为需要可复现步骤,却 30 天未收到回应。现关闭 issue,若有任何问题,可评论回复。
- name: close inactive issue not use template
uses: actions-cool/issues-helper@v2.2.1
with:
actions: "close-issues"
labels: "pls use issue template"
inactive-day: 30
body: |
Since the issue was labeled with `pls use issue template`, but no response in 30 days. This issue will be close. If you have any questions, you can comment and reply.
由于该 issue 被标记为需要使用模板,却 30 天未收到回应。现关闭 issue,若有任何问题,可评论回复。
- name: close inactive issue out of scope
uses: actions-cool/issues-helper@v2.2.1
with:
actions: "close-issues"
labels: "out-of-scope"
inactive-day: 30
body: |
Since the issue was labeled with `out-of-scope`, but no response in 30 days. This issue will be close. If you have any questions, you can comment and reply.
由于该 issue 被标记为与本项目无关,却 30 天未收到回应。现关闭 issue,若有任何问题,可评论回复。
- name: close inactive issue
uses: actions-cool/issues-helper@v2.2.1
with:
actions: "close-issues"
labels: "inactive"
inactive-day: 7
body: |
Since the issue was labeled with `inactive`, but no response in 7 days. This issue will be close. If you have any questions, you can comment and reply.
由于该 issue 被标记为不活跃,且 7 天未收到回应。现关闭 issue,若有任何问题,可评论回复。
================================================
FILE: .github/workflows/issue-reply.yml
================================================
name: Issue Reply
on:
issues:
types: [labeled]
jobs:
reply-helper:
runs-on: ubuntu-latest
steps:
- name: help wanted
if: github.event.label.name == 'pr welcome' || github.event.label.name == 'help wanted'
uses: actions-cool/issues-helper@v2.0.0
with:
actions: "create-comment"
issue-number: ${{ github.event.issue.number }}
body: |
Hello @${{ github.event.issue.user.login }}. We totally like your proposal/feedback, welcome to send us a Pull Request for it. Please be sure to fill in the default template in the Pull Request, provide changelog/documentation/test cases if needed and make sure CI passed, we will review it soon. We appreciate your effort in advance and looking forward to your contribution!
你好 @${{ github.event.issue.user.login }},我们完全同意你的提议/反馈,欢迎直接在此仓库创建一个 Pull Request 来解决这个问题。请务必填写 Pull Request 内的预设模板,提供改动所需相应的 changelog、测试用例、文档等,并确保 CI 通过,我们会尽快进行 Review,提前感谢和期待您的贡献。
- name: pls use issue template
if: github.event.label.name == 'pls use issue template'
uses: actions-cool/issues-helper@v2.0.0
with:
actions: "create-comment, close-issue"
issue-number: ${{ github.event.issue.number }}
body: |
Hello @${{ github.event.issue.user.login }}. To save both time, please use the issue template to report. This issue will be closed.
你好 @${{ github.event.issue.user.login }},为节约大家的时间,请使用 issue 模板反馈问题。该 issue 将要被关闭。
- name: Need Reproduction
if: github.event.label.name == 'Need Reproduction'
uses: actions-cool/issues-helper@v2.0.0
with:
actions: "create-comment"
issue-number: ${{ github.event.issue.number }}
body: |
Hello @${{ github.event.issue.user.login }}. In order to facilitate location and troubleshooting, we need you to provide a realistic example. Please forking these link [codesandbox](https://codesandbox.io/) or clone [qiankun examples](https://github.com/umijs/qiankun/tree/master/examples) to your GitHub repository.
你好 @${{ github.event.issue.user.login }}, 为了方便定位和排查问题,我们需要你提供一个重现实例,请提供一个尽可能精简的链接 [codesandbox](https://codesandbox.io/) 或直接 clone [qiankun examples](https://github.com/umijs/qiankun/tree/master/examples),并上传到你的 GitHub 仓库。

================================================
FILE: .github/workflows/publish-1.x.yml
================================================
name: Publish 1.x Version
on:
push:
tags:
- v1.*
jobs:
publish:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: "lts/*"
check-latest: true
registry-url: "https://registry.npmjs.org"
cache: "pnpm"
- run: corepack enable
- run: pnpm install --frozen-lockfile
- run: pnpm publish --tag qiankun1
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_AUTH_TOKEN }}
================================================
FILE: .github/workflows/publish-latest.yml
================================================
name: Publish Latest Version
on:
push:
tags:
- v2.*
jobs:
publish:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: "lts/*"
check-latest: true
registry-url: "https://registry.npmjs.org"
cache: "pnpm"
- run: corepack enable
- run: pnpm install --frozen-lockfile
- run: pnpm publish --tag latest
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_AUTH_TOKEN }}
================================================
FILE: .github/workflows/release-notify.yml
================================================
name: Release Notify
on:
release:
types: [published]
jobs:
notify:
runs-on: ubuntu-latest
steps:
- name: Send DingGroup1 Notify
uses: zcong1993/actions-ding@master
with:
dingToken: ${{ secrets.DING_GROUP_1_TOKEN }}
secret: ${{ secrets.DING_GROUP_1_SIGN }}
body: |
{
"msgtype": "markdown",
"markdown": {
"title": "qiankun ${{github.event.release.tag_name}} 发布公告",
"text": "# qiankun [${{github.event.release.tag_name}}](${{github.event.release.html_url}}) 发布公告\n${{github.event.release.body}}",
}
}
- name: Send DingGroup2 Notify
uses: zcong1993/actions-ding@master
with:
dingToken: ${{ secrets.DING_GROUP_2_TOKEN }}
secret: ${{ secrets.DING_GROUP_2_SIGN }}
body: |
{
"msgtype": "markdown",
"markdown": {
"title": "qiankun ${{github.event.release.tag_name}} 发布公告",
"text": "# qiankun [${{github.event.release.tag_name}}](${{github.event.release.html_url}}) 发布公告\n${{github.event.release.body}}",
}
}
- name: Send DingGroup3 Notify
uses: zcong1993/actions-ding@master
with:
dingToken: ${{ secrets.DING_GROUP_3_TOKEN }}
secret: ${{ secrets.DING_GROUP_3_SIGN }}
body: |
{
"msgtype": "markdown",
"markdown": {
"title": "qiankun ${{github.event.release.tag_name}} 发布公告",
"text": "# qiankun [${{github.event.release.tag_name}}](${{github.event.release.html_url}}) 发布公告\n${{github.event.release.body}}",
}
}
- name: Send DingGroup4 Notify
uses: zcong1993/actions-ding@master
with:
dingToken: ${{ secrets.DING_GROUP_4_TOKEN }}
secret: ${{ secrets.DING_GROUP_4_SIGN }}
body: |
{
"msgtype": "markdown",
"markdown": {
"title": "qiankun ${{github.event.release.tag_name}} 发布公告",
"text": "# qiankun [${{github.event.release.tag_name}}](${{github.event.release.html_url}}) 发布公告\n${{github.event.release.body}}",
}
}
- name: Send DingGroup5 Notify
uses: zcong1993/actions-ding@master
with:
dingToken: ${{ secrets.DING_GROUP_5_TOKEN }}
secret: ${{ secrets.DING_GROUP_5_SIGN }}
body: |
{
"msgtype": "markdown",
"markdown": {
"title": "qiankun ${{github.event.release.tag_name}} 发布公告",
"text": "# qiankun [${{github.event.release.tag_name}}](${{github.event.release.html_url}}) 发布公告\n${{github.event.release.body}}",
}
}
- name: Send DingGroup6 Notify
uses: zcong1993/actions-ding@master
with:
dingToken: ${{ secrets.DING_GROUP_6_TOKEN }}
secret: ${{ secrets.DING_GROUP_6_SIGN }}
body: |
{
"msgtype": "markdown",
"markdown": {
"title": "qiankun ${{github.event.release.tag_name}} 发布公告",
"text": "# qiankun [${{github.event.release.tag_name}}](${{github.event.release.html_url}}) 发布公告\n${{github.event.release.body}}",
}
}
- name: Send DingGroup7 Notify
uses: zcong1993/actions-ding@master
with:
dingToken: ${{ secrets.DING_GROUP_7_TOKEN }}
secret: ${{ secrets.DING_GROUP_7_SIGN }}
body: |
{
"msgtype": "markdown",
"markdown": {
"title": "qiankun ${{github.event.release.tag_name}} 发布公告",
"text": "# qiankun [${{github.event.release.tag_name}}](${{github.event.release.html_url}}) 发布公告\n${{github.event.release.body}}",
}
}
- name: Send DingGroupInc Notify
uses: zcong1993/actions-ding@master
with:
dingToken: ${{ secrets.DING_GROUP_INC_TOKEN }}
secret: ${{ secrets.DING_GROUP_INC_SIGN }}
body: |
{
"msgtype": "markdown",
"markdown": {
"title": "qiankun ${{github.event.release.tag_name}} 发布公告",
"text": "# qiankun [${{github.event.release.tag_name}}](${{github.event.release.html_url}}) 发布公告\n${{github.event.release.body}}",
}
}
================================================
FILE: .gitignore
================================================
pids
logs
node_modules
npm-debug.log
coverage/
run
dist
.DS_Store
.nyc_output
config.local.js
.umi
.umi-production
.idea/
.vscode/
.cache
yarn.lock
es
lib
package-lock.json
.eslintcache
.history
.worktrees
.now
.pnpm-store
*.log
packages/qiankun/src/version.ts
packages/sandbox/src/core/sandbox/globals.ts
.dumi/tmp
.dumi/tmp-test
.dumi/tmp-production
================================================
FILE: .husky/commit-msg
================================================
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
npx --no-install commitlint --edit $1
================================================
FILE: .husky/pre-commit
================================================
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
npx lint-staged
================================================
FILE: .husky/pre-push
================================================
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
#pnpm run test
================================================
FILE: .prettierignore
================================================
/test/fixtures
**/*.gif
/dist
/docs
/es
/lib
/coverage
.cache
examples
.umi
.dumi
.umi-production
.changeset/*
pnpm-lock.yaml
packages/sandbox/src/core/globals.ts
packages/create-qiankun/template
# changeset 会修改这个文件,导致 prettier:check 失败
packages/**/*/package.json
================================================
FILE: .prettierrc
================================================
{
"singleQuote": true,
"trailingComma": "all",
"proseWrap": "never",
"overrides": [
{
"files": ["*.json", ".prettierrc"],
"options": { "parser": "json" }
},
{
"files": ["*.{yaml,yml}"],
"options": { "singleQuote": false }
}
]
}
================================================
FILE: AGENTS.md
================================================
# QIANKUN PROJECT KNOWLEDGE BASE
**Generated:** 2026-01-10 **Commit:** 058166b6 **Branch:** next
## OVERVIEW
Qiankun is a micro-frontend framework built on single-spa, providing HTML entry, JS sandbox, and style isolation. Monorepo managed by pnpm with `father` build tool.
## STRUCTURE
```
qiankun/
├── packages/
│ ├── qiankun/ # Main facade - re-exports from loader/sandbox/shared
│ ├── sandbox/ # JS isolation via Proxy membrane + Compartment (SEE packages/sandbox/AGENTS.md)
│ ├── loader/ # Streaming HTML entry loader (SEE packages/loader/AGENTS.md)
│ ├── shared/ # fetch-utils, asset transpilers, module-resolver (SEE packages/shared/AGENTS.md)
│ ├── ui-bindings/ # React/Vue <MicroApp> components
│ ├── bundler-plugin/ # Entry point configuration plugin
│ └── create-qiankun/ # CLI scaffolding tool
├── examples/ # Integration examples (NOT in workspace currently)
└── docs/ # VitePress documentation
```
## WHERE TO LOOK
| Task | Location | Notes |
| --- | --- | --- |
| Core APIs (registerMicroApps, loadMicroApp) | `packages/qiankun/src/apis/` | Thin wrappers around loader/sandbox |
| App loading lifecycle | `packages/qiankun/src/core/loadApp.ts` | Orchestrates sandbox+loader+hooks |
| JS sandbox implementation | `packages/sandbox/src/core/` | Membrane, Compartment, StandardSandbox |
| HTML streaming loader | `packages/loader/src/index.ts` | Uses writable-dom for streaming |
| Script/link transpilation | `packages/shared/src/assets-transpilers/` | Blob URL sandboxing |
| Fetch enhancements | `packages/shared/src/fetch-utils/` | Cache, retry, error handling |
| Dependency sharing | `packages/shared/src/module-resolver/` | Semver-based matching |
| React/Vue bindings | `packages/ui-bindings/{react,vue}/` | `<MicroApp>` component |
## CODE MAP
### Package Dependencies (internal)
```
qiankun (facade)
├── @qiankunjs/loader
│ ├── @qiankunjs/sandbox
│ └── @qiankunjs/shared
├── @qiankunjs/sandbox
│ └── @qiankunjs/shared
└── @qiankunjs/shared (base utilities)
```
### Key Entry Points
| Package | Entry | Primary Exports |
| ------------------ | -------------- | --------------------------------------------------- |
| qiankun | `src/index.ts` | `registerMicroApps`, `start`, `loadMicroApp` |
| @qiankunjs/sandbox | `src/index.ts` | `createSandboxContainer`, `StandardSandbox` |
| @qiankunjs/loader | `src/index.ts` | `loadEntry` |
| @qiankunjs/shared | `src/index.ts` | `transpileScript`, `makeFetchCacheable`, `Deferred` |
## CONVENTIONS
### TypeScript (STRICT - enforced by eslint)
- `@typescript-eslint/no-explicit-any`: ERROR - use `unknown` instead
- `@typescript-eslint/consistent-type-imports`: inline-type-imports required
- `@typescript-eslint/no-unnecessary-condition`: ERROR
- Path aliases: `@qiankunjs/*` → `packages/*/src`
### Code Style
- No `as any`, `@ts-ignore`, `@ts-expect-error`
- Unused vars: prefix with `_` (e.g., `_unused`)
- Type exports: use `export type { X }` inline syntax
### Build
- Tool: `father` (UmiJS ecosystem)
- Output: dual ESM + CJS in `dist/`
- No `exports` field in package.json (uses `main`/`module`/`types`)
## ANTI-PATTERNS (THIS PROJECT)
- **NEVER** add more than 1 `entry` attribute script per HTML entry
- **NEVER** use `!important` in CSS unless absolutely necessary (breaks isolation)
- **ALWAYS** unmount micro-apps when finished (`loadMicroApp` returns unmount handle)
- **AVOID** global variables in micro-apps - sandbox tracks `latestSetProp` for exports
### Technical Debt (from codebase comments)
- `FIXME` in `loadApp.ts`: async execution order coordination
- `FIXME` in sandbox: System.js scope escape via indirect eval
- `TODO`: Snapshot sandbox and GC not yet implemented
## COMMANDS
```bash
pnpm install # Install all workspace deps
pnpm run build # Build all packages (father build)
pnpm run test # Run vitest across workspace
pnpm run eslint # Lint packages/
pnpm run ci # Full CI: build + eslint + prettier:check
# Development
pnpm run start:example # Build + run example apps
pnpm run docs:dev # VitePress dev server
# Release (changesets)
pnpm run prerelease:alpha # Enter alpha, version bump
pnpm run release:alpha # Build, publish, exit alpha
```
## NOTES
- **v3.0 Active Development**: Check roadmap at github.com/umijs/qiankun/discussions/1378
- **Streaming Architecture**: v3 uses `writable-dom` for incremental HTML parsing
- **Head Virtualization**: `<head>` → `<qiankun-head>` for isolation
- **Blob URL Execution**: Scripts wrapped and executed via `URL.createObjectURL`
- **Test Environment**: Vitest + happy-dom; edge-runtime for fetch tests
================================================
FILE: LICENSE
================================================
MIT License
Copyright (c) 2019 Kuitos
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:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
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
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.
================================================
FILE: README.md
================================================
<p align="center">
<a href="https://qiankun.umijs.org" target="_blank" rel="noopener noreferrer">
<img width="180" src="./docs/logo.png" alt="qiankun logo">
</a>
</p>
<p align="center">
<a href="https://www.npmjs.com/package/qiankun"><img src="https://img.shields.io/npm/v/qiankun/next.svg?style=flat-square" alt="npm version" /></a>
<a href="https://codecov.io/gh/umijs/qiankun"><img src="https://img.shields.io/codecov/c/github/umijs/qiankun.svg?style=flat-square" alt="coverage" /></a>
<a href="https://www.npmjs.com/package/qiankun"><img src="https://img.shields.io/npm/dm/qiankun.svg?style=flat-square" alt="npm downloads" /></a>
<a href="https://github.com/umijs/qiankun/actions/workflows/ci.yml"><img src="https://img.shields.io/github/actions/workflow/status/umijs/qiankun/ci.yml?branch=master&style=flat-square" alt="build status" /></a>
<a href="https://github.com/umijs/dumi"><img src="https://img.shields.io/badge/docs%20by-dumi-blue" alt="dumi" /></a>
</p>
# qiankun(乾坤)
> [!WARNING] 🚧 qiankun 3.0 is currently under active development. Check out the [Roadmap](https://github.com/umijs/qiankun/discussions/1378) for more details.
> In Chinese, `qian(乾)` means heaven and `kun(坤)` earth. `qiankun` is the universe.
Qiankun enables you and your teams to build next-generation and enterprise-ready web applications leveraging [Micro Frontends](https://micro-frontends.org/). It is inspired by and based on [single-spa](https://github.com/single-spa/single-spa).
## 🤔 Motivation
A quick recap about the concept of `Micro Frontends`:
> Techniques, strategies and recipes for building a **modern web app** with **multiple teams** using **different JavaScript frameworks**. — [Micro Frontends](https://micro-frontends.org/)
Qiankun was birthed internally in our group during the time web app development by distributed teams had turned to complete chaos. We faced every problem micro frontend was conceived to solve, so naturally, it became part of our solution.
The path was never easy, we stepped on every challenge there could possibly be. Just to name a few:
- In what form do micro-apps publish static resources?
- How does the framework integrate individual micro-apps?
- How to ensure that sub-applications are isolated from one another (development independence and deployment independence) and runtime sandboxed?
- Performance issues? What about public dependencies?
- The list goes on long ...
After solving these common problems of micro frontends and lots of polishing and testing, we extracted the minimal viable framework of our solution, and named it `qiankun`, as it can contain and serve anything. Not long after, it became the cornerstone of hundreds of our web applications in production, and we decided to open-source it to save you the suffering.
**TLDR: Qiankun is probably the most complete micro-frontend solution you ever met🧐.**
## :sparkles: Features
Qiankun inherits many benefits from [single-spa](https://github.com/single-spa/single-spa):
- 📦 **Micro-apps Independent Deployment**
- 🛴 **Lazy Load**
- 📱 **Technology Agnostic**
And on top of these, it offers:
- 💃 **Elegant API**
- 💪 **HTML Entry Access Mode**
- 🛡 **Style Isolation**
- 🧳 **JS Sandbox**
- ⚡ **Prefetch Assets**
- 🔌 **[Umi Plugin](https://github.com/umijs/plugins/tree/master/packages/plugin-qiankun) Integration**
## Packages
| Package | Version (click for changelogs) |
| --- | :-- |
| [qiankun](packages/qiankun) | [](packages/qiankun/CHANGELOG.md) |
| [@qiankunjs/loader](packages/loader) | [](packages/loader/CHANGELOG.md) |
| [@qiankunjs/sandbox](packages/sandbox) | [](packages/sandbox/CHANGELOG.md) |
| [@qiankunjs/shared](packages/shared) | [](packages/shared/CHANGELOG.md) |
| [@qiankunjs/react](packages/ui-bindings/react) | [](packages/ui-bindings/react/CHANGELOG.md) |
| [@qiankunjs/vue](packages/ui-bindings/vue) | [](packages/ui-bindings/vue/CHANGELOG.md) |
| [@qiankunjs/ui-shared](packages/ui-bindings/shared) | [](packages/ui-bindings/shared/CHANGELOG.md) |
| [@qiankunjs/bundler-plugin](packages/bundler-plugin) | [](packages/bundler-plugin/CHANGELOG.md) |
| [create-qiankun](packages/create-qiankun) | [](packages/create-qiankun/CHANGELOG.md) |
## 📦 Installation
```shell
$ yarn add qiankun # or npm i qiankun -S
```
## 📖 Documentation
You can find the Qiankun documentation [on the website](https://qiankun.umijs.org/)
Check out the [Getting Started](https://qiankun.umijs.org/guide/getting-started) page for a quick overview.
The documentation is divided into several sections:
- [Tutorial](https://qiankun.umijs.org/cookbook)
- [API Reference](https://qiankun.umijs.org/api)
- [FAQ](https://qiankun.umijs.org/faq)
- [Community](https://qiankun.umijs.org/#-community)
## 💿 Examples
Inside the `examples` folder, there is a sample Shell app and multiple mounted Micro FE apps. To get it running, first clone `qiankun`:
```shell
$ git clone https://github.com/umijs/qiankun.git
$ cd qiankun
```
Now install and run the example:
```shell
$ pnpm install
$ pnpm run examples:install
$ pnpm run examples:start
```
Visit `http://localhost:7099`.

## 🎯 Roadmap
See [Qiankun 3.0 Roadmap](https://github.com/umijs/qiankun/discussions/1378)
## 🤝 Contributing
[](https://deepwiki.com/umijs/qiankun)
See [contributing guide](./CONTRIBUTING.md).
## 👥 Contributors
Thanks to all the contributors!
<a href="https://github.com/umijs/qiankun/graphs/contributors">
<img src="https://opencollective.com/qiankun/contributors.svg?width=960&button=false" alt="contributors" />
</a>
## 🎁 Acknowledgements
- [single-spa](https://github.com/single-spa/single-spa) What an awesome meta-framework for micro-frontends!
- [writable-dom](https://github.com/marko-js/writable-dom/) Utility to stream HTML content into a live document.
## 📄 License
Qiankun is [MIT licensed](./LICENSE).
================================================
FILE: commitlint.config.js
================================================
module.exports = {
extends: ['@commitlint/config-conventional'],
rules: {
'type-enum': [
2,
'always',
['feat', 'fix', 'docs', 'style', 'refactor', 'perf', 'test', 'build', 'ci', 'chore', 'revert'],
],
'subject-case': [0, 'never'],
},
};
================================================
FILE: docs/.vitepress/config.mjs
================================================
import { defineConfig } from 'vitepress'
export default defineConfig({
title: 'qiankun',
description: 'Probably the most complete micro-frontends solution you ever met🧐',
// Default to English
lang: 'en-US',
head: [
['link', { rel: 'icon', href: '/logo.png' }],
['meta', { name: 'theme-color', content: '#646cff' }],
['meta', { property: 'og:title', content: 'qiankun' }],
['meta', { property: 'og:description', content: 'Probably the most complete micro-frontends solution you ever met🧐' }],
['meta', { property: 'og:image', content: '/logo.png' }]
],
locales: {
root: {
label: 'English',
lang: 'en',
title: 'qiankun',
description: 'Probably the most complete micro-frontends solution you ever met🧐',
themeConfig: {
nav: [
{ text: 'Guide', link: '/guide/' },
{ text: 'API', link: '/api/' },
{ text: 'Ecosystem', link: '/ecosystem/' },
{ text: 'Cookbook', link: '/cookbook/' },
{ text: 'FAQ', link: '/faq/' },
{
text: 'Links',
items: [
{ text: 'GitHub', link: 'https://github.com/umijs/qiankun' },
{ text: 'Changelog', link: 'https://github.com/umijs/qiankun/releases' },
{ text: 'Community', link: 'https://github.com/umijs/qiankun/discussions' },
]
}
],
sidebar: {
'/guide/': [
{
text: 'Introduction',
items: [
{ text: 'What is qiankun?', link: '/guide/' },
{ text: 'Quick Start', link: '/guide/quick-start' },
{ text: 'Tutorial', link: '/guide/tutorial' },
]
}
],
'/api/': [
{
text: 'Core APIs',
items: [
{ text: 'Overview', link: '/api/' },
{ text: 'registerMicroApps', link: '/api/register-micro-apps' },
{ text: 'loadMicroApp', link: '/api/load-micro-app' },
{ text: 'start', link: '/api/start' },
{ text: 'isRuntimeCompatible', link: '/api/is-runtime-compatible' },
]
},
{
text: 'Reference',
items: [
{ text: 'Lifecycles', link: '/api/lifecycles' },
{ text: 'Configuration', link: '/api/configuration' },
{ text: 'Types', link: '/api/types' },
]
}
],
'/ecosystem/': [
{
text: 'UI Bindings',
items: [
{ text: 'Overview', link: '/ecosystem/' },
{ text: 'React', link: '/ecosystem/react' },
{ text: 'Vue', link: '/ecosystem/vue' },
]
},
{
text: 'Tools',
items: [
{ text: 'Webpack Plugin', link: '/ecosystem/webpack-plugin' },
{ text: 'Create Qiankun', link: '/ecosystem/create-qiankun' },
]
}
],
'/cookbook/': [
{
text: 'Best Practices',
items: [
{ text: 'Overview', link: '/cookbook/' },
{ text: 'Style Isolation', link: '/cookbook/style-isolation' },
{ text: 'Performance', link: '/cookbook/performance' },
{ text: 'Error Handling', link: '/cookbook/error-handling' },
]
}
]
}
}
},
'zh-CN': {
label: '中文',
lang: 'zh-CN',
title: 'qiankun',
description: '可能是你见过最完善的微前端解决方案🧐',
themeConfig: {
nav: [
{ text: '指南', link: '/zh-CN/guide/' },
{ text: 'API', link: '/zh-CN/api/' },
{ text: '生态系统', link: '/zh-CN/ecosystem/' },
{ text: '最佳实践', link: '/zh-CN/cookbook/' },
{ text: '常见问题', link: '/zh-CN/faq/' },
{
text: '相关链接',
items: [
{ text: 'GitHub', link: 'https://github.com/umijs/qiankun' },
{ text: '更新日志', link: 'https://github.com/umijs/qiankun/releases' },
{ text: '社区讨论', link: 'https://github.com/umijs/qiankun/discussions' },
]
}
],
sidebar: {
'/zh-CN/guide/': [
{
text: '介绍',
items: [
{ text: '什么是 qiankun?', link: '/zh-CN/guide/' },
{ text: '快速开始', link: '/zh-CN/guide/quick-start' },
{ text: '详细教程', link: '/zh-CN/guide/tutorial' },
]
}
],
'/zh-CN/api/': [
{
text: '核心 API',
items: [
{ text: '概览', link: '/zh-CN/api/' },
{ text: 'registerMicroApps', link: '/zh-CN/api/register-micro-apps' },
{ text: 'loadMicroApp', link: '/zh-CN/api/load-micro-app' },
{ text: 'start', link: '/zh-CN/api/start' },
{ text: 'isRuntimeCompatible', link: '/zh-CN/api/is-runtime-compatible' },
]
}
],
'/zh-CN/ecosystem/': [
{
text: 'UI 绑定',
items: [
{ text: '概览', link: '/zh-CN/ecosystem/' },
{ text: 'React', link: '/zh-CN/ecosystem/react' },
{ text: 'Vue', link: '/zh-CN/ecosystem/vue' },
]
}
],
'/zh-CN/cookbook/': [
{
text: '最佳实践',
items: [
{ text: '概览', link: '/zh-CN/cookbook/' },
{ text: '常见问题', link: '/zh-CN/cookbook/error-handling' },
]
}
],
'/zh-CN/faq/': [
{
text: '常见问题',
items: [
{ text: 'FAQ', link: '/zh-CN/faq/' },
]
}
]
}
}
}
},
themeConfig: {
logo: '/logo.png',
socialLinks: [
{ icon: 'github', link: 'https://github.com/umijs/qiankun' }
],
search: {
provider: 'local'
},
editLink: {
pattern: 'https://github.com/umijs/qiankun/edit/next/docs/:path',
text: 'Edit this page on GitHub'
},
lastUpdated: {
text: 'Last updated',
formatOptions: {
dateStyle: 'short',
timeStyle: 'medium'
}
},
footer: {
message: 'Released under the MIT License.',
copyright: 'Copyright © 2019-present qiankun contributors'
}
},
markdown: {
lineNumbers: true,
theme: {
light: 'github-light',
dark: 'github-dark'
}
},
cleanUrls: true,
sitemap: {
hostname: 'https://qiankun.umijs.org'
},
ignoreDeadLinks: true
})
================================================
FILE: docs/.vitepress/theme/index.js
================================================
// .vitepress/theme/index.js
import DefaultTheme from 'vitepress/theme'
import { onMounted, nextTick } from 'vue'
export default {
extends: DefaultTheme,
enhanceApp({ app, router }) {
// 路由变化时重新渲染 Mermaid
if (typeof window !== 'undefined') {
router.onAfterRouteChanged = () => {
nextTick(() => {
renderMermaidCharts()
})
}
}
},
setup() {
onMounted(() => {
// 初始加载时渲染 Mermaid
setTimeout(() => {
renderMermaidCharts()
}, 100)
})
}
}
function renderMermaidCharts() {
if (typeof window === 'undefined' || !window.mermaid) {
return
}
try {
// 初始化 mermaid
window.mermaid.initialize({
startOnLoad: false,
theme: 'default'
})
// 查找所有 mermaid 代码块
const mermaidElements = document.querySelectorAll('pre code.language-mermaid')
mermaidElements.forEach((element, index) => {
// 如果已经渲染过,跳过
if (element.getAttribute('data-processed') === 'true') {
return
}
const code = element.textContent || element.innerText
const uniqueId = `mermaid-${Date.now()}-${index}`
// 创建容器
const container = document.createElement('div')
container.className = 'mermaid-container'
container.id = uniqueId
// 渲染图表
window.mermaid.render(uniqueId + '-svg', code).then(({ svg }) => {
container.innerHTML = svg
// 替换原来的代码块
const parent = element.closest('pre')
if (parent && parent.parentNode) {
parent.parentNode.replaceChild(container, parent)
}
}).catch(error => {
console.warn('Mermaid 渲染错误:', error)
})
// 标记为已处理
element.setAttribute('data-processed', 'true')
})
} catch (error) {
console.warn('Mermaid 初始化错误:', error)
}
}
================================================
FILE: docs/api/configuration.md
================================================
# Configuration
qiankun provides flexible configuration options to customize the behavior of micro-frontend applications. This document covers all available configuration options for different use cases.
## 📋 Configuration Types
### AppConfiguration
Configuration for individual micro applications used with `loadMicroApp`.
```typescript
type AppConfiguration = {
sandbox?: boolean;
globalContext?: WindowProxy;
fetch?: Function;
streamTransformer?: Function;
nodeTransformer?: Function;
};
```
### StartOpts
Configuration for starting the qiankun framework used with `start()`.
```typescript
interface StartOpts {
prefetch?: boolean | 'all' | string[] | ((apps: RegistrableApp[]) => { criticalAppNames: string[]; minorAppsName: string[] });
sandbox?: boolean | { strictStyleIsolation?: boolean; experimentalStyleIsolation?: boolean; };
singular?: boolean;
urlRerouteOnly?: boolean;
// ... other single-spa options
}
```
## ⚙️ App Configuration Options
### sandbox
**Type**: `boolean`
**Default**: `true`
**Description**: Enable sandbox isolation for the micro application.
#### Basic Usage
```typescript
// Enable sandbox (default)
loadMicroApp({
name: 'my-app',
entry: '//localhost:8080',
container: '#container',
}, {
sandbox: true
});
// Disable sandbox (not recommended)
loadMicroApp({
name: 'legacy-app',
entry: '//localhost:8080',
container: '#container',
}, {
sandbox: false
});
```
#### Why Use Sandbox?
```typescript
// With sandbox enabled, global variables are isolated
loadMicroApp({
name: 'app1',
entry: '//localhost:8001',
container: '#container1',
}, {
sandbox: true // app1 gets its own global scope
});
loadMicroApp({
name: 'app2',
entry: '//localhost:8002',
container: '#container2',
}, {
sandbox: true // app2 gets its own isolated global scope
});
```
### globalContext
**Type**: `WindowProxy`
**Default**: `window`
**Description**: Custom global context for the micro application.
```typescript
// Create a custom global context
const customGlobal = new Proxy(window, {
get(target, prop) {
// Custom logic for property access
if (prop === 'customAPI') {
return { version: '1.0' };
}
return target[prop];
}
});
loadMicroApp({
name: 'custom-app',
entry: '//localhost:8080',
container: '#container',
}, {
globalContext: customGlobal
});
```
### fetch
**Type**: `Function`
**Default**: `window.fetch`
**Description**: Custom fetch function for loading application resources.
#### Custom Headers
```typescript
const customFetch = async (url, options) => {
return fetch(url, {
...options,
headers: {
...options?.headers,
'Authorization': `Bearer ${getToken()}`,
'X-Custom-Header': 'custom-value'
}
});
};
loadMicroApp({
name: 'authenticated-app',
entry: '//localhost:8080',
container: '#container',
}, {
fetch: customFetch
});
```
#### Request Transformation
```typescript
const transformFetch = async (url, options) => {
// Transform URLs
const transformedUrl = url.replace('//localhost', '//production-domain');
// Add custom logic
console.log(`Fetching: ${transformedUrl}`);
const response = await fetch(transformedUrl, options);
// Transform response
if (!response.ok) {
throw new Error(`Failed to fetch ${transformedUrl}: ${response.status}`);
}
return response;
};
```
#### Caching Strategy
```typescript
const cache = new Map();
const cachingFetch = async (url, options) => {
const cacheKey = `${url}${JSON.stringify(options)}`;
if (cache.has(cacheKey)) {
console.log(`Cache hit for ${url}`);
return cache.get(cacheKey);
}
const response = await fetch(url, options);
cache.set(cacheKey, response.clone());
return response;
};
```
### streamTransformer
**Type**: `Function`
**Description**: Transform streaming HTML content during loading.
```typescript
const customStreamTransformer = (stream) => {
return stream.pipeThrough(new TransformStream({
transform(chunk, controller) {
// Transform HTML chunks
const transformedChunk = chunk
.replace(/old-api/g, 'new-api')
.replace(/deprecated-feature/g, 'updated-feature');
controller.enqueue(transformedChunk);
}
}));
};
loadMicroApp({
name: 'streaming-app',
entry: '//localhost:8080',
container: '#container',
}, {
streamTransformer: customStreamTransformer
});
```
### nodeTransformer
**Type**: `Function`
**Description**: Transform DOM nodes during application loading.
```typescript
const customNodeTransformer = (node, options) => {
// Transform script tags
if (node.tagName === 'SCRIPT') {
// Add custom attributes
node.setAttribute('data-app', 'my-app');
// Modify script source
if (node.src) {
node.src = node.src.replace('localhost', 'production-domain');
}
}
// Transform style tags
if (node.tagName === 'STYLE') {
// Add CSS scope
node.textContent = `.app-scope { ${node.textContent} }`;
}
return node;
};
loadMicroApp({
name: 'transformed-app',
entry: '//localhost:8080',
container: '#container',
}, {
nodeTransformer: customNodeTransformer
});
```
## 🚀 Start Configuration Options
### prefetch
**Type**: `boolean | 'all' | string[] | Function`
**Default**: `true`
**Description**: Resource prefetching strategy for better performance.
#### Boolean Values
```typescript
// Disable prefetch
start({ prefetch: false });
// Enable default prefetch
start({ prefetch: true });
```
#### Prefetch All
```typescript
// Prefetch all registered micro apps
start({ prefetch: 'all' });
```
#### Selective Prefetch
```typescript
// Prefetch specific apps
start({
prefetch: ['dashboard', 'user-profile', 'analytics']
});
```
#### Dynamic Prefetch Strategy
```typescript
start({
prefetch: (apps) => {
// Business logic to determine prefetch strategy
const currentTime = new Date().getHours();
const isBusinessHours = currentTime >= 9 && currentTime <= 17;
if (isBusinessHours) {
// Prefetch business-critical apps during business hours
return {
criticalAppNames: ['dashboard', 'crm', 'finance'],
minorAppsName: ['reporting', 'settings']
};
} else {
// Minimal prefetch during off-hours
return {
criticalAppNames: ['dashboard'],
minorAppsName: []
};
}
}
});
```
#### User-based Prefetch
```typescript
start({
prefetch: (apps) => {
const userRole = getCurrentUserRole();
switch (userRole) {
case 'admin':
return {
criticalAppNames: ['admin-panel', 'user-management', 'system-monitor'],
minorAppsName: ['reports', 'settings']
};
case 'user':
return {
criticalAppNames: ['dashboard', 'profile'],
minorAppsName: ['help', 'feedback']
};
default:
return {
criticalAppNames: ['dashboard'],
minorAppsName: []
};
}
}
});
```
### sandbox
**Type**: `boolean | SandboxConfig`
**Default**: `true`
**Description**: Global sandbox configuration for all micro applications.
#### Basic Sandbox
```typescript
// Enable sandbox for all apps
start({ sandbox: true });
// Disable sandbox for all apps (not recommended)
start({ sandbox: false });
```
#### Advanced Sandbox Configuration
```typescript
start({
sandbox: {
strictStyleIsolation: true, // Enable Shadow DOM style isolation
experimentalStyleIsolation: true, // Enable scoped CSS style isolation
}
});
```
#### Style Isolation Options
**strictStyleIsolation**: Uses Shadow DOM to completely isolate styles
```typescript
start({
sandbox: {
strictStyleIsolation: true, // Strongest isolation but may break some UI libraries
}
});
```
**experimentalStyleIsolation**: Uses scoped CSS to isolate styles
```typescript
start({
sandbox: {
experimentalStyleIsolation: true, // Good balance of isolation and compatibility
}
});
```
#### Combined Style Isolation
```typescript
start({
sandbox: {
strictStyleIsolation: false, // Disable Shadow DOM
experimentalStyleIsolation: true, // Enable scoped CSS
}
});
```
### singular
**Type**: `boolean`
**Default**: `true`
**Description**: Whether only one micro app can be mounted at a time.
```typescript
// Only one app at a time (default)
start({ singular: true });
// Allow multiple apps simultaneously
start({
singular: false // Useful for dashboard-style applications
});
```
#### Use Cases for Multiple Apps
```typescript
// Dashboard with multiple widgets
start({
singular: false,
// Other configurations
});
// Register widget-style micro apps
registerMicroApps([
{ name: 'widget-weather', entry: '//localhost:8001', container: '#widget-1', activeRule: '/dashboard' },
{ name: 'widget-stocks', entry: '//localhost:8002', container: '#widget-2', activeRule: '/dashboard' },
{ name: 'widget-news', entry: '//localhost:8003', container: '#widget-3', activeRule: '/dashboard' },
]);
```
### urlRerouteOnly
**Type**: `boolean`
**Default**: `true`
**Description**: Whether to trigger routing only on URL changes.
```typescript
// Only route on URL changes (default)
start({ urlRerouteOnly: true });
// Route on both URL and programmatic changes
start({
urlRerouteOnly: false // More responsive but potentially more performance overhead
});
```
## 🔧 Environment-based Configuration
### Development Configuration
```typescript
const developmentConfig = {
prefetch: false, // Faster rebuilds
sandbox: {
strictStyleIsolation: false, // Easier debugging
experimentalStyleIsolation: true,
},
singular: false, // More flexible development
urlRerouteOnly: false, // More responsive navigation
};
if (process.env.NODE_ENV === 'development') {
start(developmentConfig);
}
```
### Production Configuration
```typescript
const productionConfig = {
prefetch: 'all', // Better user experience
sandbox: {
strictStyleIsolation: true, // Better isolation
experimentalStyleIsolation: false,
},
singular: true, // Stable performance
urlRerouteOnly: true, // Optimized routing
};
if (process.env.NODE_ENV === 'production') {
start(productionConfig);
}
```
### Mobile Configuration
```typescript
const mobileConfig = {
prefetch: (apps) => ({
// Conservative prefetch on mobile
criticalAppNames: ['home'],
minorAppsName: []
}),
sandbox: {
// Lighter sandbox for mobile performance
strictStyleIsolation: false,
experimentalStyleIsolation: true,
},
singular: true, // Better for mobile UX
};
const isMobile = window.innerWidth < 768;
if (isMobile) {
start(mobileConfig);
}
```
## 🎯 Advanced Configuration Patterns
### 1. Feature Flag Integration
```typescript
const getConfigWithFeatureFlags = async () => {
const featureFlags = await getFeatureFlags();
return {
prefetch: featureFlags.enablePrefetch ? 'all' : false,
sandbox: {
strictStyleIsolation: featureFlags.strictIsolation,
experimentalStyleIsolation: !featureFlags.strictIsolation,
},
singular: featureFlags.allowMultipleApps ? false : true,
};
};
getConfigWithFeatureFlags().then(config => start(config));
```
### 2. Performance-based Configuration
```typescript
const getPerformanceConfig = () => {
const connection = navigator.connection || navigator.mozConnection || navigator.webkitConnection;
const isSlowConnection = connection?.effectiveType === '2g' || connection?.effectiveType === 'slow-2g';
if (isSlowConnection) {
return {
prefetch: false, // No prefetch on slow connections
sandbox: {
strictStyleIsolation: false,
experimentalStyleIsolation: true,
},
singular: true,
};
}
return {
prefetch: 'all',
sandbox: {
strictStyleIsolation: true,
experimentalStyleIsolation: false,
},
singular: false,
};
};
start(getPerformanceConfig());
```
### 3. User Role-based Configuration
```typescript
const getRoleBasedConfig = (userRole) => {
const baseConfig = {
sandbox: true,
singular: true,
};
switch (userRole) {
case 'admin':
return {
...baseConfig,
prefetch: 'all', // Admins get all features
singular: false, // Can use multiple admin tools
};
case 'poweruser':
return {
...baseConfig,
prefetch: ['dashboard', 'analytics', 'reports'],
singular: false,
};
default:
return {
...baseConfig,
prefetch: ['dashboard'], // Basic users get minimal prefetch
singular: true,
};
}
};
const userRole = getCurrentUserRole();
start(getRoleBasedConfig(userRole));
```
## ⚠️ Important Notes
### 1. Configuration Precedence
```typescript
// App-level configuration overrides global configuration
start({
sandbox: true, // Global setting
});
loadMicroApp({
name: 'special-app',
entry: '//localhost:8080',
container: '#container',
}, {
sandbox: false // This overrides the global setting for this app
});
```
### 2. Performance Considerations
```typescript
// ❌ Bad: Heavy configuration that impacts performance
start({
prefetch: 'all', // Might slow down initial load
sandbox: {
strictStyleIsolation: true, // More overhead
},
singular: false, // More memory usage
urlRerouteOnly: false, // More frequent route checks
});
// ✅ Good: Balanced configuration
start({
prefetch: ['critical-app'], // Only prefetch what's needed
sandbox: {
experimentalStyleIsolation: true, // Good balance
},
singular: true, // Stable performance
urlRerouteOnly: true, // Optimized routing
});
```
### 3. Debugging Configuration
```typescript
const debugConfig = {
sandbox: {
strictStyleIsolation: false, // Easier to inspect styles
experimentalStyleIsolation: true,
},
// Custom fetch for logging
fetch: async (url, options) => {
console.log(`[DEBUG] Fetching: ${url}`);
const response = await fetch(url, options);
console.log(`[DEBUG] Response: ${response.status}`);
return response;
},
// Custom node transformer for debugging
nodeTransformer: (node, options) => {
if (node.tagName === 'SCRIPT') {
console.log(`[DEBUG] Processing script: ${node.src || 'inline'}`);
}
return node;
}
};
```
## 🔗 Related APIs
- [start](/api/start) - Start qiankun with configuration
- [loadMicroApp](/api/load-micro-app) - Load app with configuration
- [registerMicroApps](/api/register-micro-apps) - Register apps
================================================
FILE: docs/api/index.md
================================================
# API Reference
qiankun provides a simple yet powerful API set for building micro-frontend applications. All APIs are fully typed with TypeScript definitions to ensure both developer experience and type safety.
## 📚 Core APIs
### Application Registration & Startup
| API | Description | Type |
|-----|-------------|------|
| [`registerMicroApps`](/api/register-micro-apps) | Register micro applications | `(apps: RegistrableApp[], lifeCycles?: LifeCycles) => void` |
| [`start`](/api/start) | Start qiankun framework | `(opts?: StartOpts) => void` |
| [`loadMicroApp`](/api/load-micro-app) | Manually load micro application | `(app: LoadableApp, configuration?: AppConfiguration, lifeCycles?: LifeCycles) => MicroApp` |
### Utility APIs
| API | Description | Type |
|-----|-------------|------|
| [`isRuntimeCompatible`](/api/is-runtime-compatible) | Check runtime compatibility | `() => boolean` |
## 🎯 Quick Navigation
### By Use Case
**Route-based Mode**
```typescript
import { registerMicroApps, start } from 'qiankun';
// 1. Register micro apps
registerMicroApps([...]);
// 2. Start framework
start();
```
**Manual Loading Mode**
```typescript
import { loadMicroApp } from 'qiankun';
// Manually load micro app
const microApp = loadMicroApp({...});
```
**Compatibility Check**
```typescript
import { isRuntimeCompatible } from 'qiankun';
if (isRuntimeCompatible()) {
// Start micro-frontend application
}
```
### By Functionality
| Category | Related APIs | Description |
|----------|--------------|-------------|
| **App Management** | `registerMicroApps`, `loadMicroApp` | Register and load micro applications |
| **Framework Control** | `start` | Framework startup and configuration |
| **Utilities** | `isRuntimeCompatible` | Helper utility methods |
## 🔧 Type Definitions
qiankun provides complete TypeScript type definitions:
```typescript
import type {
RegistrableApp,
LoadableApp,
MicroApp,
LifeCycles,
AppConfiguration,
} from 'qiankun';
```
See [Type Definitions](/api/types) for detailed information.
## 📖 Detailed Documentation
### Core APIs
- [registerMicroApps](/api/register-micro-apps) - Register micro applications
- [start](/api/start) - Start qiankun framework
- [loadMicroApp](/api/load-micro-app) - Manually load micro applications
- [isRuntimeCompatible](/api/is-runtime-compatible) - Runtime compatibility check
### Reference Documentation
- [Lifecycles](/api/lifecycles) - Application lifecycle hooks
- [Configuration](/api/configuration) - Framework configuration options
- [Types](/api/types) - TypeScript type definitions
## 💡 Usage Recommendations
### Recommended API Usage Patterns
1. **Standard Route-based Mode** (Recommended)
```typescript
registerMicroApps([...]) → start()
```
2. **Dynamic Loading Mode**
```typescript
loadMicroApp({...})
```
3. **Hybrid Mode**
```typescript
registerMicroApps([...]) → start() + loadMicroApp({...})
```
### Best Practices
- ✅ Use TypeScript for complete type support
- ✅ Register all micro apps before starting the framework
- ✅ Use lifecycle hooks appropriately for state management
- ✅ Configure proper error handling
- ❌ Avoid registering duplicate app names
- ❌ Avoid calling main app APIs from micro apps
- ❌ Avoid time-consuming operations in lifecycle hooks
================================================
FILE: docs/api/is-runtime-compatible.md
================================================
# isRuntimeCompatible
Check if the current browser environment is compatible with qiankun runtime features.
## 🎯 Function Signature
```typescript
function isRuntimeCompatible(): boolean
```
## 📋 Parameters
This function takes no parameters.
## 🔄 Return Value
- **Type**: `boolean`
- **Description**: Returns `true` if the current environment supports qiankun features, `false` otherwise.
## 💡 Usage Examples
### Basic Compatibility Check
```typescript
import { isRuntimeCompatible, registerMicroApps, start } from 'qiankun';
if (isRuntimeCompatible()) {
// Environment supports qiankun
registerMicroApps([...]);
start();
} else {
// Fallback for unsupported browsers
console.warn('Current browser does not support qiankun');
initFallbackRouting();
}
```
### With Graceful Degradation
```typescript
function initApplication() {
if (isRuntimeCompatible()) {
// Use qiankun micro-frontend architecture
initMicroFrontend();
} else {
// Fall back to traditional SPA
initTraditionalSPA();
}
}
function initMicroFrontend() {
registerMicroApps([
{
name: 'module-a',
entry: '//localhost:8001',
container: '#container',
activeRule: '/module-a',
}
]);
start();
}
function initTraditionalSPA() {
// Traditional routing setup
import('./traditional-router').then(router => {
router.init();
});
}
```
## 🔍 What It Checks
The `isRuntimeCompatible` function checks for the following browser features:
### Required Features
1. **Proxy Support**: For JavaScript sandbox isolation
2. **Window.Proxy**: Essential for creating isolated execution contexts
3. **Import Maps** (when used): For dynamic module loading
4. **Dynamic Import**: For loading micro applications
### Browser Compatibility
| Browser | Minimum Version | Support |
|---------|----------------|---------|
| Chrome | 61+ | ✅ Full |
| Firefox | 60+ | ✅ Full |
| Safari | 11+ | ✅ Full |
| Edge | 79+ | ✅ Full |
| IE | Any | ❌ Not Supported |
## 🚀 Best Practices
### 1. Early Detection
```typescript
// Check compatibility before any qiankun setup
function bootstrap() {
if (!isRuntimeCompatible()) {
showUnsupportedBrowserMessage();
return;
}
// Safe to proceed with qiankun
setupMicroFrontend();
}
```
### 2. Progressive Enhancement
```typescript
class ApplicationBootstrap {
private isQiankunSupported = isRuntimeCompatible();
init() {
if (this.isQiankunSupported) {
this.initWithMicroFrontend();
} else {
this.initWithoutMicroFrontend();
}
}
private initWithMicroFrontend() {
// Full micro-frontend experience
registerMicroApps([...]);
start();
}
private initWithoutMicroFrontend() {
// Simplified experience for unsupported browsers
this.loadAllModulesDirectly();
}
}
```
### 3. User Communication
```typescript
if (!isRuntimeCompatible()) {
// Show user-friendly message
const banner = document.createElement('div');
banner.innerHTML = `
<div style="background: #fff3cd; padding: 12px; border: 1px solid #ffeaa7; margin: 10px;">
<strong>Browser Compatibility Notice:</strong>
For the best experience, please use a modern browser like Chrome, Firefox, or Safari.
Some features may be limited in your current browser.
</div>
`;
document.body.insertBefore(banner, document.body.firstChild);
}
```
## 🔧 Integration Patterns
### 1. With Feature Flags
```typescript
const featureFlags = {
useMicroFrontend: isRuntimeCompatible() && process.env.ENABLE_MICRO_FRONTEND,
useAdvancedFeatures: isRuntimeCompatible(),
};
if (featureFlags.useMicroFrontend) {
// Full micro-frontend setup
registerMicroApps([...]);
start();
} else {
// Traditional setup
initTraditionalApp();
}
```
### 2. With Analytics
```typescript
// Track browser compatibility for analytics
const compatible = isRuntimeCompatible();
// Send analytics event
analytics.track('browser_compatibility_check', {
compatible,
userAgent: navigator.userAgent,
timestamp: Date.now(),
});
if (compatible) {
initQiankunApp();
} else {
initFallbackApp();
}
```
### 3. With Dynamic Loading
```typescript
async function loadApplicationFramework() {
if (isRuntimeCompatible()) {
// Load qiankun and micro-frontend modules
const [qiankun, microApps] = await Promise.all([
import('qiankun'),
import('./micro-apps-config'),
]);
qiankun.registerMicroApps(microApps.default);
qiankun.start();
} else {
// Load traditional SPA modules
const traditionalApp = await import('./traditional-app');
traditionalApp.init();
}
}
```
## ⚠️ Important Notes
### 1. Performance Consideration
```typescript
// ✅ Good: Check once and cache the result
const QIANKUN_COMPATIBLE = isRuntimeCompatible();
function someFunction() {
if (QIANKUN_COMPATIBLE) {
// Use cached result
}
}
// ❌ Bad: Check multiple times
function someFunction() {
if (isRuntimeCompatible()) { // Redundant check
// ...
}
}
```
### 2. SSR Considerations
```typescript
// In SSR environments, check if window is available
function safeCompatibilityCheck() {
if (typeof window === 'undefined') {
// SSR environment - assume compatible
return true;
}
return isRuntimeCompatible();
}
```
### 3. Testing Environment
```typescript
// For testing, you might want to mock the compatibility
if (process.env.NODE_ENV === 'test') {
// Mock for testing
global.mockQiankunCompatible = true;
}
function checkCompatibility() {
if (process.env.NODE_ENV === 'test' && global.mockQiankunCompatible !== undefined) {
return global.mockQiankunCompatible;
}
return isRuntimeCompatible();
}
```
## 🎯 Common Scenarios
### 1. Corporate Environment
```typescript
// Corporate environments might have older browsers
function initCorporateApp() {
const compatible = isRuntimeCompatible();
if (!compatible) {
// Inform IT department about browser requirements
logToAdminConsole('User browser incompatible with micro-frontend features');
}
return compatible ? initMicroFrontend() : initLegacyApp();
}
```
### 2. Public Website
```typescript
// Public websites need to support a wider range of browsers
function initPublicSite() {
if (isRuntimeCompatible()) {
// Enhanced experience with micro-frontends
loadAdvancedFeatures();
} else {
// Basic experience that works everywhere
loadBasicFeatures();
}
}
```
### 3. Mobile App WebView
```typescript
// Mobile WebViews might have different compatibility
function initMobileWebView() {
const compatible = isRuntimeCompatible();
// Log for mobile app developers
if (window.ReactNativeWebView) {
window.ReactNativeWebView.postMessage(JSON.stringify({
type: 'qiankun_compatibility',
compatible,
}));
}
return compatible ? initMicroFrontend() : initSimplifiedView();
}
```
## 🔗 Related APIs
- [start](/api/start) - Start qiankun (should be called after compatibility check)
- [registerMicroApps](/api/register-micro-apps) - Register micro applications
- [loadMicroApp](/api/load-micro-app) - Manually load micro applications
================================================
FILE: docs/api/lifecycles.md
================================================
# Lifecycles
Lifecycle hooks allow you to perform custom logic at different stages of a micro application's lifecycle. These hooks are executed automatically by qiankun during application loading, mounting, and unmounting processes.
## 🎯 Type Definition
```typescript
export type LifeCycleFn<T extends ObjectType> = (
app: LoadableApp<T>,
global: WindowProxy
) => Promise<void>;
export type LifeCycles<T extends ObjectType> = {
beforeLoad?: LifeCycleFn<T> | Array<LifeCycleFn<T>>;
beforeMount?: LifeCycleFn<T> | Array<LifeCycleFn<T>>;
afterMount?: LifeCycleFn<T> | Array<LifeCycleFn<T>>;
beforeUnmount?: LifeCycleFn<T> | Array<LifeCycleFn<T>>;
afterUnmount?: LifeCycleFn<T> | Array<LifeCycleFn<T>>;
};
```
## 📋 Available Lifecycle Hooks
### beforeLoad
**Timing**: Called before the micro application starts loading.
**Purpose**: Perform setup tasks before the application code is fetched and parsed.
```typescript
beforeLoad: async (app, global) => {
console.log(`About to load ${app.name}`);
// Setup global configurations
global.__INITIAL_CONFIG__ = getInitialConfig();
}
```
### beforeMount
**Timing**: Called after the application is loaded but before it's mounted to the DOM.
**Purpose**: Perform final setup before the application becomes active.
```typescript
beforeMount: async (app, global) => {
console.log(`About to mount ${app.name}`);
// Initialize services
await initializeServices();
// Set loading state
setLoadingState(false);
}
```
### afterMount
**Timing**: Called after the micro application has been successfully mounted.
**Purpose**: Perform post-mount operations like analytics, feature initialization.
```typescript
afterMount: async (app, global) => {
console.log(`${app.name} mounted successfully`);
// Track analytics
analytics.track('micro_app_mounted', { appName: app.name });
// Initialize features that depend on DOM
initializeDOMDependentFeatures();
}
```
### beforeUnmount
**Timing**: Called before the micro application starts unmounting.
**Purpose**: Cleanup operations before the application is removed.
```typescript
beforeUnmount: async (app, global) => {
console.log(`About to unmount ${app.name}`);
// Save application state
saveApplicationState(app.name);
// Cleanup event listeners
cleanupEventListeners();
}
```
### afterUnmount
**Timing**: Called after the micro application has been completely unmounted.
**Purpose**: Final cleanup and resource deallocation.
```typescript
afterUnmount: async (app, global) => {
console.log(`${app.name} unmounted`);
// Clear caches
clearApplicationCache(app.name);
// Reset global state
resetGlobalState();
}
```
## 🔄 Lifecycle Flow
```mermaid
graph TD
A[Start Loading] --> B[beforeLoad]
B --> C[Load Application Code]
C --> D[beforeMount]
D --> E[Mount Application]
E --> F[afterMount]
F --> G[Application Running]
G --> H[beforeUnmount]
H --> I[Unmount Application]
I --> J[afterUnmount]
J --> K[Application Cleaned Up]
```
## 💡 Usage Examples
### Basic Usage with registerMicroApps
```typescript
import { registerMicroApps, start } from 'qiankun';
registerMicroApps([
{
name: 'react-app',
entry: '//localhost:7100',
container: '#subapp-viewport',
activeRule: '/react',
}
], {
beforeLoad: async (app) => {
console.log('Loading app:', app.name);
},
afterMount: async (app) => {
console.log('App mounted:', app.name);
},
beforeUnmount: async (app) => {
console.log('Unmounting app:', app.name);
}
});
start();
```
### With loadMicroApp
```typescript
import { loadMicroApp } from 'qiankun';
const microApp = loadMicroApp({
name: 'dashboard',
entry: '//localhost:8080',
container: '#dashboard-container',
}, undefined, {
beforeLoad: async (app, global) => {
// Setup dashboard-specific configurations
global.DASHBOARD_CONFIG = getDashboardConfig();
},
afterMount: async (app) => {
// Initialize dashboard widgets
initializeDashboardWidgets();
}
});
```
### Multiple Hooks
```typescript
// You can provide multiple hooks as an array
const lifecycles = {
beforeMount: [
async (app) => {
await setupDatabase();
},
async (app) => {
await setupAnalytics();
},
async (app) => {
await setupFeatureFlags();
}
],
afterMount: [
async (app) => {
trackPageView(app.name);
},
async (app) => {
initializeUserTracking();
}
]
};
```
## 🔧 Advanced Patterns
### 1. State Management Integration
```typescript
import { store } from './store';
const lifecycles = {
beforeLoad: async (app) => {
// Set loading state
store.dispatch({ type: 'SET_APP_LOADING', payload: { appName: app.name, loading: true } });
},
afterMount: async (app) => {
// Update mounted apps list
store.dispatch({ type: 'ADD_MOUNTED_APP', payload: app.name });
store.dispatch({ type: 'SET_APP_LOADING', payload: { appName: app.name, loading: false } });
},
beforeUnmount: async (app) => {
// Save app state before unmounting
const appState = getAppState(app.name);
store.dispatch({ type: 'SAVE_APP_STATE', payload: { appName: app.name, state: appState } });
},
afterUnmount: async (app) => {
// Remove from mounted apps list
store.dispatch({ type: 'REMOVE_MOUNTED_APP', payload: app.name });
}
};
```
### 2. Error Handling
```typescript
const lifecycles = {
beforeLoad: async (app) => {
try {
await performPreLoadChecks(app);
} catch (error) {
console.error(`Pre-load checks failed for ${app.name}:`, error);
// Optionally prevent loading by throwing
throw new Error(`Failed to initialize ${app.name}`);
}
},
afterMount: async (app) => {
try {
await performPostMountTasks(app);
} catch (error) {
console.error(`Post-mount tasks failed for ${app.name}:`, error);
// Log error but don't prevent the app from running
reportError(error, { context: 'afterMount', appName: app.name });
}
}
};
```
### 3. Performance Monitoring
```typescript
const performanceTracker = new Map();
const lifecycles = {
beforeLoad: async (app) => {
performanceTracker.set(app.name, {
loadStart: performance.now()
});
},
beforeMount: async (app) => {
const timing = performanceTracker.get(app.name);
timing.loadEnd = performance.now();
timing.mountStart = performance.now();
},
afterMount: async (app) => {
const timing = performanceTracker.get(app.name);
timing.mountEnd = performance.now();
// Calculate and report metrics
const loadTime = timing.loadEnd - timing.loadStart;
const mountTime = timing.mountEnd - timing.mountStart;
analytics.track('micro_app_performance', {
appName: app.name,
loadTime,
mountTime,
totalTime: loadTime + mountTime
});
}
};
```
### 4. Resource Management
```typescript
const resourceMap = new Map();
const lifecycles = {
beforeMount: async (app) => {
// Allocate resources
const resources = await allocateResources(app.name);
resourceMap.set(app.name, resources);
},
beforeUnmount: async (app) => {
// Save critical data
const resources = resourceMap.get(app.name);
if (resources) {
await saveCriticalData(app.name, resources);
}
},
afterUnmount: async (app) => {
// Release resources
const resources = resourceMap.get(app.name);
if (resources) {
await releaseResources(resources);
resourceMap.delete(app.name);
}
}
};
```
## 🎯 Common Use Cases
### 1. Loading States
```typescript
const loadingManager = {
show: (appName) => {
const loader = document.createElement('div');
loader.id = `loader-${appName}`;
loader.innerHTML = '<div class="spinner">Loading...</div>';
document.body.appendChild(loader);
},
hide: (appName) => {
const loader = document.getElementById(`loader-${appName}`);
if (loader) loader.remove();
}
};
const lifecycles = {
beforeLoad: async (app) => {
loadingManager.show(app.name);
},
afterMount: async (app) => {
loadingManager.hide(app.name);
}
};
```
### 2. Authentication Check
```typescript
const lifecycles = {
beforeLoad: async (app) => {
const isAuthenticated = await checkAuthentication();
if (!isAuthenticated) {
throw new Error('User not authenticated');
}
},
beforeMount: async (app, global) => {
// Inject user context
const userContext = await getUserContext();
global.__USER_CONTEXT__ = userContext;
}
};
```
### 3. Theme Synchronization
```typescript
const lifecycles = {
beforeMount: async (app, global) => {
// Sync theme with micro app
const currentTheme = getCurrentTheme();
global.__THEME__ = currentTheme;
// Apply theme-specific styles
applyThemeStyles(currentTheme);
},
afterUnmount: async (app) => {
// Clean up theme styles
removeThemeStyles(app.name);
}
};
```
### 4. Feature Flag Management
```typescript
const lifecycles = {
beforeLoad: async (app, global) => {
// Load feature flags for the specific app
const featureFlags = await getFeatureFlags(app.name);
global.__FEATURE_FLAGS__ = featureFlags;
},
afterMount: async (app) => {
// Track which features are enabled
trackEnabledFeatures(app.name);
}
};
```
## ⚠️ Important Notes
### 1. Hook Execution Order
```typescript
// Hooks are executed in this order:
// 1. beforeLoad (before app code is loaded)
// 2. beforeMount (after load, before DOM mount)
// 3. afterMount (after DOM mount)
// ... app is running ...
// 4. beforeUnmount (before DOM unmount)
// 5. afterUnmount (after DOM unmount)
```
### 2. Error Handling
```typescript
// ❌ Bad: Unhandled errors can break the lifecycle
beforeLoad: async (app) => {
riskyOperation(); // This could throw
}
// ✅ Good: Always handle potential errors
beforeLoad: async (app) => {
try {
await riskyOperation();
} catch (error) {
console.error('Error in beforeLoad:', error);
// Decide whether to throw or handle gracefully
}
}
```
### 3. Async Operations
```typescript
// ✅ Good: All lifecycle hooks are async
beforeMount: async (app) => {
await setupDatabase();
await loadUserPreferences();
}
// ❌ Bad: Don't forget await for async operations
beforeMount: async (app) => {
setupDatabase(); // Missing await!
loadUserPreferences(); // Missing await!
}
```
### 4. Global Context
```typescript
// ✅ Good: Use the provided global context
beforeMount: async (app, global) => {
global.MY_CONFIG = getConfig(); // Set on the isolated global
}
// ❌ Bad: Don't use window directly
beforeMount: async (app, global) => {
window.MY_CONFIG = getConfig(); // Might affect other apps
}
```
## 🚀 Best Practices
### 1. Keep Hooks Lightweight
```typescript
// ✅ Good: Fast operations
beforeMount: async (app) => {
setAppTheme(app.name);
updateNavigationState();
}
// ❌ Bad: Heavy operations
beforeMount: async (app) => {
await downloadLargeDataset(); // This will block mounting
await processHeavyCalculations();
}
```
### 2. Use Hook Arrays for Organization
```typescript
const lifecycles = {
beforeMount: [
setupAuthentication,
setupTheme,
setupAnalytics,
setupFeatureFlags
],
afterMount: [
trackPageView,
initializeWidgets,
preloadCriticalData
]
};
```
### 3. Consistent Error Logging
```typescript
const createSafeHook = (hookName, hookFn) => async (app, global) => {
try {
await hookFn(app, global);
} catch (error) {
console.error(`Error in ${hookName} for ${app.name}:`, error);
// Report to error tracking service
errorTracker.report(error, { hook: hookName, app: app.name });
}
};
const lifecycles = {
beforeLoad: createSafeHook('beforeLoad', async (app) => {
// Your beforeLoad logic
}),
afterMount: createSafeHook('afterMount', async (app) => {
// Your afterMount logic
})
};
```
### 4. Resource Cleanup
```typescript
// Track resources in a way that survives app reloads
const globalResourceMap = window.__QIANKUN_RESOURCES__ || new Map();
window.__QIANKUN_RESOURCES__ = globalResourceMap;
const lifecycles = {
beforeMount: async (app) => {
const resources = await allocateResources();
globalResourceMap.set(app.name, resources);
},
afterUnmount: async (app) => {
const resources = globalResourceMap.get(app.name);
if (resources) {
await cleanupResources(resources);
globalResourceMap.delete(app.name);
}
}
};
```
## 🔗 Related APIs
- [registerMicroApps](/api/register-micro-apps) - Using lifecycles with registered apps
- [loadMicroApp](/api/load-micro-app) - Using lifecycles with manually loaded apps
- [start](/api/start) - Framework startup configuration
================================================
FILE: docs/api/load-micro-app.md
================================================
# loadMicroApp
Manually load a micro application. This is useful for loading micro applications dynamically or when they are not associated with routing.
## 🎯 Function Signature
```typescript
function loadMicroApp<T extends ObjectType>(
app: LoadableApp<T>,
configuration?: AppConfiguration,
lifeCycles?: LifeCycles<T>
): MicroApp
```
## 📋 Parameters
### app
- **Type**: `LoadableApp<T>`
- **Required**: ✅
- **Description**: Micro application configuration
#### LoadableApp Structure
```typescript
interface LoadableApp<T extends ObjectType> {
name: string; // Micro app name, globally unique
entry: string | EntryOpts; // Micro app entry
container: string | HTMLElement; // Container for the micro app
props?: T; // Custom data passed to micro app
}
```
| Property | Type | Required | Description |
|----------|------|----------|-------------|
| `name` | `string` | ✅ | Micro application name, used as unique identifier |
| `entry` | `string \| EntryOpts` | ✅ | Micro application entry, can be URL or resource configuration |
| `container` | `string \| HTMLElement` | ✅ | Container node selector or DOM element |
| `props` | `T` | ❌ | Custom data passed to the micro application |
### configuration
- **Type**: `AppConfiguration`
- **Required**: ❌
- **Description**: Advanced configuration options
```typescript
interface AppConfiguration {
sandbox?: boolean; // Enable sandbox isolation
globalContext?: WindowProxy; // Global context for the micro app
fetch?: Function; // Custom fetch function
streamTransformer?: Function; // Stream transformer
nodeTransformer?: Function; // Node transformer
}
```
### lifeCycles
- **Type**: `LifeCycles<T>`
- **Required**: ❌
- **Description**: Lifecycle hooks for this specific micro application
## 🔄 Return Value
Returns a `MicroApp` instance with the following methods:
```typescript
interface MicroApp {
mount(): Promise<void>; // Mount the micro app
unmount(): Promise<void>; // Unmount the micro app
update(props: any): Promise<void>; // Update micro app props
getStatus(): string; // Get current status
loadPromise: Promise<void>; // Loading promise
mountPromise: Promise<void>; // Mounting promise
unmountPromise: Promise<void>; // Unmounting promise
}
```
## 💡 Usage Examples
### Basic Usage
```typescript
import { loadMicroApp } from 'qiankun';
const microApp = loadMicroApp({
name: 'manual-app',
entry: '//localhost:8080',
container: '#manual-container',
});
// The micro app will be automatically mounted
```
### With Custom Props
```typescript
const microApp = loadMicroApp({
name: 'dashboard',
entry: '//localhost:8080',
container: '#dashboard-container',
props: {
token: localStorage.getItem('token'),
userId: getCurrentUserId(),
theme: 'dark'
}
});
```
### With Configuration
```typescript
const microApp = loadMicroApp({
name: 'third-party-app',
entry: '//external.example.com',
container: '#external-container',
}, {
sandbox: false, // Disable sandbox for legacy apps
fetch: customFetch, // Use custom fetch
});
```
### With Lifecycle Hooks
```typescript
const microApp = loadMicroApp({
name: 'monitored-app',
entry: '//localhost:8080',
container: '#monitored-container',
}, undefined, {
beforeMount: (app) => {
console.log('About to mount:', app.name);
showLoadingSpinner();
},
afterMount: (app) => {
console.log('Mounted successfully:', app.name);
hideLoadingSpinner();
},
beforeUnmount: (app) => {
console.log('About to unmount:', app.name);
saveUserState();
}
});
```
## 🔧 Advanced Usage
### Dynamic Loading with Conditions
```typescript
async function loadAppConditionally(condition: boolean) {
if (condition) {
const microApp = loadMicroApp({
name: 'conditional-app',
entry: '//localhost:8080',
container: '#conditional-container',
});
return microApp;
}
return null;
}
```
### Loading Multiple Apps
```typescript
function loadMultipleApps() {
const apps = [
{ name: 'app1', entry: '//localhost:8001', container: '#container1' },
{ name: 'app2', entry: '//localhost:8002', container: '#container2' },
{ name: 'app3', entry: '//localhost:8003', container: '#container3' },
];
const microApps = apps.map(app => loadMicroApp(app));
return microApps;
}
```
### Manual Control
```typescript
const microApp = loadMicroApp({
name: 'controlled-app',
entry: '//localhost:8080',
container: '#controlled-container',
});
// Manual unmount
await microApp.unmount();
// Update props
await microApp.update({ newData: 'updated' });
// Check status
console.log(microApp.getStatus()); // 'MOUNTED', 'UNMOUNTED', etc.
```
## 🎭 Use Cases
### 1. Modal/Dialog Applications
```typescript
function openAppModal() {
const modal = document.createElement('div');
modal.id = 'app-modal';
document.body.appendChild(modal);
const microApp = loadMicroApp({
name: 'modal-app',
entry: '//localhost:8080',
container: modal,
props: {
onClose: () => {
microApp.unmount().then(() => {
document.body.removeChild(modal);
});
}
}
});
return microApp;
}
```
### 2. Tab-based Applications
```typescript
class TabManager {
private activeTabs = new Map<string, MicroApp>();
async switchTab(tabName: string, config: LoadableApp) {
// Unmount current active tab
const currentApp = this.activeTabs.get('active');
if (currentApp) {
await currentApp.unmount();
}
// Load new tab
const newApp = loadMicroApp({
...config,
container: '#tab-content'
});
this.activeTabs.set('active', newApp);
this.activeTabs.set(tabName, newApp);
}
}
```
### 3. Widget System
```typescript
class WidgetSystem {
loadWidget(widgetConfig: any) {
return loadMicroApp({
name: `widget-${widgetConfig.id}`,
entry: widgetConfig.url,
container: `#widget-${widgetConfig.id}`,
props: widgetConfig.props
}, {
sandbox: true // Isolate widgets
});
}
}
```
## ⚠️ Important Notes
### Container Management
```typescript
// ❌ Bad: Reusing containers without proper cleanup
loadMicroApp({ name: 'app1', entry: '//localhost:8001', container: '#shared' });
loadMicroApp({ name: 'app2', entry: '//localhost:8002', container: '#shared' }); // Conflict!
// ✅ Good: Use unique containers or proper cleanup
const app1 = loadMicroApp({ name: 'app1', entry: '//localhost:8001', container: '#container1' });
const app2 = loadMicroApp({ name: 'app2', entry: '//localhost:8002', container: '#container2' });
```
### Memory Management
```typescript
// ✅ Good: Proper cleanup
const microApp = loadMicroApp({...});
// When done, always unmount
window.addEventListener('beforeunload', () => {
microApp.unmount();
});
```
### Error Handling
```typescript
try {
const microApp = loadMicroApp({
name: 'potentially-failing-app',
entry: '//unreliable-server.com',
container: '#container',
});
// Wait for load
await microApp.loadPromise;
console.log('App loaded successfully');
} catch (error) {
console.error('Failed to load micro app:', error);
// Handle error - show fallback UI, retry, etc.
}
```
## 🆚 vs registerMicroApps
| Feature | `loadMicroApp` | `registerMicroApps` |
|---------|----------------|---------------------|
| **Loading** | Manual, immediate | Automatic, route-based |
| **Use Case** | Dynamic loading, widgets, modals | Main navigation, SPA routing |
| **Lifecycle** | Manual control | Automatic by routing |
| **Performance** | Load on demand | Can preload |
## 🚀 Best Practices
### 1. Resource Management
```typescript
class MicroAppManager {
private apps = new Map<string, MicroApp>();
async loadApp(config: LoadableApp) {
// Check if already loaded
if (this.apps.has(config.name)) {
return this.apps.get(config.name);
}
const app = loadMicroApp(config);
this.apps.set(config.name, app);
// Auto cleanup on unmount
app.unmountPromise.then(() => {
this.apps.delete(config.name);
});
return app;
}
}
```
### 2. Props Management
```typescript
// ✅ Good: Reactive props
function createReactiveMicroApp(baseConfig: LoadableApp) {
let currentApp: MicroApp;
return {
async updateProps(newProps: any) {
if (currentApp) {
await currentApp.update(newProps);
}
},
async reload(newConfig: LoadableApp) {
if (currentApp) {
await currentApp.unmount();
}
currentApp = loadMicroApp({
...baseConfig,
...newConfig
});
}
};
}
```
### 3. Error Boundaries
```typescript
function loadMicroAppWithFallback(config: LoadableApp, fallbackHTML: string) {
const microApp = loadMicroApp(config);
microApp.loadPromise.catch((error) => {
console.error('Micro app failed to load:', error);
// Show fallback content
const container = typeof config.container === 'string'
? document.querySelector(config.container)
: config.container;
if (container) {
container.innerHTML = fallbackHTML;
}
});
return microApp;
}
```
## 🔗 Related APIs
- [registerMicroApps](/api/register-micro-apps) - For route-based micro app loading
- [start](/api/start) - Start qiankun framework
- [Lifecycles](/api/lifecycles) - Detailed lifecycle documentation
================================================
FILE: docs/api/register-micro-apps.md
================================================
# registerMicroApps
注册微应用到 qiankun 中,这是构建微前端应用的核心 API。
## 🎯 函数签名
```typescript
function registerMicroApps<T extends ObjectType>(
apps: Array<RegistrableApp<T>>,
lifeCycles?: LifeCycles<T>
): void
```
## 📋 参数
### apps
- **类型**: `Array<RegistrableApp<T>>`
- **必填**: ✅
- **描述**: 微应用注册信息数组
#### RegistrableApp 结构
```typescript
interface RegistrableApp<T extends ObjectType> {
name: string; // 微应用名称,全局唯一
entry: string | { scripts?: string[], styles?: string[] }; // 微应用入口
container: string | HTMLElement; // 微应用容器节点
activeRule: string | (location: Location) => boolean; // 激活规则
props?: T; // 传递给微应用的数据
loader?: (loading: boolean) => void; // 加载状态回调
}
```
| 属性 | 类型 | 必填 | 描述 |
|------|------|------|------|
| `name` | `string` | ✅ | 微应用名称,作为微应用的唯一标识 |
| `entry` | `string \| EntryOpts` | ✅ | 微应用的入口,可以是 URL 或资源配置对象 |
| `container` | `string \| HTMLElement` | ✅ | 微应用的容器节点选择器或 DOM 节点 |
| `activeRule` | `string \| Function` | ✅ | 微应用的激活规则 |
| `props` | `T` | ❌ | 传递给微应用的自定义数据 |
| `loader` | `Function` | ❌ | 微应用加载状态改变时的回调函数 |
### lifeCycles
- **类型**: `LifeCycles<T>`
- **必填**: ❌
- **描述**: 全局生命周期钩子
```typescript
interface LifeCycles<T extends ObjectType> {
beforeLoad?: LifeCycleFn<T> | Array<LifeCycleFn<T>>;
beforeMount?: LifeCycleFn<T> | Array<LifeCycleFn<T>>;
afterMount?: LifeCycleFn<T> | Array<LifeCycleFn<T>>;
beforeUnmount?: LifeCycleFn<T> | Array<LifeCycleFn<T>>;
afterUnmount?: LifeCycleFn<T> | Array<LifeCycleFn<T>>;
}
```
## 💡 使用示例
### 基础用法
```typescript
import { registerMicroApps, start } from 'qiankun';
registerMicroApps([
{
name: 'react16App',
entry: '//localhost:7100',
container: '#subapp-viewport',
activeRule: '/react16',
},
{
name: 'vue3App',
entry: '//localhost:7101',
container: '#subapp-viewport',
activeRule: '/vue3',
}
]);
start();
```
### 高级配置
```typescript
registerMicroApps([
{
name: 'dashboard',
entry: {
scripts: [
'//localhost:7100/static/js/main.js'
],
styles: [
'//localhost:7100/static/css/main.css'
]
},
container: '#dashboard-container',
activeRule: (location) => location.pathname.startsWith('/dashboard'),
props: {
token: 'your-auth-token',
userId: 123,
theme: 'dark'
},
loader: (loading) => {
console.log('Dashboard app loading:', loading);
// 显示/隐藏 loading 状态
}
}
], {
beforeLoad: [
app => console.log('Before load:', app.name),
app => trackEvent('micro-app-loading', { name: app.name })
],
beforeMount: app => console.log('Before mount:', app.name),
afterMount: app => console.log('After mount:', app.name),
beforeUnmount: app => console.log('Before unmount:', app.name),
afterUnmount: app => console.log('After unmount:', app.name),
});
```
## ⚙️ Entry 配置详解
### URL 字符串
最简单的配置方式,qiankun 会通过这个 URL 获取微应用的 HTML:
```typescript
{
name: 'app1',
entry: '//localhost:8080',
// ...
}
```
### 资源对象
精确控制微应用的资源加载:
```typescript
{
name: 'app2',
entry: {
scripts: [
'//localhost:8080/static/js/chunk.js',
'//localhost:8080/static/js/main.js'
],
styles: [
'//localhost:8080/static/css/main.css'
]
},
// ...
}
```
## 🎯 ActiveRule 配置
### 字符串路径
```typescript
{
activeRule: '/react16' // 匹配 /react16/xxx 路径
}
```
### 函数判断
```typescript
{
activeRule: (location) => {
// 自定义激活逻辑
return location.pathname.startsWith('/admin') &&
location.search.includes('module=dashboard');
}
}
```
### 常见模式
```typescript
// 1. 精确匹配
activeRule: (location) => location.pathname === '/exact-path'
// 2. 多路径匹配
activeRule: (location) => ['/path1', '/path2'].some(path =>
location.pathname.startsWith(path)
)
// 3. 带参数匹配
activeRule: (location) => /^\/user\/\d+/.test(location.pathname)
// 4. 查询参数匹配
activeRule: (location) => new URLSearchParams(location.search).get('app') === 'module1'
```
## 🔧 Container 配置
### CSS 选择器
```typescript
{
container: '#micro-app-container'
}
```
### DOM 节点
```typescript
{
container: document.querySelector('#container')
}
```
## 📨 Props 数据传递
微应用可以通过 props 参数接收主应用传递的数据:
```typescript
// 主应用
registerMicroApps([{
name: 'child-app',
// ...
props: {
data: { user: 'john' },
methods: {
onGlobalStateChange: (state) => console.log(state),
setGlobalState: (state) => updateGlobalState(state)
}
}
}]);
```
```typescript
// 微应用
export async function mount(props) {
console.log(props.data); // { user: 'john' }
console.log(props.methods); // { onGlobalStateChange, setGlobalState }
}
```
## ⚠️ 注意事项
### 应用名称唯一性
```typescript
// ❌ 错误:重复的应用名称
registerMicroApps([
{ name: 'app1', entry: '//localhost:8080', /*...*/ },
{ name: 'app1', entry: '//localhost:8081', /*...*/ }, // 重复!
]);
// ✅ 正确:唯一的应用名称
registerMicroApps([
{ name: 'app1', entry: '//localhost:8080', /*...*/ },
{ name: 'app2', entry: '//localhost:8081', /*...*/ },
]);
```
### 容器节点存在性
```typescript
// ❌ 错误:容器节点不存在
registerMicroApps([{
container: '#non-existent-container', // DOM 中不存在
// ...
}]);
// ✅ 正确:确保容器节点存在
registerMicroApps([{
container: '#app-container', // 确保 DOM 中存在
// ...
}]);
```
### 重复注册
```typescript
// ❌ 错误:重复注册会导致应用重复加载
registerMicroApps([...]);
registerMicroApps([...]); // 重复注册
// ✅ 正确:只注册一次
registerMicroApps([...]);
```
## 🚀 最佳实践
### 1. 应用配置管理
```typescript
// 推荐:将应用配置抽取为单独文件
const microApps = [
{
name: 'order-management',
entry: getAppEntry('order'),
container: '#subapp-container',
activeRule: '/order',
props: getAppProps('order')
},
// ...
];
registerMicroApps(microApps, {
beforeLoad: [initLoadingUI],
afterMount: [removeLoadingUI],
});
```
### 2. 环境配置
```typescript
const getAppEntry = (name: string) => {
const entries = {
development: {
order: '//localhost:8001',
user: '//localhost:8002'
},
production: {
order: '//order.example.com',
user: '//user.example.com'
}
};
return entries[process.env.NODE_ENV][name];
};
```
### 3. 统一错误处理
```typescript
registerMicroApps(microApps, {
beforeLoad: (app) => {
console.log(`Loading ${app.name}...`);
},
afterMount: (app) => {
console.log(`${app.name} mounted successfully`);
},
beforeUnmount: (app) => {
// 清理全局状态
cleanupGlobalState(app.name);
}
});
```
## 🔗 相关 API
- [start](/api/start) - 启动 qiankun
- [loadMicroApp](/api/load-micro-app) - 手动加载微应用
- [生命周期](/api/lifecycles) - 详细的生命周期说明
================================================
FILE: docs/api/start.md
================================================
# start
Start the qiankun framework. This function initializes the micro-frontend system and enables automatic routing-based micro application loading.
## 🎯 Function Signature
```typescript
function start(opts?: StartOpts): void
```
## 📋 Parameters
### opts
- **Type**: `StartOpts`
- **Required**: ❌
- **Description**: Startup configuration options
```typescript
interface StartOpts {
prefetch?: boolean | 'all' | string[] | ((apps: RegistrableApp[]) => { criticalAppNames: string[]; minorAppsName: string[] });
sandbox?: boolean | { strictStyleIsolation?: boolean; experimentalStyleIsolation?: boolean; };
singular?: boolean;
urlRerouteOnly?: boolean;
// ... other single-spa start options
}
```
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `prefetch` | `boolean \| 'all' \| string[] \| Function` | `true` | Resource prefetch strategy |
| `sandbox` | `boolean \| SandboxOpts` | `true` | Sandbox isolation configuration |
| `singular` | `boolean` | `true` | Whether only one micro app can be mounted at a time |
| `urlRerouteOnly` | `boolean` | `true` | Whether to trigger routing only on URL changes |
## 💡 Usage Examples
### Basic Usage
```typescript
import { registerMicroApps, start } from 'qiankun';
// Register micro apps first
registerMicroApps([
{
name: 'react-app',
entry: '//localhost:7100',
container: '#subapp-viewport',
activeRule: '/react',
},
{
name: 'vue-app',
entry: '//localhost:7101',
container: '#subapp-viewport',
activeRule: '/vue',
},
]);
// Start qiankun
start();
```
### With Configuration
```typescript
start({
prefetch: false, // Disable prefetch
sandbox: true, // Enable sandbox
singular: true, // Only one app at a time
urlRerouteOnly: true, // Route only on URL changes
});
```
### Advanced Sandbox Configuration
```typescript
start({
sandbox: {
strictStyleIsolation: true, // Enable strict style isolation
experimentalStyleIsolation: true, // Enable experimental style isolation
}
});
```
### Custom Prefetch Strategy
```typescript
start({
prefetch: 'all', // Prefetch all micro apps
});
// Or prefetch specific apps
start({
prefetch: ['react-app', 'vue-app'], // Only prefetch these apps
});
// Or custom prefetch function
start({
prefetch: (apps) => ({
criticalAppNames: ['dashboard', 'user-center'], // Critical apps to prefetch immediately
minorAppsName: ['analytics', 'settings'], // Minor apps to prefetch later
})
});
```
## ⚙️ Configuration Options
### Prefetch Strategies
#### 1. Boolean Values
```typescript
// Disable prefetch completely
start({ prefetch: false });
// Enable default prefetch behavior
start({ prefetch: true });
```
#### 2. Prefetch All
```typescript
// Prefetch all registered micro apps
start({ prefetch: 'all' });
```
#### 3. Selective Prefetch
```typescript
// Prefetch only specified apps
start({
prefetch: ['critical-app1', 'critical-app2']
});
```
#### 4. Dynamic Prefetch Strategy
```typescript
start({
prefetch: (apps) => {
// Custom logic to determine which apps to prefetch
const criticalApps = apps
.filter(app => app.name.includes('critical'))
.map(app => app.name);
const minorApps = apps
.filter(app => !app.name.includes('critical'))
.map(app => app.name);
return {
criticalAppNames: criticalApps, // Prefetch immediately
minorAppsName: minorApps, // Prefetch when idle
};
}
});
```
### Sandbox Configuration
#### 1. Boolean Sandbox
```typescript
// Enable basic sandbox
start({ sandbox: true });
// Disable sandbox (not recommended)
start({ sandbox: false });
```
#### 2. Advanced Sandbox
```typescript
start({
sandbox: {
strictStyleIsolation: true, // Shadow DOM based style isolation
experimentalStyleIsolation: true, // Scoped CSS based style isolation
}
});
```
### Performance Options
```typescript
start({
singular: false, // Allow multiple apps to mount simultaneously
urlRerouteOnly: false, // Trigger routing on both URL and programmatic changes
});
```
## 🚀 Best Practices
### 1. Call After Registration
```typescript
// ✅ Correct order
registerMicroApps([...]);
start();
// ❌ Wrong order
start();
registerMicroApps([...]); // This won't work properly
```
### 2. Environment-based Configuration
```typescript
const startOpts = {
prefetch: process.env.NODE_ENV === 'production' ? 'all' : false,
sandbox: {
strictStyleIsolation: process.env.NODE_ENV === 'production',
},
};
start(startOpts);
```
### 3. Performance Optimization
```typescript
// For better performance in production
start({
prefetch: (apps) => ({
criticalAppNames: ['dashboard'], // Only prefetch critical apps
minorAppsName: [], // Don't prefetch minor apps
}),
singular: true, // Prevent memory issues
sandbox: {
strictStyleIsolation: false, // Use lightweight style isolation
experimentalStyleIsolation: true,
},
});
```
### 4. Development vs Production
```typescript
if (process.env.NODE_ENV === 'development') {
start({
prefetch: false, // Faster development reload
sandbox: false, // Easier debugging
singular: false, // More flexible development
});
} else {
start({
prefetch: 'all', // Better user experience
sandbox: true, // Better isolation
singular: true, // Stable performance
});
}
```
## 🔧 Integration Patterns
### 1. With Loading States
```typescript
import { registerMicroApps, start } from 'qiankun';
let isQiankunStarted = false;
function startQiankunWithLoading() {
if (isQiankunStarted) return;
showGlobalLoading();
registerMicroApps([...], {
beforeLoad: (app) => {
console.log(`Loading ${app.name}...`);
},
afterMount: (app) => {
console.log(`${app.name} mounted`);
hideGlobalLoading();
},
});
start({
prefetch: 'all',
sandbox: true,
});
isQiankunStarted = true;
}
```
### 2. With Error Handling
```typescript
function startQiankunSafely() {
try {
registerMicroApps([...]);
start({
prefetch: 'all',
sandbox: true,
});
console.log('Qiankun started successfully');
} catch (error) {
console.error('Failed to start qiankun:', error);
// Fallback to traditional routing or show error page
window.location.href = '/fallback';
}
}
```
### 3. With Feature Detection
```typescript
import { isRuntimeCompatible } from 'qiankun';
if (isRuntimeCompatible()) {
registerMicroApps([...]);
start();
} else {
console.warn('Browser not compatible with qiankun');
// Fallback implementation
initTraditionalRouting();
}
```
## ⚠️ Important Notes
### 1. Call Only Once
```typescript
// ❌ Bad: Multiple calls
start();
start(); // This will be ignored
// ✅ Good: Single call
start();
```
### 2. Order Matters
```typescript
// ✅ Correct order
registerMicroApps([...]); // 1. Register apps first
start(); // 2. Then start
// ❌ Wrong order - apps won't be registered properly
start();
registerMicroApps([...]);
```
### 3. Prefetch Considerations
```typescript
// ⚠️ Be careful with 'all' in large applications
start({ prefetch: 'all' }); // Might impact initial load performance
// ✅ Better: Selective prefetch
start({
prefetch: ['critical-app1', 'critical-app2']
});
```
## 🎯 Common Use Cases
### 1. E-commerce Platform
```typescript
registerMicroApps([
{ name: 'product-catalog', entry: '//catalog.example.com', activeRule: '/products' },
{ name: 'shopping-cart', entry: '//cart.example.com', activeRule: '/cart' },
{ name: 'user-account', entry: '//account.example.com', activeRule: '/account' },
]);
start({
prefetch: (apps) => ({
criticalAppNames: ['shopping-cart'], // Always prefetch cart
minorAppsName: ['user-account'], // Prefetch account when idle
}),
sandbox: true,
singular: true,
});
```
### 2. Admin Dashboard
```typescript
start({
prefetch: false, // Don't prefetch - admin tools are used on demand
sandbox: {
strictStyleIsolation: true, // Prevent style conflicts between admin tools
},
singular: false, // Allow multiple admin tools open simultaneously
});
```
### 3. Multi-tenant Platform
```typescript
const tenantId = getCurrentTenantId();
start({
prefetch: [`tenant-${tenantId}-dashboard`], // Only prefetch current tenant's apps
sandbox: true, // Isolate tenant data
singular: true,
});
```
## 🔗 Related APIs
- [registerMicroApps](/api/register-micro-apps) - Register micro applications
- [loadMicroApp](/api/load-micro-app) - Manually load micro applications
- [isRuntimeCompatible](/api/is-runtime-compatible) - Check browser compatibility
================================================
FILE: docs/api/types.md
================================================
# TypeScript Types
qiankun provides comprehensive TypeScript type definitions to ensure type safety and excellent developer experience. This document covers all available types and interfaces.
## 📋 Core Types
### ObjectType
**Description**: Base type for generic object structures.
```typescript
export type ObjectType = Record<string, unknown>;
```
**Usage**:
```typescript
// Used as a constraint for generic types
function processApp<T extends ObjectType>(props: T): void {
// T can be any object type
}
```
### HTMLEntry
**Description**: Type for micro application entry points.
```typescript
export type HTMLEntry = string;
```
**Usage**:
```typescript
const appEntry: HTMLEntry = '//localhost:8080';
const appEntryWithPath: HTMLEntry = '//localhost:8080/micro-app';
```
## 🏗️ Application Types
### AppMetadata
**Description**: Base metadata for micro applications.
```typescript
type AppMetadata = {
name: string; // Unique application name
entry: HTMLEntry; // Application entry URL
};
```
### LoadableApp\<T\>
**Description**: Configuration for manually loaded micro applications.
```typescript
export type LoadableApp<T extends ObjectType> = AppMetadata & {
container: HTMLElement; // DOM container element
props?: T; // Custom properties passed to the app
};
```
**Usage**:
```typescript
// Basic usage
const app: LoadableApp<{}> = {
name: 'my-app',
entry: '//localhost:8080',
container: document.getElementById('app-container')!,
};
// With custom props
interface MyAppProps {
theme: 'light' | 'dark';
userId: string;
}
const appWithProps: LoadableApp<MyAppProps> = {
name: 'themed-app',
entry: '//localhost:8080',
container: document.getElementById('container')!,
props: {
theme: 'dark',
userId: '123'
}
};
```
### RegistrableApp\<T\>
**Description**: Configuration for route-based micro applications.
```typescript
export type RegistrableApp<T extends ObjectType> = LoadableApp<T> & {
loader?: (loading: boolean) => void; // Loading state callback
activeRule: RegisterApplicationConfig['activeWhen']; // Routing activation rule
};
```
**Usage**:
```typescript
import { registerMicroApps } from 'qiankun';
interface UserAppProps {
currentUser: { id: string; name: string };
}
const apps: RegistrableApp<UserAppProps>[] = [
{
name: 'user-dashboard',
entry: '//localhost:8001',
container: '#subapp-viewport',
activeRule: '/dashboard',
props: {
currentUser: { id: '123', name: 'John' }
},
loader: (loading) => {
if (loading) {
showLoadingSpinner();
} else {
hideLoadingSpinner();
}
}
}
];
registerMicroApps(apps);
```
## ⚙️ Configuration Types
### AppConfiguration
**Description**: Configuration options for individual micro applications.
```typescript
export type AppConfiguration = Partial<Pick<LoaderOpts, 'fetch' | 'streamTransformer' | 'nodeTransformer'>> & {
sandbox?: boolean; // Enable sandbox isolation
globalContext?: WindowProxy; // Custom global context
};
```
**Usage**:
```typescript
import { loadMicroApp } from 'qiankun';
const customConfig: AppConfiguration = {
sandbox: true,
globalContext: window,
fetch: async (url, options) => {
// Custom fetch implementation
return fetch(url, {
...options,
headers: {
...options?.headers,
'Authorization': 'Bearer token'
}
});
},
nodeTransformer: (node, opts) => {
// Transform DOM nodes
if (node.tagName === 'SCRIPT') {
node.setAttribute('data-app', 'my-app');
}
return node;
}
};
loadMicroApp({
name: 'configured-app',
entry: '//localhost:8080',
container: document.getElementById('container')!
}, customConfig);
```
## 🔄 Lifecycle Types
### LifeCycleFn\<T\>
**Description**: Type for lifecycle hook functions.
```typescript
export type LifeCycleFn<T extends ObjectType> = (
app: LoadableApp<T>,
global: WindowProxy
) => Promise<void>;
```
**Usage**:
```typescript
const beforeLoadHook: LifeCycleFn<{ theme: string }> = async (app, global) => {
console.log(`Loading app: ${app.name}`);
global.__APP_THEME__ = app.props?.theme || 'default';
};
const afterMountHook: LifeCycleFn<any> = async (app, global) => {
console.log(`App ${app.name} mounted successfully`);
// Track analytics
analytics.track('app_mounted', { appName: app.name });
};
```
### LifeCycles\<T\>
**Description**: Complete lifecycle hooks configuration.
```typescript
export type LifeCycles<T extends ObjectType> = {
beforeLoad?: LifeCycleFn<T> | Array<LifeCycleFn<T>>;
beforeMount?: LifeCycleFn<T> | Array<LifeCycleFn<T>>;
afterMount?: LifeCycleFn<T> | Array<LifeCycleFn<T>>;
beforeUnmount?: LifeCycleFn<T> | Array<LifeCycleFn<T>>;
afterUnmount?: LifeCycleFn<T> | Array<LifeCycleFn<T>>;
};
```
**Usage**:
```typescript
interface AppProps {
userId: string;
permissions: string[];
}
const lifecycles: LifeCycles<AppProps> = {
beforeLoad: async (app, global) => {
// Setup before loading
global.__USER_ID__ = app.props?.userId;
},
beforeMount: [
async (app, global) => {
// Multiple hooks as array
await setupAuthentication(app.props?.userId);
},
async (app, global) => {
await loadUserPermissions(app.props?.permissions);
}
],
afterMount: async (app) => {
console.log(`${app.name} is ready`);
},
beforeUnmount: async (app) => {
// Cleanup before unmounting
await saveUserState(app.name);
},
afterUnmount: async (app) => {
// Final cleanup
await clearUserData(app.name);
}
};
```
## 🎯 Micro App Types
### MicroApp
**Description**: Instance of a loaded micro application.
```typescript
export type MicroApp = Parcel;
```
The `MicroApp` type extends the single-spa `Parcel` interface with these methods:
```typescript
interface MicroApp {
mount(): Promise<void>; // Mount the application
unmount(): Promise<void>; // Unmount the application
update(props: any): Promise<void>; // Update application props
getStatus(): string; // Get current status
loadPromise: Promise<void>; // Promise that resolves when loaded
mountPromise: Promise<void>; // Promise that resolves when mounted
unmountPromise: Promise<void>; // Promise that resolves when unmounted
}
```
**Usage**:
```typescript
import { loadMicroApp } from 'qiankun';
const microApp: MicroApp = loadMicroApp({
name: 'my-app',
entry: '//localhost:8080',
container: document.getElementById('container')!
});
// Check status
console.log(microApp.getStatus()); // 'LOADING', 'MOUNTED', 'UNMOUNTED', etc.
// Wait for mounting
await microApp.mountPromise;
console.log('App is mounted');
// Update props
await microApp.update({ newTheme: 'dark' });
// Unmount when done
await microApp.unmount();
```
### MicroAppLifeCycles
**Description**: Internal lifecycle type used by qiankun.
```typescript
export type MicroAppLifeCycles = FlattenArrayValue<ParcelLifeCycles<ExtraProps>>;
```
This type is primarily for internal use and represents the flattened lifecycle functions that micro applications must export.
## 🌐 Global Types
### Window Extensions
qiankun extends the global `Window` interface with special properties:
```typescript
declare global {
interface Window {
__POWERED_BY_QIANKUN__?: boolean; // Indicates app is running in qiankun
__INJECTED_PUBLIC_PATH_BY_QIANKUN__?: string; // Injected public path
__QIANKUN_DEVELOPMENT__?: boolean; // Development mode flag
Zone?: CallableFunction; // Zone.js compatibility
__zone_symbol__setTimeout?: Window['setTimeout']; // Zone.js timeout
}
}
```
**Usage in Micro Applications**:
```typescript
// Check if running in qiankun
if (window.__POWERED_BY_QIANKUN__) {
console.log('Running as a micro app');
// Use injected public path
const publicPath = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__ || '/';
// Configure your app accordingly
setupApp({ publicPath });
} else {
console.log('Running standalone');
setupApp({ publicPath: '/' });
}
```
## 🎨 Utility Types
### Custom Type Guards
Create type guards for better type safety:
```typescript
// Type guard for LoadableApp
function isLoadableApp<T extends ObjectType>(
app: any
): app is LoadableApp<T> {
return (
typeof app === 'object' &&
typeof app.name === 'string' &&
typeof app.entry === 'string' &&
app.container instanceof HTMLElement
);
}
// Type guard for RegistrableApp
function isRegistrableApp<T extends ObjectType>(
app: any
): app is RegistrableApp<T> {
return (
isLoadableApp(app) &&
(typeof app.activeRule === 'string' || typeof app.activeRule === 'function')
);
}
// Usage
function processApp(app: unknown) {
if (isRegistrableApp(app)) {
// TypeScript knows app is RegistrableApp here
console.log(`Registering app: ${app.name} with rule: ${app.activeRule}`);
} else if (isLoadableApp(app)) {
// TypeScript knows app is LoadableApp here
console.log(`Loading app: ${app.name}`);
}
}
```
### Generic Helper Types
Create reusable generic types for common patterns:
```typescript
// Props with theme support
type ThemedProps<T = {}> = T & {
theme?: 'light' | 'dark';
};
// Props with user context
type UserAwareProps<T = {}> = T & {
currentUser?: {
id: string;
name: string;
role: string;
};
};
// Combined props
type AppProps<T = {}> = ThemedProps<UserAwareProps<T>>;
// Usage
const app: LoadableApp<AppProps<{ customData: string }>> = {
name: 'themed-user-app',
entry: '//localhost:8080',
container: document.getElementById('container')!,
props: {
theme: 'dark',
currentUser: { id: '123', name: 'John', role: 'admin' },
customData: 'custom value'
}
};
```
## 📖 Advanced Type Patterns
### Conditional Types for Configuration
```typescript
// Configuration based on environment
type EnvironmentConfig<T extends 'development' | 'production'> = T extends 'development'
? {
sandbox: false;
prefetch: false;
strictStyleIsolation: false;
}
: {
sandbox: true;
prefetch: 'all';
strictStyleIsolation: true;
};
// Usage with environment detection
declare const NODE_ENV: 'development' | 'production';
type CurrentConfig = EnvironmentConfig<typeof NODE_ENV>;
```
### Branded Types for App Names
```typescript
// Create branded type for app names to prevent mix-ups
type AppName = string & { readonly __brand: unique symbol };
function createAppName(name: string): AppName {
return name as AppName;
}
// Enhanced LoadableApp with branded name
type SafeLoadableApp<T extends ObjectType> = Omit<LoadableApp<T>, 'name'> & {
name: AppName;
};
// Usage
const appName = createAppName('my-secure-app');
const app: SafeLoadableApp<{}> = {
name: appName, // Type-safe app name
entry: '//localhost:8080',
container: document.getElementById('container')!
};
```
### Lifecycle Event Types
```typescript
// Enhanced lifecycle with event data
type LifeCycleEvent<T extends ObjectType> = {
app: LoadableApp<T>;
global: WindowProxy;
timestamp: number;
phase: 'beforeLoad' | 'beforeMount' | 'afterMount' | 'beforeUnmount' | 'afterUnmount';
};
type EnhancedLifeCycleFn<T extends ObjectType> = (event: LifeCycleEvent<T>) => Promise<void>;
// Usage
const enhancedHook: EnhancedLifeCycleFn<{ userId: string }> = async (event) => {
console.log(`Phase: ${event.phase}, App: ${event.app.name}, Time: ${event.timestamp}`);
if (event.phase === 'beforeMount') {
// Setup user context
event.global.__USER_ID__ = event.app.props?.userId;
}
};
```
## 🔍 Type Inference Examples
### Automatic Props Type Inference
```typescript
// Helper function with automatic type inference
function createTypedApp<T extends ObjectType>(
config: {
name: string;
entry: string;
container: HTMLElement;
props: T;
}
): LoadableApp<T> {
return config; // TypeScript infers the correct type
}
// Usage - TypeScript automatically infers the props type
const app = createTypedApp({
name: 'inferred-app',
entry: '//localhost:8080',
container: document.getElementById('container')!,
props: {
theme: 'dark',
userId: '123',
features: ['feature1', 'feature2']
}
// TypeScript knows props type is { theme: string; userId: string; features: string[] }
});
```
### Lifecycle Type Inference
```typescript
// Helper for creating typed lifecycles
function createLifecycles<T extends ObjectType>(
lifecycles: LifeCycles<T>
): LifeCycles<T> {
return lifecycles;
}
// Usage with inference
const typedLifecycles = createLifecycles({
beforeMount: async (app) => {
// TypeScript infers app.props type based on usage
console.log(app.props?.theme); // TypeScript knows this might be undefined
}
});
```
## ⚡ Best Practices
### 1. Use Strict Types
```typescript
// ✅ Good: Strict typing
interface StrictAppProps {
readonly userId: string;
readonly theme: 'light' | 'dark';
readonly permissions: readonly string[];
}
const app: LoadableApp<StrictAppProps> = {
name: 'strict-app',
entry: '//localhost:8080',
container: document.getElementById('container')!,
props: {
userId: '123',
theme: 'dark',
permissions: ['read', 'write']
}
};
// ❌ Bad: Loose typing
const looseApp: LoadableApp<any> = {
name: 'loose-app',
entry: '//localhost:8080',
container: document.getElementById('container')!,
props: { anything: 'goes' } // No type safety
};
```
### 2. Create Domain-Specific Types
```typescript
// Create types specific to your domain
interface ECommerceAppProps {
cartId: string;
currency: 'USD' | 'EUR' | 'GBP';
customerSegment: 'premium' | 'standard';
features: {
wishlist: boolean;
recommendations: boolean;
reviews: boolean;
};
}
type ECommerceApp = LoadableApp<ECommerceAppProps>;
type ECommerceLifecycles = LifeCycles<ECommerceAppProps>;
```
### 3. Use Generic Constraints
```typescript
// Constrain generic types for better type safety
interface BaseAppProps {
version: string;
environment: 'development' | 'staging' | 'production';
}
function createApp<T extends BaseAppProps>(
config: Omit<LoadableApp<T>, 'container'> & {
containerId: string;
}
): LoadableApp<T> {
const container = document.getElementById(config.containerId);
if (!container) {
throw new Error(`Container ${config.containerId} not found`);
}
return {
...config,
container
};
}
```
## 🔗 Related Documentation
- [API Reference](/api/) - Main API documentation
- [Lifecycles](/api/lifecycles) - Detailed lifecycle documentation
- [Configuration](/api/configuration) - Configuration options
================================================
FILE: docs/cookbook/error-handling.md
================================================
# Error Handling
Robust error handling is essential for micro-frontend applications where multiple independent applications run within the same context. This guide covers comprehensive strategies for handling errors, implementing graceful degradation, and maintaining application stability across qiankun-based micro-frontend systems.
## 🎯 Error Types in Micro-Frontends
### Common Error Categories
Micro-frontend applications face unique error scenarios:
- **Loading Errors**: Failed to fetch or parse micro application resources
- **Runtime Errors**: JavaScript errors within micro applications
- **Communication Errors**: Failed inter-application communication
- **Network Errors**: API calls and resource loading failures
- **Sandbox Errors**: Issues with JavaScript and CSS isolation
- **Lifecycle Errors**: Problems during mount/unmount processes
- **Version Conflicts**: Dependency version mismatches
### Error Impact Assessment
```javascript
// Error severity levels for micro-frontend applications
const ERROR_LEVELS = {
CRITICAL: 'critical', // Main app or core functionality affected
HIGH: 'high', // Major micro app functionality lost
MEDIUM: 'medium', // Partial micro app functionality affected
LOW: 'low', // Minor features or visual issues
INFO: 'info' // Non-blocking informational issues
};
const ErrorClassifier = {
classify(error, appName, context) {
// Critical: Main app crashes or core navigation fails
if (appName === 'main' || context.includes('navigation')) {
return ERROR_LEVELS.CRITICAL;
}
// High: User cannot complete primary workflows
if (context.includes('checkout') || context.includes('auth')) {
return ERROR_LEVELS.HIGH;
}
// Medium: Feature degradation but app still usable
if (error.name === 'ChunkLoadError' || error.name === 'TypeError') {
return ERROR_LEVELS.MEDIUM;
}
// Default to low for other errors
return ERROR_LEVELS.LOW;
}
};
```
## 🛡️ qiankun Error Boundaries
### Global Error Handling
Set up global error handlers for the entire micro-frontend ecosystem:
```javascript
import { addGlobalUncaughtErrorHandler, removeGlobalUncaughtErrorHandler } from 'qiankun';
// Global error handler for all micro apps
const globalErrorHandler = (event) => {
const { error, appName, lifecycleName } = event;
console.error(`Error in micro app "${appName}" during "${lifecycleName}":`, error);
// Report to error tracking service
reportError({
error,
appName,
lifecycle: lifecycleName,
timestamp: Date.now(),
userAgent: navigator.userAgent,
url: window.location.href
});
// Implement recovery strategy
handleMicroAppError(appName, error, lifecycleName);
};
// Register global error handler
addGlobalUncaughtErrorHandler(globalErrorHandler);
// Remove when cleaning up (e.g., in app unmount)
// removeGlobalUncaughtErrorHandler(globalErrorHandler);
```
### Lifecycle-Specific Error Handling
```javascript
// Error handling in lifecycle hooks
const errorHandlingLifecycles = {
async beforeLoad(app) {
try {
// Pre-loading checks
const healthCheck = await fetch(`${app.entry}/health`);
if (!healthCheck.ok) {
throw new Error(`Health check failed for ${app.name}`);
}
} catch (error) {
console.warn(`Pre-load health check failed for ${app.name}:`, error);
// Continue with loading but flag as potentially unstable
markAppAsUnstable(app.name);
}
},
async beforeMount(app) {
try {
// Validate app requirements
validateAppRequirements(app);
} catch (error) {
// Attempt to fix common issues
await attemptAutoFix(app, error);
}
},
async afterMount(app) {
// Verify successful mount
setTimeout(() => {
const container = document.querySelector(app.container);
if (!container || container.children.length === 0) {
console.error(`Mount verification failed for ${app.name}`);
showFallbackContent(app.container, app.name);
}
}, 1000);
},
async beforeUnmount(app) {
try {
// Clean up resources
cleanupAppResources(app.name);
} catch (error) {
console.warn(`Cleanup error for ${app.name}:`, error);
// Force cleanup
forceCleanup(app.name);
}
}
};
```
## 🚨 Framework-Specific Error Boundaries
### React Error Boundaries
```jsx
// React error boundary for micro applications
import React from 'react';
class MicroAppErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = {
hasError: false,
error: null,
errorInfo: null,
retryCount: 0,
lastRetry: null
};
}
static getDerivedStateFromError(error) {
return { hasError: true };
}
componentDidCatch(error, errorInfo) {
this.setState({
error,
errorInfo
});
// Report error
this.reportError(error, errorInfo);
// Attempt automatic recovery
this.attemptRecovery(error);
}
reportError = (error, errorInfo) => {
const errorReport = {
error: {
name: error.name,
message: error.message,
stack: error.stack
},
errorInfo,
appName: this.props.appName,
timestamp: Date.now(),
url: window.location.href,
userAgent: navigator.userAgent,
retryCount: this.state.retryCount
};
// Send to error tracking service
fetch('/api/errors', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(errorReport)
}).catch(err => console.error('Failed to report error:', err));
};
attemptRecovery = (error) => {
const { retryCount, lastRetry } = this.state;
const now = Date.now();
// Prevent too frequent retries
if (lastRetry && now - lastRetry < 5000) {
return;
}
// Limit retry attempts
if (retryCount >= 3) {
console.error(`Max retry attempts reached for ${this.props.appName}`);
return;
}
setTimeout(() => {
this.setState({
hasError: false,
error: null,
errorInfo: null,
retryCount: retryCount + 1,
lastRetry: now
});
}, 2000 * Math.pow(2, retryCount)); // Exponential backoff
};
render() {
if (this.state.hasError) {
const { appName, fallbackComponent: FallbackComponent } = this.props;
if (FallbackComponent) {
return (
<FallbackComponent
error={this.state.error}
appName={appName}
onRetry={() => this.attemptRecovery(this.state.error)}
/>
);
}
return (
<div className="micro-app-error">
<h3>Application Error</h3>
<p>The {appName} application encountered an error.</p>
<button onClick={() => this.attemptRecovery(this.state.error)}>
Retry ({this.state.retryCount}/3)
</button>
<details style={{ marginTop: '1rem' }}>
<summary>Error Details</summary>
<pre>{this.state.error?.stack}</pre>
</details>
</div>
);
}
return this.props.children;
}
}
// Usage with micro app
function MicroAppContainer({ appName, entry }) {
return (
<MicroAppErrorBoundary
appName={appName}
fallbackComponent={CustomErrorFallback}
>
<div id={`${appName}-container`} />
</MicroAppErrorBoundary>
);
}
```
### Vue Error Handling
```javascript
// Vue global error handler for micro apps
const app = createApp(MainApp);
app.config.errorHandler = (err, instance, info) => {
const appName = instance?.$root?.$options?.name || 'unknown';
console.error(`Vue error in ${appName}:`, err, info);
// Report error
reportVueError({
error: err,
appName,
info,
timestamp: Date.now()
});
// Attempt recovery
if (instance && typeof instance.$forceUpdate === 'function') {
instance.$forceUpdate();
}
};
// Vue 2 error boundary component
Vue.component('ErrorBoundary', {
data() {
return {
hasError: false,
error: null
};
},
errorCaptured(err, instance, info) {
this.hasError = true;
this.error = err;
// Report error
this.reportError(err, info);
// Prevent error from propagating
return false;
},
methods: {
reportError(error, info) {
// Error reporting logic
},
retry() {
this.hasError = false;
this.error = null;
this.$forceUpdate();
}
},
render(h) {
if (this.hasError) {
return h('div', { class: 'error-boundary' }, [
h('h3', 'Something went wrong'),
h('button', { on: { click: this.retry } }, 'Retry'),
h('pre', this.error?.message)
]);
}
return this.$slots.default;
}
});
```
## 🔄 Graceful Degradation Strategies
### Progressive Enhancement
```javascript
// Progressive feature loading with fallbacks
class FeatureLoader {
constructor() {
this.features = new Map();
this.fallbacks = new Map();
}
register(featureName, loader, fallback) {
this.features.set(featureName, loader);
this.fallbacks.set(featureName, fallback);
}
async load(featureName) {
try {
const loader = this.features.get(featureName);
if (!loader) {
throw new Error(`Feature "${featureName}" not registered`);
}
const feature = await loader();
return feature;
} catch (error) {
console.warn(`Failed to load feature "${featureName}":`, error);
const fallback = this.fallbacks.get(featureName);
if (fallback) {
return await fallback();
}
throw error;
}
}
}
// Usage example
const featureLoader = new FeatureLoader();
// Register advanced dashboard with fallback
featureLoader.register(
'advanced-dashboard',
() => import('./AdvancedDashboard'),
() => import('./BasicDashboard')
);
// Register chart component with static fallback
featureLoader.register(
'interactive-charts',
() => import('./InteractiveCharts'),
() => Promise.resolve(() => '<div>Charts unavailable</div>')
);
```
### Fallback UI Components
```jsx
// Comprehensive fallback components
const ErrorFallbacks = {
// Network error fallback
NetworkError: ({ onRetry, appName }) => (
<div className="error-fallback network-error">
<div className="error-icon">🌐</div>
<h3>Connection Problem</h3>
<p>Unable to load {appName}. Please check your internet connection.</p>
<div className="error-actions">
<button onClick={onRetry} className="retry-button">
Try Again
</button>
<button onClick={() => window.location.reload()}>
Refresh Page
</button>
</div>
</div>
),
// JavaScript error fallback
JavaScriptError: ({ error, appName, onRetry }) => (
<div className="error-fallback js-error">
<div className="error-icon">⚠️</div>
<h3>Application Error</h3>
<p>The {appName} application encountered a technical issue.</p>
<div className="error-actions">
<button onClick={onRetry} className="retry-button">
Reload Application
</button>
<button onClick={() => reportIssue(error, appName)}>
Report Issue
</button>
</div>
{process.env.NODE_ENV === 'development' && (
<details className="error-details">
<summary>Technical Details</summary>
<pre>{error.stack}</pre>
</details>
)}
</div>
),
// Loading timeout fallback
LoadingTimeout: ({ appName, onRetry }) => (
<div className="error-fallback loading-timeout">
<div className="error-icon">⏱️</div>
<h3>Loading Timeout</h3>
<p>{appName} is taking longer than expected to load.</p>
<div className="error-actions">
<button onClick={onRetry} className="retry-button">
Try Again
</button>
<button onClick={() => loadBasicVersion(appName)}>
Load Basic Version
</button>
</div>
</div>
),
// Generic fallback
Generic: ({ error, appName, onRetry }) => (
<div className="error-fallback generic">
<div className="error-icon">🔧</div>
<h3>Temporary Issue</h3>
<p>We're experiencing technical difficulties with {appName}.</p>
<div className="error-actions">
<button onClick={onRetry} className="retry-button">
Try Again
</button>
</div>
</div>
)
};
```
### Circuit Breaker Pattern
```javascript
// Circuit breaker for micro app loading
class CircuitBreaker {
constructor(threshold = 5, timeout = 60000, monitor = 30000) {
this.failureThreshold = threshold;
this.timeout = timeout;
this.monitoringPeriod = monitor;
this.state = 'CLOSED'; // CLOSED, OPEN, HALF_OPEN
this.failureCount = 0;
this.lastFailureTime = null;
this.nextAttemptTime = null;
}
async execute(operation, appName) {
if (this.state === 'OPEN') {
if (Date.now() < this.nextAttemptTime) {
throw new Error(`Circuit breaker is OPEN for ${appName}`);
}
this.state = 'HALF_OPEN';
}
try {
const result = await operation();
this.onSuccess();
return result;
} catch (error) {
this.onFailure();
throw error;
}
}
onSuccess() {
this.failureCount = 0;
this.state = 'CLOSED';
}
onFailure() {
this.failureCount++;
this.lastFailureTime = Date.now();
if (this.failureCount >= this.failureThreshold) {
this.state = 'OPEN';
this.nextAttemptTime = Date.now() + this.timeout;
}
}
getState() {
return this.state;
}
}
// Usage with micro app loading
const circuitBreakers = new Map();
const loadMicroAppWithCircuitBreaker = async (appConfig) => {
const { name } = appConfig;
if (!circuitBreakers.has(name)) {
circuitBreakers.set(name, new CircuitBreaker());
}
const breaker = circuitBreakers.get(name);
try {
return await breaker.execute(() => loadMicroApp(appConfig), name);
} catch (error) {
console.error(`Circuit breaker prevented loading ${name}:`, error);
throw error;
}
};
```
## 📊 Error Monitoring and Reporting
### Comprehensive Error Tracking
```javascript
// Advanced error tracking system
class ErrorTracker {
constructor(config) {
this.config = {
endpoint: '/api/errors',
batchSize: 10,
batchTimeout: 5000,
maxRetries: 3,
...config
};
this.errorQueue = [];
this.batchTimeout = null;
this.retryCount = new Map();
}
track(error, context = {}) {
const errorData = this.serializeError(error, context);
// Add to queue
this.errorQueue.push(errorData);
// Process batch if queue is full
if (this.errorQueue.length >= this.config.batchSize) {
this.processBatch();
} else {
// Set timeout for batch processing
this.scheduleBatchProcessing();
}
}
serializeError(error, context) {
return {
id: this.generateErrorId(),
timestamp: Date.now(),
error: {
name: error.name,
message: error.message,
stack: error.stack,
fileName: error.fileName,
lineNumber: error.lineNumber,
columnNumber: error.columnNumber
},
context: {
appName: context.appName || 'unknown',
userId: context.userId,
sessionId: this.getSessionId(),
url: window.location.href,
userAgent: navigator.userAgent,
viewport: {
width: window.innerWidth,
height: window.innerHeight
},
...context
},
environment: {
isDevelopment: process.env.NODE_ENV === 'development',
timestamp: Date.now(),
timezone: Intl.DateTimeFormat().resolvedOptions().timeZone
}
};
}
scheduleBatchProcessing() {
if (this.batchTimeout) {
clearTimeout(this.batchTimeout);
}
this.batchTimeout = setTimeout(() => {
this.processBatch();
}, this.config.batchTimeout);
}
async processBatch() {
if (this.errorQueue.length === 0) return;
const batch = this.errorQueue.splice(0, this.config.batchSize);
try {
await this.sendErrors(batch);
// Clear retry count on success
batch.forEach(error => {
this.retryCount.delete(error.id);
});
} catch (error) {
console.error('Failed to send error batch:', error);
// Retry logic
batch.forEach(errorData => {
const retries = this.retryCount.get(errorData.id) || 0;
if (retries < this.config.maxRetries) {
this.retryCount.set(errorData.id, retries + 1);
this.errorQueue.unshift(errorData); // Add back to front of queue
}
});
}
}
async sendErrors(errors) {
const response = await fetch(this.config.endpoint, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ errors })
});
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
return response.json();
}
generateErrorId() {
return `error_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
}
getSessionId() {
// Implementation to get/generate session ID
return sessionStorage.getItem('sessionId') || 'anonymous';
}
}
// Initialize global error tracker
const errorTracker = new ErrorTracker();
// Track unhandled errors
window.addEventListener('error', (event) => {
errorTracker.track(event.error, {
type: 'unhandled_error',
source: 'window.onerror'
});
});
// Track unhandled promise rejections
window.addEventListener('unhandledrejection', (event) => {
errorTracker.track(event.reason, {
type: 'unhandled_rejection',
source: 'unhandledrejection'
});
});
```
### Performance Impact Monitoring
```javascript
// Monitor error impact on performance
class ErrorImpactMonitor {
constructor() {
this.errorImpacts = new Map();
this.performanceBaseline = this.measureBaseline();
}
measureBaseline() {
return {
loadTime: performance.now(),
memoryUsage: performance.memory ? performance.memory.usedJSHeapSize : 0,
timing: performance.timing
};
}
recordErrorImpact(errorId, appName) {
const impact = {
errorId,
appName,
timestamp: Date.now(),
performance: {
loadTime: performance.now(),
memoryUsage: performance.memory ? performance.memory.usedJSHeapSize : 0,
timing: performance.timing
},
userExperience: {
pageVisible: !document.hidden,
userActive: this.isUserActive(),
scrollPosition: window.scrollY
}
};
this.errorImpacts.set(errorId, impact);
this.analyzeImpact(impact);
}
analyzeImpact(impact) {
const { performance: current } = impact;
const baseline = this.performanceBaseline;
const memoryIncrease = current.memoryUsage - baseline.memoryUsage;
const loadTimeIncrease = current.loadTime - baseline.loadTime;
if (memoryIncrease > 50 * 1024 * 1024) { // 50MB
console.warn('High memory impact detected after error:', impact);
}
if (loadTimeIncrease > 5000) { // 5 seconds
console.warn('Significant performance degradation after error:', impact);
}
}
isUserActive() {
// Simple user activity detection
return Date.now() - this.lastUserActivity < 30000;
}
}
```
## 🔧 Recovery Mechanisms
### Automatic Recovery Strategies
```javascript
// Comprehensive recovery system
class RecoveryManager {
constructor() {
this.recoveryStrategies = new Map();
this.setupDefaultStrategies();
}
setupDefaultStrategies() {
// Network error recovery
this.register('NetworkError', async (error, context) => {
await this.waitForConnection();
return this.reloadMicroApp(context.appName);
});
// Chunk load error recovery
this.register('ChunkLoadError', async (error, context) => {
// Clear webpack cache
if (window.__webpack_require__ && window.__webpack_require__.cache) {
delete window.__webpack_require__.cache[error.request];
}
// Reload with cache busting
return this.reloadWithCacheBust(context.appName);
});
// Script error recovery
this.register('TypeError', async (error, context) => {
// Attempt to reload dependencies
await this.reloadDependencies(context.appName);
return this.remountMicroApp(context.appName);
});
// Memory error recovery
this.register('RangeError', async (error, context) => {
// Force garbage collection
if (window.gc) window.gc();
// Reduce memory footprint
await this.reducememoryFootprint(context.appName);
return this.reloadMicroApp(context.appName);
});
}
register(errorType, strategy) {
this.recoveryStrategies.set(errorType, strategy);
}
async recover(error, context) {
const strategy = this.recoveryStrategies.get(error.name);
if (strategy) {
try {
console.log(`Attempting recovery for ${error.name} in ${context.appName}`);
const result = await strategy(error, context);
console.log(`Recovery successful for ${context.appName}`);
return result;
} catch (recoveryError) {
console.error(`Recovery failed for ${context.appName}:`, recoveryError);
return this.fallbackRecovery(context);
}
}
return this.fallbackRecovery(context);
}
async waitForConnection() {
return new Promise((resolve) => {
if (navigator.onLine) {
resolve();
} else {
const handleOnline = () => {
window.removeEventListener('online', handleOnline);
resolve();
};
window.addEventListener('online', handleOnline);
}
});
}
async reloadMicroApp(appName) {
// Unmount current instance
try {
await unmountMicroApp(appName);
} catch (error) {
console.warn(`Failed to unmount ${appName}:`, error);
}
// Reload the micro app
const appConfig = getAppConfig(appName);
return loadMicroApp(appConfig);
}
async reloadWithCacheBust(appName) {
const appConfig = getAppConfig(appName);
const cacheBustEntry = `${appConfig.entry}?t=${Date.now()}`;
return loadMicroApp({
...appConfig,
entry: cacheBustEntry
});
}
async fallbackRecovery(context) {
console.log(`Using fallback recovery for ${context.appName}`);
// Show fallback UI
showFallbackUI(context.appName);
// Report recovery failure
reportRecoveryFailure(context);
return null;
}
}
```
### User-Initiated Recovery
```jsx
// User-controlled recovery interface
const RecoveryPanel = ({ appName, error, onRecover, onDismiss }) => {
const [recovering, setRecovering] = useState(false);
const [lastAttempt, setLastAttempt] = useState(null);
const handleRecover = async (strategy) => {
setRecovering(true);
setLastAttempt(Date.now());
try {
await onRecover(strategy);
} catch (error) {
console.error('User-initiated recovery failed:', error);
} finally {
setRecovering(false);
}
};
const recoveryOptions = [
{
key: 'reload',
label: 'Reload Application',
description: 'Restart the application from scratch',
action: () => handleRecover('reload')
},
{
key: 'reset',
label: 'Reset to Default',
description: 'Clear all data and reload',
action: () => handleRecover('reset')
},
{
key: 'safe-mode',
label: 'Safe Mode',
description: 'Load with minimal features',
action: () => handleRecover('safe-mode')
}
];
return (
<div className="recovery-panel">
<div className="recovery-header">
<h3>Recovery Options for {appName}</h3>
<button onClick={onDismiss} className="close-button">×</button>
</div>
<div className="error-summary">
<p><strong>Error:</strong> {error.message}</p>
{lastAttempt && (
<p><small>Last attempt: {new Date(lastAttempt).toLocaleTimeString()}</small></p>
)}
</div>
<div className="recovery-options">
{recoveryOptions.map(option => (
<button
key={option.key}
onClick={option.action}
disabled={recovering}
className="recovery-option"
>
<div className="option-label">{option.label}</div>
<div className="option-description">{option.description}</div>
</button>
))}
</div>
{recovering && (
<div className="recovery-progress">
<div className="spinner" />
<span>Attempting recovery...</span>
</div>
)}
</div>
);
};
```
## 🎯 Best Practices Summary
### ✅ Error Handling Do's
1. **Implement global error handlers** for comprehensive coverage
2. **Use error boundaries** in each micro application
3. **Provide meaningful error messages** for users
4. **Implement graceful degradation** with fallback UIs
5. **Monitor and track errors** systematically
6. **Test error scenarios** during development
7. **Implement automatic recovery** where possible
8. **Clear error context** in reports
9. **Handle network failures** gracefully
10. **Provide user recovery options**
### ❌ Error Handling Don'ts
1. **Don't ignore errors** or fail silently
2. **Don't show technical details** to end users
3. **Don't retry indefinitely** without limits
4. **Don't block the entire application** for one micro app error
5. **Don't forget to clean up** after errors
6. **Don't rely solely on automatic recovery**
7. **Don't overwhelm users** with error messages
8. **Don't forget about memory leaks** in error scenarios
9. **Don't skip error testing** in production-like environments
10. **Don't ignore user feedback** about errors
### 🔄 Error Recovery Checklist
```javascript
// Comprehensive error handling checklist
const errorHandlingChecklist = {
prevention: {
validation: '✓ Input validation implemented',
typeChecking: '✓ TypeScript or PropTypes used',
testing: '✓ Error scenarios tested',
monitoring: '✓ Health checks in place'
},
detection: {
globalHandlers: '✓ Global error handlers set up',
boundaries: '✓ Error boundaries implemented',
logging: '✓ Comprehensive error logging',
alerting: '✓ Real-time error alerts'
},
recovery: {
gracefulDegradation: '✓ Fallback UIs implemented',
automaticRecovery: '✓ Auto-recovery strategies',
userRecovery: '✓ User-initiated recovery options',
resourceCleanup: '✓ Proper cleanup on errors'
},
learning: {
errorTracking: '✓ Error analytics in place',
trendAnalysis: '✓ Error trend monitoring',
rootCauseAnalysis: '✓ RCA process defined',
continuousImprovement: '✓ Regular error review meetings'
}
};
```
## 🔗 Related Documentation
- [Performance Optimization](/cookbook/performance) - Error impact on performance
- [Debugging](/cookbook/debugging) - Error debugging techniques
- [Style Isolation](/cookbook/style-isolation) - CSS error handling
- [Configuration](/api/configuration) - Error-related configurations
================================================
FILE: docs/cookbook/index.md
================================================
# Best Practices
This section contains practical guides and best practices for building production-ready micro-frontend applications with qiankun. These guides are based on real-world experience and common challenges faced when implementing micro-frontend architectures.
## 🎯 Overview
Building micro-frontends requires careful consideration of various aspects including architecture design, performance optimization, development workflow, and deployment strategies. These guides will help you avoid common pitfalls and implement robust solutions.
## 📚 Available Guides
### 🎨 [Style Isolation](/cookbook/style-isolation)
Learn how to prevent CSS conflicts between micro applications and implement effective style isolation strategies.
**What you'll learn:**
- CSS isolation techniques
- Shadow DOM implementation
- CSS scoping strategies
- Runtime style conflict resolution
- Best practices for component libraries
### ⚡ [Performance Optimization](/cookbook/performance)
Optimize your micro-frontend applications for better load times and runtime performance.
**What you'll learn:**
- Resource loading optimization
- Bundle splitting strategies
- Caching mechanisms
- Lazy loading techniques
- Performance monitoring
### 🛠️ [Error Handling](/cookbook/error-handling)
Implement robust error handling and recovery mechanisms for micro-frontend applications.
**What you'll learn:**
- Error boundaries implementation
- Graceful degradation strategies
- Error monitoring and reporting
- Recovery mechanisms
- User experience considerations
### 🔍 [Debugging & Development](/cookbook/debugging)
Master debugging techniques and development workflows for micro-frontend applications.
**What you'll learn:**
- Development environment setup
- Debugging tools and techniques
- Hot reload configuration
- Cross-application debugging
- Production debugging strategies
### 🚀 [Deployment Strategies](/cookbook/deployment)
Learn deployment patterns and CI/CD strategies for micro-frontend applications.
**What you'll learn:**
- Independent deployment workflows
- Version management
- Rollback strategies
- Environment configuration
- Zero-downtime deployments
### 🔄 [State Management](/cookbook/state-management)
Implement effective state management across micro applications.
**What you'll learn:**
- Cross-application state sharing
- Event-driven communication
- State synchronization
- Data flow patterns
- Store management
### 🌐 [Routing & Navigation](/cookbook/routing)
Design and implement navigation patterns for micro-frontend applications.
**What you'll learn:**
- Route configuration strategies
- Deep linking support
- Navigation guards
- History management
- SEO considerations
### 🔒 [Security](/cookbook/security)
Implement security best practices for micro-frontend architectures.
**What you'll learn:**
- Content Security Policy (CSP)
- Cross-origin resource sharing (CORS)
- Authentication and authorization
- Secure communication patterns
- Vulnerability prevention
### 🧪 [Testing Strategies](/cookbook/testing)
Develop comprehensive testing strategies for micro-frontend applications.
**What you'll learn:**
- Unit testing micro applications
- Integration testing strategies
- End-to-end testing
- Visual regression testing
- Performance testing
### 📊 [Monitoring & Analytics](/cookbook/monitoring)
Implement monitoring and analytics for micro-frontend applications.
**What you'll learn:**
- Performance monitoring
- Error tracking
- User analytics
- Application health checks
- Business metrics
## 🎯 Getting Started
If you're new to qiankun or micro-frontends, we recommend starting with these guides in order:
1. **[Style Isolation](/cookbook/style-isolation)** - Essential for preventing CSS conflicts
2. **[Error Handling](/cookbook/error-handling)** - Critical for production stability
3. **[Performance Optimization](/cookbook/performance)** - Important for user experience
4. **[Debugging & Development](/cookbook/debugging)** - Improves development productivity
## 🏗️ Common Patterns
### Micro-Frontend Architecture Patterns
```mermaid
graph TB
A[Main Application] --> B[User Management]
A --> C[Product
gitextract_dfszrfro/ ├── .changeset/ │ ├── README.md │ ├── big-cougars-draw.md │ ├── clean-walls-hang.md │ ├── clever-carpets-vanish.md │ ├── clever-dragons-ring.md │ ├── config.json │ ├── empty-jars-vanish.md │ ├── empty-lions-rescue.md │ ├── five-papayas-buy.md │ ├── forty-teachers-taste.md │ ├── four-worms-think.md │ ├── friendly-apples-design.md │ ├── giant-geckos-love.md │ ├── green-pants-remember.md │ ├── green-tools-wonder.md │ ├── hungry-needles-doubt.md │ ├── itchy-pears-retire.md │ ├── itchy-snakes-tell.md │ ├── large-jokes-smile.md │ ├── lemon-seals-juggle.md │ ├── long-flies-repair.md │ ├── loud-berries-watch.md │ ├── loud-penguins-crash.md │ ├── loud-teachers-develop.md │ ├── lovely-colts-decide.md │ ├── lucky-bikes-scream.md │ ├── metal-cougars-help.md │ ├── mighty-nails-pull.md │ ├── modern-kiwis-tap.md │ ├── ninety-rivers-check.md │ ├── orange-boats-allow.md │ ├── poor-squids-hide.md │ ├── pre.json │ ├── rare-lobsters-marry.md │ ├── real-trees-unite.md │ ├── red-islands-mate.md │ ├── red-students-run.md │ ├── rich-parents-relate.md │ ├── selfish-lamps-thank.md │ ├── serious-nails-jog.md │ ├── shaggy-shrimps-drum.md │ ├── sharp-files-raise.md │ ├── shiny-jeans-sip.md │ ├── short-kings-explain.md │ ├── shy-mayflies-shave.md │ ├── silly-books-complain.md │ ├── slow-timers-heal.md │ ├── small-experts-hug.md │ ├── smart-guests-jam.md │ ├── smart-scissors-press.md │ ├── smart-scissors-sell.md │ ├── smooth-pillows-jam.md │ ├── sour-roses-smile.md │ ├── spotty-plums-hear.md │ ├── stale-dolls-push.md │ ├── strong-rocks-sneeze.md │ ├── sweet-cars-protect.md │ ├── sweet-shoes-brake.md │ ├── swift-squids-vanish.md │ ├── tall-buttons-pretend.md │ ├── tasty-donkeys-relax.md │ ├── tender-dingos-allow.md │ ├── tender-pots-perform.md │ ├── thin-ways-allow.md │ ├── three-hornets-hammer.md │ ├── tough-beers-grow.md │ ├── tough-phones-chew.md │ ├── twelve-donkeys-help.md │ ├── warm-chefs-chew.md │ ├── wicked-icons-type.md │ ├── wise-eagles-tease.md │ └── wise-ravens-prove.md ├── .dumirc.ts ├── .editorconfig ├── .eslintignore ├── .eslintrc.cjs ├── .fatherrc.cjs ├── .github/ │ ├── CODE_OF_CONDUCT.md │ ├── CONTRIBUTING.md │ ├── ISSUE_TEMPLATE/ │ │ ├── bug_report.md │ │ ├── bug_report_cn.md │ │ ├── feature_request.md │ │ └── rfc_cn.md │ ├── PULL_REQUEST_TEMPLATE.md │ └── workflows/ │ ├── announcement-notify.yml │ ├── changeset-prerelease.yml │ ├── ci.yml │ ├── emoji-helper.yml │ ├── github-pages.yml │ ├── issue-close-inactive.yml │ ├── issue-reply.yml │ ├── publish-1.x.yml │ ├── publish-latest.yml │ └── release-notify.yml ├── .gitignore ├── .husky/ │ ├── commit-msg │ ├── pre-commit │ └── pre-push ├── .prettierignore ├── .prettierrc ├── AGENTS.md ├── LICENSE ├── README.md ├── commitlint.config.js ├── docs/ │ ├── .vitepress/ │ │ ├── config.mjs │ │ └── theme/ │ │ └── index.js │ ├── api/ │ │ ├── configuration.md │ │ ├── index.md │ │ ├── is-runtime-compatible.md │ │ ├── lifecycles.md │ │ ├── load-micro-app.md │ │ ├── register-micro-apps.md │ │ ├── start.md │ │ └── types.md │ ├── cookbook/ │ │ ├── error-handling.md │ │ ├── index.md │ │ ├── performance.md │ │ └── style-isolation.md │ ├── ecosystem/ │ │ ├── bundler-plugin.md │ │ ├── create-qiankun.md │ │ ├── index.md │ │ ├── react.md │ │ └── vue.md │ ├── faq/ │ │ └── index.md │ ├── guide/ │ │ ├── index.md │ │ ├── quick-start.md │ │ └── tutorial.md │ ├── index.md │ └── zh-CN/ │ ├── api/ │ │ ├── configuration.md │ │ ├── index.md │ │ ├── is-runtime-compatible.md │ │ ├── lifecycles.md │ │ ├── load-micro-app.md │ │ ├── register-micro-apps.md │ │ ├── start.md │ │ └── types.md │ ├── cookbook/ │ │ ├── error-handling.md │ │ ├── index.md │ │ ├── performance.md │ │ └── style-isolation.md │ ├── ecosystem/ │ │ ├── create-qiankun.md │ │ ├── index.md │ │ ├── react.md │ │ ├── vue.md │ │ └── webpack-plugin.md │ ├── faq/ │ │ └── index.md │ ├── guide/ │ │ ├── index.md │ │ ├── quick-start.md │ │ └── tutorial.md │ └── index.md ├── examples/ │ ├── main/ │ │ ├── index.html │ │ ├── package.json │ │ ├── postcss.config.js │ │ ├── src/ │ │ │ ├── App.tsx │ │ │ ├── components/ │ │ │ │ ├── Dashboard.tsx │ │ │ │ ├── Header.tsx │ │ │ │ ├── MicroAppContainer.tsx │ │ │ │ └── Sidebar.tsx │ │ │ ├── main.tsx │ │ │ ├── store/ │ │ │ │ └── qiankun.ts │ │ │ ├── styles/ │ │ │ │ └── index.css │ │ │ └── vite-env.d.ts │ │ ├── tailwind.config.js │ │ ├── tsconfig.json │ │ ├── tsconfig.node.json │ │ └── vite.config.ts │ ├── purehtml/ │ │ ├── entry.js │ │ ├── index.html │ │ └── package.json │ ├── react/ │ │ ├── .gitignore │ │ ├── README.md │ │ ├── config/ │ │ │ └── qiankunHtml.ts │ │ ├── eslint.config.js │ │ ├── index.html │ │ ├── package.json │ │ ├── src/ │ │ │ ├── App.css │ │ │ ├── App.tsx │ │ │ ├── index.css │ │ │ ├── main.tsx │ │ │ └── vite-env.d.ts │ │ ├── tsconfig.app.json │ │ ├── tsconfig.json │ │ ├── tsconfig.node.json │ │ └── vite.config.ts │ ├── vite/ │ │ ├── .eslintrc.cjs │ │ ├── .gitignore │ │ ├── index.html │ │ ├── package.json │ │ ├── src/ │ │ │ ├── App.css │ │ │ ├── App.tsx │ │ │ ├── index.css │ │ │ ├── main.tsx │ │ │ └── vite-env.d.ts │ │ ├── tsconfig.json │ │ ├── tsconfig.node.json │ │ └── vite.config.ts │ └── vue/ │ ├── .gitignore │ ├── README.md │ ├── config/ │ │ └── qiankunHtml.ts │ ├── index.html │ ├── package.json │ ├── src/ │ │ ├── App.vue │ │ ├── components/ │ │ │ └── HelloWorld.vue │ │ ├── main.ts │ │ ├── style.css │ │ └── vite-env.d.ts │ ├── tsconfig.app.json │ ├── tsconfig.json │ ├── tsconfig.node.json │ └── vite.config.ts ├── package.json ├── packages/ │ ├── bundler-plugin/ │ │ ├── .fatherrc.js │ │ ├── CHANGELOG.md │ │ ├── README-zh.md │ │ ├── README.md │ │ ├── package.json │ │ ├── src/ │ │ │ ├── index.ts │ │ │ └── webpack/ │ │ │ └── index.ts │ │ └── tests/ │ │ ├── fixtures/ │ │ │ ├── webpack4.html │ │ │ └── webpack5.html │ │ ├── plugin.test.ts │ │ ├── webpack4/ │ │ │ ├── .eslintrc.js │ │ │ ├── index.html │ │ │ ├── index.js │ │ │ ├── package.json │ │ │ └── webpack.config.js │ │ └── webpack5/ │ │ ├── .eslintrc.js │ │ ├── index.html │ │ ├── index.js │ │ ├── package.json │ │ └── webpack.config.js │ ├── create-qiankun/ │ │ ├── .fatherrc.js │ │ ├── CHANGELOG.md │ │ ├── Readme.md │ │ ├── package.json │ │ ├── src/ │ │ │ ├── index.ts │ │ │ └── shared/ │ │ │ ├── generators/ │ │ │ │ └── createVite.ts │ │ │ ├── patchers/ │ │ │ │ ├── entryFile.ts │ │ │ │ ├── index.ts │ │ │ │ ├── packageJson.ts │ │ │ │ ├── qiankunHtmlPlugin.ts │ │ │ │ └── viteConfig.ts │ │ │ ├── types.ts │ │ │ └── utils/ │ │ │ └── index.ts │ │ ├── tests/ │ │ │ ├── e2e.cli.test.ts │ │ │ └── fixtures/ │ │ │ ├── react-ts/ │ │ │ │ ├── main.tsx.txt │ │ │ │ ├── qiankunHtml.ts.txt │ │ │ │ └── vite.config.ts.txt │ │ │ └── vue-ts/ │ │ │ ├── main.ts.txt │ │ │ ├── qiankunHtml.ts.txt │ │ │ └── vite.config.ts.txt │ │ ├── tsconfig.json │ │ ├── vitest.config.ts │ │ └── vitest.e2e.config.ts │ ├── loader/ │ │ ├── .fatherrc.js │ │ ├── AGENTS.md │ │ ├── CHANGELOG.md │ │ ├── benchmarks/ │ │ │ └── parser/ │ │ │ ├── html.js │ │ │ ├── huge-html/ │ │ │ │ ├── huge-html.js │ │ │ │ ├── import-html-entry.html │ │ │ │ └── parser.html │ │ │ ├── import-html-entry.html │ │ │ ├── parser.html │ │ │ └── tern/ │ │ │ ├── html.js │ │ │ ├── import-html-entry.html │ │ │ └── parser.html │ │ ├── package.json │ │ └── src/ │ │ ├── TagTransformStream.ts │ │ ├── index.ts │ │ ├── parser.ts │ │ ├── utils.ts │ │ └── writable-dom/ │ │ ├── README.md │ │ └── index.ts │ ├── qiankun/ │ │ ├── .fatherrc.js │ │ ├── CHANGELOG.md │ │ ├── README.md │ │ ├── package.json │ │ └── src/ │ │ ├── addons/ │ │ │ ├── engineFlag.ts │ │ │ ├── index.ts │ │ │ └── runtimePublicPath.ts │ │ ├── apis/ │ │ │ ├── __tests__/ │ │ │ │ ├── effects.test.ts │ │ │ │ └── prefetch.test.ts │ │ │ ├── effects.ts │ │ │ ├── errorHandler.ts │ │ │ ├── isRuntimeCompatible.ts │ │ │ ├── loadMicroApp.ts │ │ │ ├── prefetch.ts │ │ │ └── registerMicroApps.ts │ │ ├── core/ │ │ │ └── loadApp.ts │ │ ├── error.ts │ │ ├── index.ts │ │ ├── types.ts │ │ └── utils.ts │ ├── sandbox/ │ │ ├── .fatherrc.js │ │ ├── AGENTS.md │ │ ├── CHANGELOG.md │ │ ├── package.json │ │ └── src/ │ │ ├── consts.ts │ │ ├── core/ │ │ │ ├── compartment/ │ │ │ │ ├── globalProps.ts │ │ │ │ └── index.ts │ │ │ ├── globals.ts │ │ │ ├── membrane/ │ │ │ │ ├── index.ts │ │ │ │ └── utils.ts │ │ │ ├── sandbox/ │ │ │ │ ├── StandardSandbox.ts │ │ │ │ ├── index.ts │ │ │ │ └── types.ts │ │ │ └── utils.ts │ │ ├── index.ts │ │ ├── patchers/ │ │ │ ├── consts.ts │ │ │ ├── dynamicAppend/ │ │ │ │ ├── common.ts │ │ │ │ ├── forStandardSandbox.ts │ │ │ │ ├── index.ts │ │ │ │ └── types.ts │ │ │ ├── historyListener.ts │ │ │ ├── index.ts │ │ │ ├── interval.ts │ │ │ ├── types.ts │ │ │ └── windowListener.ts │ │ └── utils.ts │ ├── shared/ │ │ ├── .fatherrc.js │ │ ├── AGENTS.md │ │ ├── CHANGELOG.md │ │ ├── package.json │ │ └── src/ │ │ ├── assets-transpilers/ │ │ │ ├── __tests__/ │ │ │ │ └── script.test.ts │ │ │ ├── index.ts │ │ │ ├── link.ts │ │ │ ├── script.ts │ │ │ ├── types.ts │ │ │ └── utils.ts │ │ ├── common.ts │ │ ├── deferred-queue/ │ │ │ └── index.ts │ │ ├── fetch-utils/ │ │ │ ├── __tests__/ │ │ │ │ ├── makeFetchCacheable.test.ts │ │ │ │ ├── makeFetchRetryable.test.ts │ │ │ │ └── makeFetchThrowable.test.ts │ │ │ ├── makeFetchCacheable.ts │ │ │ ├── makeFetchRetryable.ts │ │ │ ├── makeFetchThrowable.ts │ │ │ ├── miniLruCache.ts │ │ │ └── utils.ts │ │ ├── index.ts │ │ ├── module-resolver/ │ │ │ ├── __tests__/ │ │ │ │ ├── index.test.ts │ │ │ │ └── satisfies.test.ts │ │ │ ├── index.ts │ │ │ ├── satisfies.ts │ │ │ └── types.ts │ │ ├── reporter/ │ │ │ ├── QiankunError.ts │ │ │ ├── index.ts │ │ │ └── logger.ts │ │ ├── typings.d.ts │ │ └── utils.ts │ └── ui-bindings/ │ ├── react/ │ │ ├── .eslintrc.cjs │ │ ├── .fatherrc.js │ │ ├── CHANGELOG.md │ │ ├── README.md │ │ ├── README.zh-CN.md │ │ ├── package.json │ │ ├── src/ │ │ │ ├── ErrorBoundary.tsx │ │ │ ├── MicroApp.tsx │ │ │ ├── MicroAppLoader.tsx │ │ │ └── index.ts │ │ └── tsconfig.json │ ├── shared/ │ │ ├── .fatherrc.js │ │ ├── CHANGELOG.md │ │ ├── package.json │ │ ├── src/ │ │ │ └── index.ts │ │ └── tsconfig.json │ └── vue/ │ ├── .fatherrc.js │ ├── CHANGELOG.md │ ├── README.md │ ├── README.zh-CN.md │ ├── package.json │ ├── src/ │ │ ├── ErrorBoundary.ts │ │ ├── MicroApp.ts │ │ ├── MicroAppLoader.ts │ │ └── index.ts │ └── tsconfig.json ├── pnpm-workspace.yaml ├── scripts/ │ └── generate-release-notes.mjs ├── tsconfig.eslint.json ├── tsconfig.json ├── vitest.config.ts └── vitest.workspace.ts
SYMBOL INDEX (283 symbols across 81 files)
FILE: docs/.vitepress/theme/index.js
method enhanceApp (line 7) | enhanceApp({ app, router }) {
method setup (line 17) | setup() {
function renderMermaidCharts (line 27) | function renderMermaidCharts() {
FILE: examples/main/src/App.tsx
function App (line 10) | function App() {
FILE: examples/main/src/components/Dashboard.tsx
function Dashboard (line 29) | function Dashboard() {
FILE: examples/main/src/components/Header.tsx
function Header (line 18) | function Header() {
FILE: examples/main/src/components/MicroAppContainer.tsx
function MicroAppContainer (line 15) | function MicroAppContainer() {
FILE: examples/main/src/components/Sidebar.tsx
function Sidebar (line 28) | function Sidebar() {
FILE: examples/main/src/store/qiankun.ts
type GlobalState (line 3) | interface GlobalState {
type QiankunStore (line 12) | interface QiankunStore {
FILE: examples/react/config/qiankunHtml.ts
function qiankunHtmlPlugin (line 4) | function qiankunHtmlPlugin(): PluginOption {
function isQiankunBuild (line 16) | function isQiankunBuild(ctx: IndexHtmlTransformContext): boolean {
function rewriteSystemImport (line 20) | function rewriteSystemImport(script: string): string {
function transformHtml (line 38) | function transformHtml(html: string): string {
FILE: examples/react/src/App.tsx
function App (line 6) | function App() {
FILE: examples/react/src/main.tsx
type Window (line 7) | interface Window {
function render (line 15) | function render(props: { container?: Element } = {}) {
function bootstrap (line 27) | function bootstrap() {
function mount (line 32) | function mount(props: { container?: Element }) {
function unmount (line 38) | function unmount(props: { container?: Element }) {
FILE: examples/vite/src/App.tsx
function App (line 6) | function App() {
FILE: examples/vite/src/main.tsx
function bootstrap (line 6) | async function bootstrap() {
function mount (line 12) | async function mount(props: any) {
function unmount (line 26) | async function unmount(props: any) {
FILE: examples/vue/config/qiankunHtml.ts
function qiankunHtmlPlugin (line 4) | function qiankunHtmlPlugin(): PluginOption {
function isQiankunBuild (line 16) | function isQiankunBuild(ctx: IndexHtmlTransformContext): boolean {
function rewriteSystemImport (line 20) | function rewriteSystemImport(script: string): string {
function transformHtml (line 38) | function transformHtml(html: string): string {
FILE: examples/vue/src/main.ts
type Window (line 6) | interface Window {
function render (line 14) | function render(props: { container?: Element } = {}) {
function bootstrap (line 22) | function bootstrap() {
function mount (line 27) | function mount(props: { container?: Element }) {
function unmount (line 33) | function unmount(props: { container?: Element }) {
FILE: packages/bundler-plugin/src/webpack/index.ts
type QiankunWebpackPluginOptions (line 5) | interface QiankunWebpackPluginOptions {
type Chunk (line 9) | interface Chunk {
type Entrypoint (line 14) | interface Entrypoint {
type PackageJson (line 20) | interface PackageJson {
type HtmlTagObject (line 24) | interface HtmlTagObject {
type HtmlWebpackPluginData (line 32) | interface HtmlWebpackPluginData {
type HtmlWebpackPluginHooks (line 43) | interface HtmlWebpackPluginHooks {
type HtmlWebpackPluginStatic (line 52) | interface HtmlWebpackPluginStatic {
class QiankunWebpackPlugin (line 56) | class QiankunWebpackPlugin {
method constructor (line 61) | constructor(options: QiankunWebpackPluginOptions = {}) {
method getPackageName (line 65) | private static getPackageName(): string {
method apply (line 78) | apply(compiler: Compiler): void {
method configureOutput (line 83) | private configureOutput(compiler: Compiler): void {
method registerHtmlProcessing (line 105) | private registerHtmlProcessing(compiler: Compiler): void {
method findHtmlWebpackPlugin (line 115) | private findHtmlWebpackPlugin(compiler: Compiler): HtmlWebpackPluginSt...
method hookIntoHtmlWebpackPlugin (line 128) | private hookIntoHtmlWebpackPlugin(compilation: Compilation, HtmlWebpac...
method findEntryScriptSrc (line 168) | private findEntryScriptSrc(compilation: Compilation, htmlOutputName: s...
method getEntryChunkFile (line 192) | private getEntryChunkFile(entrypoint: Entrypoint): string | null {
method matchEntryScript (line 234) | private matchEntryScript(scriptSrc: string, entryFile: string): boolean {
FILE: packages/bundler-plugin/tests/plugin.test.ts
function normalizeHtml (line 6) | function normalizeHtml(html: string): string {
function readFixture (line 16) | function readFixture(name: string): string {
FILE: packages/create-qiankun/src/index.ts
function main (line 18) | async function main() {
FILE: packages/create-qiankun/src/shared/generators/createVite.ts
function generateViteApp (line 5) | async function generateViteApp(targetDir: string, appName: string, templ...
FILE: packages/create-qiankun/src/shared/patchers/entryFile.ts
function writeEntryFile (line 6) | async function writeEntryFile(appRoot: string, appName: string, template...
function writeReactEntry (line 17) | async function writeReactEntry(appRoot: string, appName: string, isTs: b...
function writeVueEntry (line 81) | async function writeVueEntry(appRoot: string, appName: string, isTs: boo...
FILE: packages/create-qiankun/src/shared/patchers/index.ts
function patchViteSubApp (line 7) | async function patchViteSubApp(appRoot: string, appName: string, templat...
FILE: packages/create-qiankun/src/shared/patchers/packageJson.ts
constant LEGACY_PLUGIN_VERSION (line 6) | const LEGACY_PLUGIN_VERSION = '^5.4.2';
constant CHEERIO_VERSION (line 7) | const CHEERIO_VERSION = '^1.0.0';
constant QIANKUN_VERSION (line 8) | const QIANKUN_VERSION = '^3.0.0-rc.0';
constant QIANKUN_REACT_VERSION (line 9) | const QIANKUN_REACT_VERSION = '^0.0.1-rc.0';
constant QIANKUN_VUE_VERSION (line 10) | const QIANKUN_VUE_VERSION = '^0.0.1-rc.0';
function patchPackageJson (line 12) | async function patchPackageJson(appRoot: string, appName: string, templa...
FILE: packages/create-qiankun/src/shared/patchers/qiankunHtmlPlugin.ts
function writeQiankunHtmlPlugin (line 6) | async function writeQiankunHtmlPlugin(appRoot: string, template: ViteTem...
function getTypeScriptPluginContent (line 18) | function getTypeScriptPluginContent(): string {
function getJavaScriptPluginContent (line 77) | function getJavaScriptPluginContent(): string {
FILE: packages/create-qiankun/src/shared/patchers/viteConfig.ts
function writeViteConfig (line 6) | async function writeViteConfig(appRoot: string, template: ViteTemplate):...
function getTypeScriptConfig (line 15) | function getTypeScriptConfig(template: ViteTemplate): string {
function getJavaScriptConfig (line 47) | function getJavaScriptConfig(template: ViteTemplate): string {
FILE: packages/create-qiankun/src/shared/types.ts
type ViteTemplate (line 1) | enum ViteTemplate {
type TemplateOption (line 8) | interface TemplateOption {
type PromptAnswers (line 20) | interface PromptAnswers {
function isReactTemplate (line 25) | function isReactTemplate(template: ViteTemplate): boolean {
function isTypeScriptTemplate (line 29) | function isTypeScriptTemplate(template: ViteTemplate): boolean {
FILE: packages/create-qiankun/src/shared/utils/index.ts
function isDirectory (line 4) | function isDirectory(targetPath: string): boolean {
function isFile (line 12) | function isFile(targetPath: string): boolean {
function detectWorkspaceRoot (line 20) | function detectWorkspaceRoot(targetDir: string): string | null {
FILE: packages/create-qiankun/tests/e2e.cli.test.ts
constant CLI_PATH (line 9) | const CLI_PATH = path.resolve(__dirname, '../dist/index.js');
constant FIXTURES_PATH (line 10) | const FIXTURES_PATH = path.resolve(__dirname, 'fixtures');
constant E2E_TIMEOUT (line 11) | const E2E_TIMEOUT = process.env.E2E_TIMEOUT ? parseInt(process.env.E2E_T...
constant APP_NAME_PLACEHOLDER (line 13) | const APP_NAME_PLACEHOLDER = '{{APP_NAME}}';
function runCli (line 15) | async function runCli(cwd: string, appName: string, template: string): P...
function installAndBuild (line 22) | async function installAndBuild(appPath: string): Promise<void> {
function normalizeContent (line 27) | function normalizeContent(content: string, appName: string): string {
function loadFixture (line 31) | async function loadFixture(template: string, fileName: string): Promise<...
function assertFileMatchesFixture (line 36) | async function assertFileMatchesFixture(
function assertQiankunHtml (line 49) | function assertQiankunHtml(html: string): void {
FILE: packages/loader/src/TagTransformStream.ts
type TagReplacement (line 1) | type TagReplacement = {
type AutoCompleteTags (line 8) | type AutoCompleteTags = {
function createTagTransformStream (line 13) | function createTagTransformStream(
FILE: packages/loader/src/index.ts
type HTMLEntry (line 13) | type HTMLEntry = string;
type Entry (line 16) | type Entry = HTMLEntry;
type LoaderOpts (line 24) | type LoaderOpts = {
function loadEntry (line 44) | async function loadEntry<T>(
FILE: packages/loader/src/parser.ts
type NormalizedEntry (line 1) | type NormalizedEntry = {
function getDocResources (line 6) | function getDocResources(container: Document) {
function parseHTML (line 16) | function parseHTML(htmlContent: string): NormalizedEntry {
FILE: packages/loader/src/utils.ts
function isUrlHasOwnProtocol (line 1) | function isUrlHasOwnProtocol(url: string): boolean {
FILE: packages/loader/src/writable-dom/index.ts
type Writable (line 1) | type Writable = {
type WritableDOM (line 36) | type WritableDOM = {
function writableDOM (line 48) | function writableDOM(
function isBlocking (line 170) | function isBlocking(node: any): node is HTMLElement {
function isSyncScript (line 180) | function isSyncScript(node: any): node is HTMLScriptElement {
function getPreloadLink (line 186) | function getPreloadLink(node: any) {
function appendInlineTextIfNeeded (line 237) | function appendInlineTextIfNeeded(
function isInlineHost (line 258) | function isInlineHost(node: Node) {
FILE: packages/qiankun/src/addons/engineFlag.ts
function getAddOn (line 8) | function getAddOn(global: Window): LifeCycles<ObjectType> {
FILE: packages/qiankun/src/addons/index.ts
function getAddOns (line 11) | function getAddOns<T extends ObjectType>(global: WindowProxy, publicPath...
FILE: packages/qiankun/src/addons/runtimePublicPath.ts
function getAddOn (line 9) | function getAddOn(global: Window, publicPath = '/'): LifeCycles<ObjectTy...
FILE: packages/qiankun/src/apis/effects.ts
function setDefaultMountApp (line 17) | function setDefaultMountApp(defaultAppLink: string): void {
function runAfterFirstMounted (line 33) | function runAfterFirstMounted(effect: () => void): void {
FILE: packages/qiankun/src/apis/loadMicroApp.ts
function loadMicroApp (line 12) | function loadMicroApp<T extends ObjectType>(
FILE: packages/qiankun/src/apis/prefetch.ts
type NetworkInformation (line 9) | interface NetworkInformation {
type Navigator (line 15) | interface Navigator {
method timeRemaining (line 29) | timeRemaining() {
function prefetch (line 48) | async function prefetch(entry: string, fetch: typeof window.fetch = wind...
type PrefetchStrategy (line 103) | type PrefetchStrategy =
function prefetchApps (line 115) | function prefetchApps(apps: AppMetadata[], fetch: typeof window.fetch = ...
FILE: packages/qiankun/src/apis/registerMicroApps.ts
function registerMicroApps (line 16) | function registerMicroApps<T extends ObjectType>(apps: Array<Registrable...
function start (line 46) | function start(opts: StartOpts = {}) {
FILE: packages/qiankun/src/core/loadApp.ts
type ParcelConfigObjectGetter (line 33) | type ParcelConfigObjectGetter = (remountContainer: HTMLElement) => Parce...
function loadApp (line 35) | async function loadApp<T extends ObjectType>(
function initContainer (line 191) | function initContainer(
function clearContainer (line 213) | function clearContainer(container: HTMLElement): void {
function execHooksChain (line 219) | function execHooksChain<T extends ObjectType>(
function getLifecyclesFromExports (line 231) | function getLifecyclesFromExports(
function calcPublicPath (line 272) | function calcPublicPath(entry: string): string {
function removeWebpackChunkCacheWhenAppHaveMultiInstance (line 289) | function removeWebpackChunkCacheWhenAppHaveMultiInstance(appName: string...
type Window (line 302) | interface Window {
function genInstanceId (line 308) | function genInstanceId(appName: string): number {
FILE: packages/qiankun/src/error.ts
class QiankunError (line 1) | class QiankunError extends Error {
method constructor (line 2) | constructor(message: string) {
FILE: packages/qiankun/src/types.ts
type Window (line 10) | interface Window {
type ObjectType (line 19) | type ObjectType = Record<string, unknown>;
type HTMLEntry (line 21) | type HTMLEntry = string;
type AppMetadata (line 23) | type AppMetadata = {
type LoadableApp (line 31) | type LoadableApp<T extends ObjectType> = AppMetadata & {
type RegistrableApp (line 39) | type RegistrableApp<T extends ObjectType> = LoadableApp<T> & {
type AppConfiguration (line 44) | type AppConfiguration = Partial<Pick<LoaderOpts, 'fetch' | 'streamTransf...
type LifeCycleFn (line 49) | type LifeCycleFn<T extends ObjectType> = (app: LoadableApp<T>, global: W...
type LifeCycles (line 50) | type LifeCycles<T extends ObjectType> = {
type MicroApp (line 58) | type MicroApp = Parcel;
type ExtraProps (line 60) | type ExtraProps = {
type FlattenArray (line 63) | type FlattenArray<T> = T extends Array<infer U> ? U : T;
type FlattenArrayValue (line 64) | type FlattenArrayValue<T> = {
type MicroAppLifeCycles (line 68) | type MicroAppLifeCycles = FlattenArrayValue<ParcelLifeCycles<ExtraProps>>;
FILE: packages/qiankun/src/utils.ts
function toArray (line 5) | function toArray<T>(array: T | T[]): T[] {
function getXPathForElement (line 14) | function getXPathForElement(el: Node, document: Document): string | void {
function getContainerXPath (line 47) | function getContainerXPath(container: HTMLElement): string | void {
function performanceGetEntriesByName (line 59) | function performanceGetEntriesByName(markName: string, type?: string) {
function performanceMark (line 67) | function performanceMark(markName: string) {
function performanceMeasure (line 73) | function performanceMeasure(measureName: string, markName: string) {
function getPureHTMLStringWithoutScripts (line 81) | async function getPureHTMLStringWithoutScripts(entry: string, fetch: typ...
FILE: packages/sandbox/src/core/compartment/globalProps.ts
function getGlobalProp (line 5) | function getGlobalProp(global: WindowProxy, useFirstGlobalProp = false) {
function noteGlobalProps (line 34) | function noteGlobalProps(global: WindowProxy) {
function shouldSkipProperty (line 50) | function shouldSkipProperty(global: WindowProxy, p: string | number): bo...
FILE: packages/sandbox/src/core/compartment/index.ts
type CompartmentGlobalId (line 14) | type CompartmentGlobalId = `${typeof compartmentGlobalIdPrefix}${string}...
type Window (line 17) | interface Window {
class Compartment (line 24) | class Compartment {
method constructor (line 34) | constructor(globalProxy: WindowProxy) {
method globalThis (line 45) | get globalThis(): WindowProxy {
method addConstantIntrinsicNames (line 49) | protected addConstantIntrinsicNames(intrinsics: string[]): void {
method makeEvaluateFactory (line 53) | makeEvaluateFactory(source: string, sourceURL?: string): string {
FILE: packages/sandbox/src/core/membrane/index.ts
type Window (line 18) | interface Window {
type MembraneTarget (line 23) | type MembraneTarget = Record<string | symbol, unknown>;
type Endowments (line 24) | type Endowments = Record<string, number | string | CallableFunction | Pr...
type SymbolTarget (line 26) | type SymbolTarget = 'target' | 'globalContext';
class Membrane (line 70) | class Membrane {
method constructor (line 81) | constructor(
method addIntrinsics (line 246) | addIntrinsics(
method lock (line 257) | lock() {
method unlock (line 261) | unlock() {
function createMembraneTarget (line 266) | function createMembraneTarget(
function uniq (line 324) | function uniq(array: Array<string | symbol>) {
FILE: packages/sandbox/src/core/membrane/utils.ts
function rebindTarget2Fn (line 6) | function rebindTarget2Fn<T>(target: unknown, fn: T, receiver: unknown): T {
FILE: packages/sandbox/src/core/sandbox/StandardSandbox.ts
class StandardSandbox (line 13) | class StandardSandbox extends Compartment implements Sandbox {
method constructor (line 20) | constructor(name: string, globals: Endowments, incubatorContext: Windo...
method latestSetProp (line 97) | get latestSetProp() {
method addIntrinsics (line 101) | addIntrinsics(intrinsics: Record<string, PropertyDescriptor>) {
method active (line 105) | active() {
method inactive (line 109) | inactive() {
FILE: packages/sandbox/src/core/sandbox/index.ts
function createSandboxContainer (line 19) | function createSandboxContainer(
FILE: packages/sandbox/src/core/sandbox/types.ts
type SandboxType (line 8) | enum SandboxType {
type Sandbox (line 13) | interface Sandbox extends Compartment {
FILE: packages/sandbox/src/core/utils.ts
function array2TruthyObject (line 9) | function array2TruthyObject(array: string[]): Record<string, true> {
FILE: packages/sandbox/src/patchers/dynamicAppend/common.ts
constant SCRIPT_TAG_NAME (line 11) | const SCRIPT_TAG_NAME = 'SCRIPT';
constant LINK_TAG_NAME (line 12) | const LINK_TAG_NAME = 'LINK';
constant STYLE_TAG_NAME (line 13) | const STYLE_TAG_NAME = 'STYLE';
type DynamicDomMutationTarget (line 19) | type DynamicDomMutationTarget = 'head' | 'body';
type HTMLLinkElement (line 22) | interface HTMLLinkElement {
type HTMLStyleElement (line 27) | interface HTMLStyleElement {
type Function (line 32) | interface Function {
function isHijackingTag (line 45) | function isHijackingTag(tagName?: string) {
function isStyledComponentsLike (line 59) | function isStyledComponentsLike(element: HTMLStyleElement): boolean {
function calcAppCount (line 65) | function calcAppCount(
function isAllAppsUnmounted (line 85) | function isAllAppsUnmounted(): boolean {
function recordStyledComponentsCSSRules (line 102) | function recordStyledComponentsCSSRules(styleElements: HTMLStyleElement[...
function getStyledElementCSSRules (line 118) | function getStyledElementCSSRules(styledElement: HTMLStyleElement): CSSR...
function getOverwrittenAppendChildOrInsertBefore (line 122) | function getOverwrittenAppendChildOrInsertBefore(
function getNewRemoveChild (line 255) | function getNewRemoveChild(
function rebuildCSSRules (line 307) | function rebuildCSSRules(
FILE: packages/sandbox/src/patchers/dynamicAppend/forStandardSandbox.ts
type HTMLElement (line 29) | interface HTMLElement {
type Window (line 33) | interface Window {
type Document (line 37) | interface Document {
function patchDocument (line 58) | function patchDocument(sandbox: Sandbox, getContainer: () => HTMLElement...
function patchDocumentHeadAndBodyMethods (line 180) | function patchDocumentHeadAndBodyMethods(container: HTMLElement): typeof...
function patchDOMPrototypeFns (line 241) | function patchDOMPrototypeFns(): typeof noop {
function patchStandardSandbox (line 310) | function patchStandardSandbox(
FILE: packages/sandbox/src/patchers/dynamicAppend/types.ts
type SandboxConfig (line 9) | type SandboxConfig = {
FILE: packages/sandbox/src/patchers/historyListener.ts
type Window (line 9) | interface Window {
function patch (line 16) | function patch() {
FILE: packages/sandbox/src/patchers/index.ts
function patchAtBootstrapping (line 14) | function patchAtBootstrapping(
function patchAtMounting (line 28) | function patchAtMounting(
FILE: packages/sandbox/src/patchers/interval.ts
function patch (line 9) | function patch(global: Window) {
FILE: packages/sandbox/src/patchers/types.ts
type Rebuild (line 5) | type Rebuild = (container: HTMLElement) => Promise<void>;
type Free (line 6) | type Free = () => Rebuild;
type Patch (line 7) | type Patch = () => Free;
FILE: packages/sandbox/src/patchers/windowListener.ts
type ListenerMapObject (line 10) | type ListenerMapObject = {
constant DEFAULT_OPTIONS (line 16) | const DEFAULT_OPTIONS: AddEventListenerOptions = { capture: false, once:...
function patch (line 75) | function patch(global: WindowProxy): Free {
FILE: packages/sandbox/src/utils.ts
function isConstructable (line 12) | function isConstructable(fn: CallableFunction): fn is CallableFunction {
function isCallable (line 36) | function isCallable(fn: unknown): fn is CallableFunction {
function isPropertyFrozen (line 55) | function isPropertyFrozen(target: object, p?: PropertyKey): boolean {
function isBoundedFunction (line 81) | function isBoundedFunction(fn: CallableFunction): fn is CallableFunction {
FILE: packages/shared/src/assets-transpilers/__tests__/script.test.ts
class MockSandbox (line 5) | class MockSandbox {
method makeEvaluateFactory (line 6) | makeEvaluateFactory(source: string, sourceURL?: string): string {
FILE: packages/shared/src/assets-transpilers/index.ts
function transpileAssets (line 16) | function transpileAssets<T extends Node>(node: T, baseURI: string, opts:...
FILE: packages/shared/src/assets-transpilers/link.ts
type PreTranspileResult (line 13) | type PreTranspileResult =
function transpileLink (line 96) | function transpileLink(
FILE: packages/shared/src/assets-transpilers/script.ts
type PreTranspileResult (line 23) | type PreTranspileResult =
function transpileScript (line 69) | function transpileScript(
FILE: packages/shared/src/assets-transpilers/types.ts
type BaseTranspilerOpts (line 9) | type BaseTranspilerOpts = BaseLoaderOpts & {
type AssetsTranspilerOpts (line 16) | type AssetsTranspilerOpts = BaseTranspilerOpts;
type NodeTransformer (line 18) | type NodeTransformer = <T extends Node>(node: T, opts: Omit<AssetsTransp...
type ScriptTranspilerOpts (line 20) | type ScriptTranspilerOpts = AssetsTranspilerOpts &
type Mode (line 26) | enum Mode {
FILE: packages/shared/src/common.ts
type BaseLoaderOpts (line 1) | type BaseLoaderOpts = {
FILE: packages/shared/src/deferred-queue/index.ts
function prepareDeferredQueue (line 3) | function prepareDeferredQueue(deferredQueue: Array<Deferred<void>>): {
FILE: packages/shared/src/fetch-utils/miniLruCache.ts
class LRUCache (line 1) | class LRUCache<K, V> {
method constructor (line 5) | constructor(capacity: number) {
method get (line 10) | get(key: K): V | undefined {
method set (line 19) | set(key: K, value: V): void {
method delete (line 30) | delete(key: K): void {
FILE: packages/shared/src/fetch-utils/utils.ts
type Fetch (line 1) | type Fetch = typeof window.fetch;
FILE: packages/shared/src/module-resolver/index.ts
type HTMLElement (line 5) | interface HTMLElement {
type Dependency (line 10) | type Dependency = {
type NormalizedDependency (line 17) | type NormalizedDependency = {
type DependencyMap (line 21) | type DependencyMap = {
function moduleResolver (line 27) | function moduleResolver(
function findDependency (line 63) | function findDependency(
function normalizeDependencies (line 87) | function normalizeDependencies(dependencies: DependencyMap['dependencies...
FILE: packages/shared/src/module-resolver/satisfies.ts
function satisfies (line 10) | function satisfies(version: string, range: string): boolean {
FILE: packages/shared/src/module-resolver/types.ts
type MatchResult (line 5) | type MatchResult = {
FILE: packages/shared/src/reporter/QiankunError.ts
class QiankunError (line 1) | class QiankunError extends Error {
method constructor (line 2) | constructor(message: string) {
FILE: packages/shared/src/reporter/logger.ts
function warn (line 1) | function warn(msg: string, ...args: unknown[]) {
FILE: packages/shared/src/typings.d.ts
type Priority (line 1) | type Priority = 'high' | 'low' | 'auto';
type HTMLScriptElement (line 3) | interface HTMLScriptElement {
type RequestInit (line 7) | interface RequestInit {
FILE: packages/shared/src/utils.ts
class Deferred (line 10) | class Deferred<T> {
method constructor (line 19) | constructor() {
method isSettled (line 32) | isSettled(): boolean {
function waitUntilSettled (line 37) | async function waitUntilSettled(promise: Promise<void>): Promise<void> {
function resolveUrl (line 47) | function resolveUrl(uri: string, baseURI: string): string {
function isRuntimeCompatible (line 64) | function isRuntimeCompatible(): boolean {
FILE: packages/ui-bindings/react/src/MicroApp.tsx
type Props (line 15) | type Props = SharedProps & SharedSlots<React.ReactNode> & Record<string,...
function useDeepCompare (line 17) | function useDeepCompare<T>(value: T): T {
FILE: packages/ui-bindings/shared/src/index.ts
type MicroAppType (line 6) | type MicroAppType = {
type SharedProps (line 12) | type SharedProps = {
type SharedSlots (line 25) | type SharedSlots<T> = {
function mountMicroApp (line 34) | async function mountMicroApp({
function updateMicroApp (line 104) | function updateMicroApp({
function unmountMicroApp (line 154) | async function unmountMicroApp(microApp: MicroAppType) {
FILE: packages/ui-bindings/vue/src/ErrorBoundary.ts
method render (line 10) | render() {
FILE: packages/ui-bindings/vue/src/MicroApp.ts
method setup (line 62) | setup(props, { slots }) {
method render (line 182) | render() {
FILE: packages/ui-bindings/vue/src/MicroAppLoader.ts
method render (line 11) | render() {
FILE: scripts/generate-release-notes.mjs
constant ROOT (line 16) | const ROOT = resolve(fileURLToPath(import.meta.url), '../..');
function discoverPackageDirs (line 22) | function discoverPackageDirs() {
function extractLatestEntry (line 72) | function extractLatestEntry(changelogContent) {
Condensed preview — 382 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (1,589K chars).
[
{
"path": ".changeset/README.md",
"chars": 510,
"preview": "# Changesets\n\nHello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that wo"
},
{
"path": ".changeset/big-cougars-draw.md",
"chars": 107,
"preview": "---\n\"@qiankunjs/sandbox\": patch\n---\n\nfeat(sandbox): use cloneNode api instead of importNode for compatible\n"
},
{
"path": ".changeset/clean-walls-hang.md",
"chars": 78,
"preview": "---\n\"@qiankunjs/bundler-plugin\": patch\n---\n\nfix: move cheerio to dependencies\n"
},
{
"path": ".changeset/clever-carpets-vanish.md",
"chars": 129,
"preview": "---\n\"@qiankunjs/sandbox\": patch\n---\n\nRevert \"fix(sandbox): non-hijacking elements should be appended to global document "
},
{
"path": ".changeset/clever-dragons-ring.md",
"chars": 176,
"preview": "---\n\"qiankun\": patch\n\"@qiankunjs/loader\": patch\n\"@qiankunjs/sandbox\": patch\n\"@qiankunjs/shared\": patch\n---\n\n✨support to "
},
{
"path": ".changeset/config.json",
"chars": 384,
"preview": "{\n \"$schema\": \"https://unpkg.com/@changesets/config@2.29.5/schema.json\",\n \"changelog\": \"@changesets/cli/changelog\",\n "
},
{
"path": ".changeset/empty-jars-vanish.md",
"chars": 66,
"preview": "---\n'create-qiankun': minor\n---\n\nfeat: introduce qiankun scaffold\n"
},
{
"path": ".changeset/empty-lions-rescue.md",
"chars": 73,
"preview": "---\n'@qiankunjs/shared': patch\n---\n\nfix: remove inline script source-url\n"
},
{
"path": ".changeset/five-papayas-buy.md",
"chars": 103,
"preview": "---\n\"qiankun\": patch\n\"@qiankunjs/shared\": patch\n---\n\nfix: optimize types and add a warning for preload\n"
},
{
"path": ".changeset/forty-teachers-taste.md",
"chars": 125,
"preview": "---\n'@qiankunjs/ui-shared': patch\n'@qiankunjs/react': patch\n'@qiankunjs/vue': patch\n---\n\nfeat: refactor the code of micr"
},
{
"path": ".changeset/four-worms-think.md",
"chars": 137,
"preview": "---\n\"@qiankunjs/sandbox\": patch\n\"@qiankunjs/shared\": patch\n---\n\nfeat(sandbox): support dynamic sync scripts executed by "
},
{
"path": ".changeset/friendly-apples-design.md",
"chars": 150,
"preview": "---\n\"qiankun\": patch\n\"@qiankunjs/react\": patch\n\"@qiankunjs/ui-shared\": patch\n\"@qiankunjs/vue\": patch\n---\n\nfix: remove un"
},
{
"path": ".changeset/giant-geckos-love.md",
"chars": 85,
"preview": "---\n\"@qiankunjs/sandbox\": patch\n---\n\nfix: double quote link element href as selector\n"
},
{
"path": ".changeset/green-pants-remember.md",
"chars": 146,
"preview": "---\n\"@qiankunjs/loader\": patch\n\"qiankun\": patch\n\"@qiankunjs/shared\": patch\n---\n\nfeat: add isRuntimeCompatible api to che"
},
{
"path": ".changeset/green-tools-wonder.md",
"chars": 90,
"preview": "---\n\"@qiankunjs/shared\": patch\n---\n\n🐛fix findDependency logic while peerDeps is undefined\n"
},
{
"path": ".changeset/hungry-needles-doubt.md",
"chars": 172,
"preview": "---\n\"@qiankunjs/loader\": patch\n\"@qiankunjs/sandbox\": patch\n\"@qiankunjs/shared\": patch\n---\n\nfeat: support defer scripts a"
},
{
"path": ".changeset/itchy-pears-retire.md",
"chars": 119,
"preview": "---\n\"qiankun\": patch\n\"@qiankunjs/sandbox\": patch\n---\n\nfeat: pass container with parameters rather than getter function\n"
},
{
"path": ".changeset/itchy-snakes-tell.md",
"chars": 110,
"preview": "---\n\"qiankun\": patch\n\"@qiankunjs/sandbox\": patch\n---\n\nfeat(loader): add lru cache for assets fetch by default\n"
},
{
"path": ".changeset/large-jokes-smile.md",
"chars": 95,
"preview": "---\n\"@qiankunjs/shared\": patch\n---\n\n🐛fix preload is invalid while reused dependency is working\n"
},
{
"path": ".changeset/lemon-seals-juggle.md",
"chars": 116,
"preview": "---\n\"qiankun\": patch\n\"@qiankunjs/shared\": patch\n---\n\nfeat(shared): introduce retryable and throwable to fetch-utils\n"
},
{
"path": ".changeset/long-flies-repair.md",
"chars": 52,
"preview": "---\n\"@qiankunjs/sandbox\": patch\n---\n\n🔀 merge master\n"
},
{
"path": ".changeset/loud-berries-watch.md",
"chars": 91,
"preview": "---\n\"@qiankunjs/shared\": patch\n---\n\nrefactor(shared): replace semver with compare-versions\n"
},
{
"path": ".changeset/loud-penguins-crash.md",
"chars": 147,
"preview": "---\n\"@qiankunjs/sandbox\": patch\n---\n\nfeat: set proxy appendChild/insertBefore method for every sandbox rather than modif"
},
{
"path": ".changeset/loud-teachers-develop.md",
"chars": 58,
"preview": "---\n\"qiankun\": patch\n---\n\nfeat: enable sandbox by default\n"
},
{
"path": ".changeset/lovely-colts-decide.md",
"chars": 66,
"preview": "---\n\"create-qiankun\": patch\n---\n\nfeat: introduce qiankun scaffold\n"
},
{
"path": ".changeset/lucky-bikes-scream.md",
"chars": 76,
"preview": "---\n\"@qiankunjs/bundler-plugin\": patch\n---\n\nfix: mv webpack-sources to deps\n"
},
{
"path": ".changeset/metal-cougars-help.md",
"chars": 91,
"preview": "---\n\"@qiankunjs/sandbox\": patch\n---\n\n🐛parallel sandbox should use different compartment id\n"
},
{
"path": ".changeset/mighty-nails-pull.md",
"chars": 112,
"preview": "---\n\"@qiankunjs/loader\": patch\n\"@qiankunjs/shared\": patch\n---\n\nfeat(loader): compatible with defer entry script\n"
},
{
"path": ".changeset/modern-kiwis-tap.md",
"chars": 83,
"preview": "---\n\"@qiankunjs/bundler-plugin\": patch\n---\n\nfeat: introduce qiankun webpack plugin\n"
},
{
"path": ".changeset/ninety-rivers-check.md",
"chars": 98,
"preview": "---\n\"@qiankunjs/loader\": patch\n\"qiankun\": patch\n---\n\nfeat: add transformer options for app loader\n"
},
{
"path": ".changeset/orange-boats-allow.md",
"chars": 153,
"preview": "---\n\"qiankun\": patch\n\"@qiankunjs/shared\": patch\n---\n\nfeat: remove webpack chunk cache attributes just while there are mu"
},
{
"path": ".changeset/poor-squids-hide.md",
"chars": 106,
"preview": "---\n\"qiankun\": patch\n---\n\nfix(qiankun): should remove internal cache of loadMicroApp while loading failed\n"
},
{
"path": ".changeset/pre.json",
"chars": 2167,
"preview": "{\n \"mode\": \"pre\",\n \"tag\": \"rc\",\n \"initialVersions\": {\n \"@qiankunjs/loader\": \"0.0.1\",\n \"qiankun\": \"3.0.0\",\n \""
},
{
"path": ".changeset/rare-lobsters-marry.md",
"chars": 42,
"preview": "---\n\"qiankun\": patch\n---\n\n🐛 fix tsc error\n"
},
{
"path": ".changeset/real-trees-unite.md",
"chars": 124,
"preview": "---\n\"@qiankunjs/sandbox\": patch\n---\n\nfix(sandbox): compatible with dynamically appending stylesheets to detached contain"
},
{
"path": ".changeset/red-islands-mate.md",
"chars": 135,
"preview": "---\n\"@qiankunjs/loader\": patch\n\"qiankun\": patch\n---\n\nfeat(loader): supports passing Response as entry parameter for load"
},
{
"path": ".changeset/red-students-run.md",
"chars": 182,
"preview": "---\n\"@qiankunjs/loader\": patch\n\"qiankun\": patch\n\"@qiankunjs/sandbox\": patch\n\"@qiankunjs/react\": patch\n---\n\nfix(sandbox):"
},
{
"path": ".changeset/rich-parents-relate.md",
"chars": 83,
"preview": "---\n\"@qiankunjs/vue\": patch\n---\n\nfix(vue): add unmount hook to unmount application\n"
},
{
"path": ".changeset/selfish-lamps-thank.md",
"chars": 87,
"preview": "---\n\"qiankun\": patch\n---\n\nfix: should re-init container while app remounted from cache\n"
},
{
"path": ".changeset/serious-nails-jog.md",
"chars": 128,
"preview": "---\n\"@qiankunjs/bundler-plugin\": patch\n---\n\nfix: correct entry script identification and webpack version detection in Vu"
},
{
"path": ".changeset/shaggy-shrimps-drum.md",
"chars": 136,
"preview": "---\n\"@qiankunjs/bundler-plugin\": patch\n\"create-qiankun\": patch\n---\n\nfix: improve QiankunPlugin webpack compatibility and"
},
{
"path": ".changeset/sharp-files-raise.md",
"chars": 101,
"preview": "---\n\"qiankun\": patch\n---\n\nfix(qiankun): remove premature lifecycle check to allow fallback detection\n"
},
{
"path": ".changeset/shiny-jeans-sip.md",
"chars": 78,
"preview": "---\n\"qiankun\": patch\n---\n\nfeat: make loadEntry and beforeLoad runs parallelly\n"
},
{
"path": ".changeset/short-kings-explain.md",
"chars": 53,
"preview": "---\n\"qiankun\": patch\n---\n\n✨add registerMicroApps api\n"
},
{
"path": ".changeset/shy-mayflies-shave.md",
"chars": 166,
"preview": "---\n\"@qiankunjs/loader\": patch\n\"@qiankunjs/shared\": patch\n---\n\nfeat: change script src before it execute thus we can be "
},
{
"path": ".changeset/silly-books-complain.md",
"chars": 152,
"preview": "---\n\"@qiankunjs/sandbox\": patch\n---\n\nfeat(sandbox): micro app mounting should wait unit rebuilding link element loaded t"
},
{
"path": ".changeset/slow-timers-heal.md",
"chars": 111,
"preview": "---\n\"@qiankunjs/sandbox\": patch\n---\n\nfix(sandbox): createElement hijack must be paired to avoid rewriting leak\n"
},
{
"path": ".changeset/small-experts-hug.md",
"chars": 107,
"preview": "---\n\"@qiankunjs/sandbox\": patch\n---\n\nfeat: support addEventListener with once options to avoid memory leak\n"
},
{
"path": ".changeset/smart-guests-jam.md",
"chars": 58,
"preview": "---\n\"@qiankunjs/sandbox\": patch\n---\n\nchore: optimize code\n"
},
{
"path": ".changeset/smart-scissors-press.md",
"chars": 92,
"preview": "---\n'qiankun': patch\n'@qiankunjs/sandbox': patch\n---\n\nfeat: optimize lifecycle validate log\n"
},
{
"path": ".changeset/smart-scissors-sell.md",
"chars": 193,
"preview": "---\n\"@qiankunjs/loader\": patch\n\"qiankun\": patch\n\"@qiankunjs/sandbox\": patch\n\"@qiankunjs/shared\": patch\n---\n\nfix: dynamic"
},
{
"path": ".changeset/smooth-pillows-jam.md",
"chars": 113,
"preview": "---\n\"qiankun\": patch\n\"@qiankunjs/shared\": patch\n---\n\nfeat: remove lru-cache and move wrapFetch to shared package\n"
},
{
"path": ".changeset/sour-roses-smile.md",
"chars": 109,
"preview": "---\n\"@qiankunjs/sandbox\": patch\n\"@qiankunjs/react\": patch\n---\n\nfeat: not rebind non-native global properties\n"
},
{
"path": ".changeset/spotty-plums-hear.md",
"chars": 115,
"preview": "---\n\"@qiankunjs/loader\": patch\n\"@qiankunjs/shared\": patch\n---\n\nfeat: improve fetch error message by prepending url\n"
},
{
"path": ".changeset/stale-dolls-push.md",
"chars": 112,
"preview": "---\n\"@qiankunjs/shared\": patch\n---\n\nfeat(transpiler): assets transpiler should work well while sandbox disabled\n"
},
{
"path": ".changeset/strong-rocks-sneeze.md",
"chars": 140,
"preview": "---\n\"@qiankunjs/loader\": patch\n\"@qiankunjs/sandbox\": patch\n\"@qiankunjs/shared\": patch\n---\n\nfix: defer scripts should wai"
},
{
"path": ".changeset/sweet-cars-protect.md",
"chars": 72,
"preview": "---\n\"create-qiankun\": patch\n---\n\nfix: include template to publish field\n"
},
{
"path": ".changeset/sweet-shoes-brake.md",
"chars": 99,
"preview": "---\n\"@qiankunjs/shared\": patch\n---\n\nfix: should not transform URLs that already include a protocol\n"
},
{
"path": ".changeset/swift-squids-vanish.md",
"chars": 90,
"preview": "---\n\"@qiankunjs/sandbox\": patch\n---\n\nfix(sandbox): fix async script order index calculate\n"
},
{
"path": ".changeset/tall-buttons-pretend.md",
"chars": 67,
"preview": "---\n\"create-qiankun\": patch\n---\n\nfeat: refactor create-qiankun cli\n"
},
{
"path": ".changeset/tasty-donkeys-relax.md",
"chars": 66,
"preview": "---\n\"qiankun\": patch\n---\n\n[#2823] Add legacy APIs for qiankun 3.0\n"
},
{
"path": ".changeset/tender-dingos-allow.md",
"chars": 121,
"preview": "---\n\"@qiankunjs/bundler-plugin\": patch\n---\n\nfix(webpack-plugin):fix webpack module not found during webpack-plugin build"
},
{
"path": ".changeset/tender-pots-perform.md",
"chars": 104,
"preview": "---\n\"@qiankunjs/loader\": patch\n---\n\nfix: prefer reading script.dataset.src in script load error message\n"
},
{
"path": ".changeset/thin-ways-allow.md",
"chars": 106,
"preview": "---\n\"@qiankunjs/loader\": patch\n---\n\nfix(loader): we should invoke our script load listener before its own\n"
},
{
"path": ".changeset/three-hornets-hammer.md",
"chars": 152,
"preview": "---\n\"qiankun\": patch\n\"@qiankunjs/sandbox\": patch\n---\n\nfix: should invoke getContainer method to get container every time"
},
{
"path": ".changeset/tough-beers-grow.md",
"chars": 104,
"preview": "---\n\"@qiankunjs/loader\": patch\n\"qiankun\": patch\n---\n\nfix: transformer should be generated in every load\n"
},
{
"path": ".changeset/tough-phones-chew.md",
"chars": 152,
"preview": "---\n\"@qiankunjs/loader\": patch\n\"qiankun\": patch\n\"@qiankunjs/sandbox\": patch\n\"@qiankunjs/shared\": patch\n---\n\n🐛 compatible"
},
{
"path": ".changeset/twelve-donkeys-help.md",
"chars": 142,
"preview": "---\n\"@qiankunjs/sandbox\": patch\n---\n\nfix: should patch the container head/body element immediately rather than patch its"
},
{
"path": ".changeset/warm-chefs-chew.md",
"chars": 65,
"preview": "---\n\"qiankun\": patch\n---\n\n✨ set data-name on micro app container\n"
},
{
"path": ".changeset/wicked-icons-type.md",
"chars": 161,
"preview": "---\n\"@qiankunjs/loader\": patch\n\"qiankun\": patch\n\"@qiankunjs/sandbox\": patch\n\"@qiankunjs/shared\": patch\n---\n\nfeat: extrac"
},
{
"path": ".changeset/wise-eagles-tease.md",
"chars": 120,
"preview": "---\n\"@qiankunjs/sandbox\": patch\n---\n\nfix(sandbox): compatible with dynamically appending scripts to detached containers\n"
},
{
"path": ".changeset/wise-ravens-prove.md",
"chars": 197,
"preview": "---\n\"@qiankunjs/loader\": patch\n\"qiankun\": patch\n\"@qiankunjs/sandbox\": patch\n\"@qiankunjs/shared\": patch\n---\n\nfeat: suppor"
},
{
"path": ".dumirc.ts",
"chars": 1817,
"preview": "import { defineConfig } from 'dumi';\n\nexport default defineConfig({\n publicPath: process.env.NOW_DEPLOY ? '/' : '/qiank"
},
{
"path": ".editorconfig",
"chars": 236,
"preview": "# http://editorconfig.org\nroot = true\n\n[*]\nindent_style = space\nindent_size = 2\nend_of_line = lf\ncharset = utf-8\ntrim_tr"
},
{
"path": ".eslintignore",
"chars": 88,
"preview": "examples\ndist\nwritable-dom\ntemplate\n\n# TODO not linting test files temporary\n__tests__/\n"
},
{
"path": ".eslintrc.cjs",
"chars": 1833,
"preview": "// eslint config for js\nconst jsConfig = {\n parserOptions: { ecmaVersion: 'latest', sourceType: 'module' },\n extends: "
},
{
"path": ".fatherrc.cjs",
"chars": 274,
"preview": "module.exports = {\n platform: 'browser',\n esm: {},\n cjs: {},\n sourcemap: true,\n extraBabelPlugins: [\n [\n 'b"
},
{
"path": ".github/CODE_OF_CONDUCT.md",
"chars": 5346,
"preview": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nWe as members, contributors, and leaders pledge to make participa"
},
{
"path": ".github/CONTRIBUTING.md",
"chars": 11356,
"preview": "# Contributing to qiankun\n\nThank you for your interest in contributing to qiankun! We welcome all types of contributions"
},
{
"path": ".github/ISSUE_TEMPLATE/bug_report.md",
"chars": 506,
"preview": "---\nname: 'Bug report'\nabout: 'Report a bug to help us improve'\ntitle: ''\nlabels: ''\nassignees: ''\n---\n\n## What happens?"
},
{
"path": ".github/ISSUE_TEMPLATE/bug_report_cn.md",
"chars": 509,
"preview": "---\nname: '缺陷问题反馈'\nabout: '反馈问题以帮助我们改进'\ntitle: '[Bug]请遵循下文模板提交问题,否则您的问题会被关闭'\nlabels: ''\nassignees: ''\n---\n\n# 提问之前强烈建立您能先"
},
{
"path": ".github/ISSUE_TEMPLATE/feature_request.md",
"chars": 426,
"preview": "---\nname: 'Feature request'\nabout: 'Suggest an idea for this project'\ntitle: '[Feature Request] say something'\nlabels: '"
},
{
"path": ".github/ISSUE_TEMPLATE/rfc_cn.md",
"chars": 257,
"preview": "---\nname: 'RFC Proposals'\nabout: 'Provide a solution for this project'\ntitle: '[RFC] say something'\nlabels: 'type: propo"
},
{
"path": ".github/PULL_REQUEST_TEMPLATE.md",
"chars": 735,
"preview": "<!--\nThank you for your pull request. Please review below requirements.\nBug fixes and new features should include tests."
},
{
"path": ".github/workflows/announcement-notify.yml",
"chars": 4333,
"preview": "name: Annoucement Notify\n\non:\n discussion:\n types: [created]\n\njobs:\n notify:\n runs-on: ubuntu-latest\n steps:\n"
},
{
"path": ".github/workflows/changeset-prerelease.yml",
"chars": 1578,
"preview": "name: Changesets\n\non:\n push:\n branches:\n - next\n\npermissions:\n id-token: write\n contents: write\n pull-reques"
},
{
"path": ".github/workflows/ci.yml",
"chars": 1391,
"preview": "name: CI\n\non:\n pull_request:\n push:\n branches:\n - master\n - next\n - 1.x\n\njobs:\n build-check-and-lin"
},
{
"path": ".github/workflows/emoji-helper.yml",
"chars": 257,
"preview": "name: Emoji Helper\n\non:\n release:\n types: [published]\n\njobs:\n emoji:\n runs-on: ubuntu-latest\n steps:\n - "
},
{
"path": ".github/workflows/github-pages.yml",
"chars": 697,
"preview": "name: Qiankun Github Pages Deploy\non:\n push:\n branches:\n - master\njobs:\n deploy-gh-pages:\n runs-on: ubuntu-"
},
{
"path": ".github/workflows/issue-close-inactive.yml",
"chars": 1987,
"preview": "name: Issue Close Inactive\n\non:\n schedule:\n - cron: \"0 0 * * *\"\n\njobs:\n close-issues:\n runs-on: ubuntu-latest\n "
},
{
"path": ".github/workflows/issue-reply.yml",
"chars": 2436,
"preview": "name: Issue Reply\n\non:\n issues:\n types: [labeled]\n\njobs:\n reply-helper:\n runs-on: ubuntu-latest\n steps:\n "
},
{
"path": ".github/workflows/publish-1.x.yml",
"chars": 527,
"preview": "name: Publish 1.x Version\n\non:\n push:\n tags:\n - v1.*\n\njobs:\n publish:\n runs-on: ubuntu-latest\n\n steps:\n "
},
{
"path": ".github/workflows/publish-latest.yml",
"chars": 528,
"preview": "name: Publish Latest Version\n\non:\n push:\n tags:\n - v2.*\n\njobs:\n publish:\n runs-on: ubuntu-latest\n\n steps"
},
{
"path": ".github/workflows/release-notify.yml",
"chars": 4568,
"preview": "name: Release Notify\n\non:\n release:\n types: [published]\n\njobs:\n notify:\n runs-on: ubuntu-latest\n steps:\n "
},
{
"path": ".gitignore",
"chars": 352,
"preview": "pids\nlogs\nnode_modules\nnpm-debug.log\ncoverage/\nrun\ndist\n.DS_Store\n.nyc_output\nconfig.local.js\n.umi\n.umi-production\n.idea"
},
{
"path": ".husky/commit-msg",
"chars": 91,
"preview": "#!/usr/bin/env sh\n. \"$(dirname -- \"$0\")/_/husky.sh\"\n\nnpx --no-install commitlint --edit $1 "
},
{
"path": ".husky/pre-commit",
"chars": 69,
"preview": "#!/usr/bin/env sh\n. \"$(dirname -- \"$0\")/_/husky.sh\"\n\nnpx lint-staged\n"
},
{
"path": ".husky/pre-push",
"chars": 68,
"preview": "#!/usr/bin/env sh\n. \"$(dirname -- \"$0\")/_/husky.sh\"\n\n#pnpm run test\n"
},
{
"path": ".prettierignore",
"chars": 266,
"preview": "/test/fixtures\n**/*.gif\n/dist\n/docs\n/es\n/lib\n/coverage\n.cache\nexamples\n.umi\n.dumi\n.umi-production\n\n.changeset/*\npnpm-loc"
},
{
"path": ".prettierrc",
"chars": 278,
"preview": "{\n \"singleQuote\": true,\n \"trailingComma\": \"all\",\n \"proseWrap\": \"never\",\n \"overrides\": [\n {\n \"files\": [\"*.jso"
},
{
"path": "AGENTS.md",
"chars": 4851,
"preview": "# QIANKUN PROJECT KNOWLEDGE BASE\n\n**Generated:** 2026-01-10 **Commit:** 058166b6 **Branch:** next\n\n## OVERVIEW\n\nQiankun "
},
{
"path": "LICENSE",
"chars": 1063,
"preview": "MIT License\n\nCopyright (c) 2019 Kuitos\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof "
},
{
"path": "README.md",
"chars": 6743,
"preview": "<p align=\"center\">\n <a href=\"https://qiankun.umijs.org\" target=\"_blank\" rel=\"noopener noreferrer\">\n <img width=\"180\""
},
{
"path": "commitlint.config.js",
"chars": 273,
"preview": "module.exports = {\n extends: ['@commitlint/config-conventional'],\n rules: {\n 'type-enum': [\n 2,\n 'always'"
},
{
"path": "docs/.vitepress/config.mjs",
"chars": 6810,
"preview": "import { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n title: 'qiankun',\n description: 'Probably the"
},
{
"path": "docs/.vitepress/theme/index.js",
"chars": 1842,
"preview": "// .vitepress/theme/index.js\nimport DefaultTheme from 'vitepress/theme'\nimport { onMounted, nextTick } from 'vue'\n\nexpor"
},
{
"path": "docs/api/configuration.md",
"chars": 14824,
"preview": "# Configuration\n\nqiankun provides flexible configuration options to customize the behavior of micro-frontend application"
},
{
"path": "docs/api/index.md",
"chars": 3310,
"preview": "# API Reference\n\nqiankun provides a simple yet powerful API set for building micro-frontend applications. All APIs are f"
},
{
"path": "docs/api/is-runtime-compatible.md",
"chars": 7136,
"preview": "# isRuntimeCompatible\n\nCheck if the current browser environment is compatible with qiankun runtime features.\n\n## 🎯 Funct"
},
{
"path": "docs/api/lifecycles.md",
"chars": 12827,
"preview": "# Lifecycles\n\nLifecycle hooks allow you to perform custom logic at different stages of a micro application's lifecycle. "
},
{
"path": "docs/api/load-micro-app.md",
"chars": 9481,
"preview": "# loadMicroApp\n\nManually load a micro application. This is useful for loading micro applications dynamically or when the"
},
{
"path": "docs/api/register-micro-apps.md",
"chars": 6490,
"preview": "# registerMicroApps\n\n注册微应用到 qiankun 中,这是构建微前端应用的核心 API。\n\n## 🎯 函数签名\n\n```typescript\nfunction registerMicroApps<T extends O"
},
{
"path": "docs/api/start.md",
"chars": 8752,
"preview": "# start\n\nStart the qiankun framework. This function initializes the micro-frontend system and enables automatic routing-"
},
{
"path": "docs/api/types.md",
"chars": 14739,
"preview": "# TypeScript Types\n\nqiankun provides comprehensive TypeScript type definitions to ensure type safety and excellent devel"
},
{
"path": "docs/cookbook/error-handling.md",
"chars": 27445,
"preview": "# Error Handling\n\nRobust error handling is essential for micro-frontend applications where multiple independent applicat"
},
{
"path": "docs/cookbook/index.md",
"chars": 7991,
"preview": "# Best Practices\n\nThis section contains practical guides and best practices for building production-ready micro-frontend"
},
{
"path": "docs/cookbook/performance.md",
"chars": 27647,
"preview": "# Performance Optimization\n\nPerformance is crucial for micro-frontend applications. With multiple applications loading a"
},
{
"path": "docs/cookbook/style-isolation.md",
"chars": 16425,
"preview": "# Style Isolation\n\nStyle isolation is one of the most critical aspects of micro-frontend architecture. When multiple app"
},
{
"path": "docs/ecosystem/bundler-plugin.md",
"chars": 4495,
"preview": "# Bundler Plugin\n\nThe `@qiankunjs/bundler-plugin` provides bundler plugins for the qiankun micro-frontend framework. Cur"
},
{
"path": "docs/ecosystem/create-qiankun.md",
"chars": 11687,
"preview": "# Create Qiankun\n\n`create-qiankun` is a CLI scaffolding tool designed specifically for the qiankun micro-frontend framew"
},
{
"path": "docs/ecosystem/index.md",
"chars": 7237,
"preview": "# Ecosystem\n\nqiankun provides a rich ecosystem of UI bindings and tools to help you build and maintain micro-frontend ap"
},
{
"path": "docs/ecosystem/react.md",
"chars": 16223,
"preview": "# React Bindings\n\nThe official React bindings for qiankun provide a declarative way to integrate micro applications into"
},
{
"path": "docs/ecosystem/vue.md",
"chars": 19525,
"preview": "# Vue Bindings\n\nThe official Vue bindings for qiankun provide a declarative way to integrate micro applications into you"
},
{
"path": "docs/faq/index.md",
"chars": 16855,
"preview": "# Frequently Asked Questions\n\nThis FAQ covers the most common questions and issues encountered when working with qiankun"
},
{
"path": "docs/guide/index.md",
"chars": 7530,
"preview": "# What is qiankun?\n\nqiankun is a micro-frontend implementation library based on [single-spa](https://github.com/single-s"
},
{
"path": "docs/guide/quick-start.md",
"chars": 7222,
"preview": "# Quick Start\n\nThis guide will help you set up a basic qiankun micro-frontend application in 5 minutes.\n\n## Prerequisite"
},
{
"path": "docs/guide/tutorial.md",
"chars": 15502,
"preview": "# Tutorial\n\nThis tutorial is suitable for people who are new to `qiankun`, and introduces how to build a `qiankun` proje"
},
{
"path": "docs/index.md",
"chars": 4271,
"preview": "---\nlayout: home\n\nhero:\n name: Qiankun\n text: Micro-Frontend Solution\n tagline: Probably the most complete micro-fron"
},
{
"path": "docs/zh-CN/api/configuration.md",
"chars": 13534,
"preview": "# Configuration\n\nqiankun 提供灵活的配置选项来自定义微前端应用的行为。本文档涵盖了不同用例的所有可用配置选项。\n\n## 📋 配置类型\n\n### AppConfiguration\n\n与 `loadMicroApp` 一"
},
{
"path": "docs/zh-CN/api/index.md",
"chars": 2283,
"preview": "# API 参考\n\nqiankun 提供了简洁而强大的 API 来构建微前端应用。所有 API 都提供了完整的 TypeScript 类型定义,确保开发体验和类型安全。\n\n## 📚 核心 API\n\n### 应用注册与启动\n\n| API | "
},
{
"path": "docs/zh-CN/api/is-runtime-compatible.md",
"chars": 6378,
"preview": "# isRuntimeCompatible\n\n检查当前浏览器环境是否与 qiankun 运行时特性兼容。\n\n## 🎯 函数签名\n\n```typescript\nfunction isRuntimeCompatible(): boolean\n`"
},
{
"path": "docs/zh-CN/api/lifecycles.md",
"chars": 11610,
"preview": "# Lifecycles\n\n生命周期钩子允许您在微应用生命周期的不同阶段执行自定义逻辑。这些钩子在应用加载、挂载和卸载过程中由 qiankun 自动执行。\n\n## 🎯 类型定义\n\n```typescript\nexport type Life"
},
{
"path": "docs/zh-CN/api/load-micro-app.md",
"chars": 8483,
"preview": "# loadMicroApp\n\n手动加载微应用。这对于动态加载微应用或当微应用不与路由关联时很有用。\n\n## 🎯 函数签名\n\n```typescript\nfunction loadMicroApp<T extends ObjectType>"
},
{
"path": "docs/zh-CN/api/register-micro-apps.md",
"chars": 6508,
"preview": "# registerMicroApps\n\n注册微应用到 qiankun 中,这是构建微前端应用的核心 API。\n\n## 🎯 函数签名\n\n```typescript\nfunction registerMicroApps<T extends O"
},
{
"path": "docs/zh-CN/api/start.md",
"chars": 6807,
"preview": "# start\n\n启动 qiankun 框架。此函数初始化微前端系统并启用基于路由的微应用自动加载。\n\n## 🎯 函数签名\n\n```typescript\nfunction start(opts?: StartOpts): void\n```\n"
},
{
"path": "docs/zh-CN/api/types.md",
"chars": 12444,
"preview": "# TypeScript 类型\n\nqiankun 提供了全面的 TypeScript 类型定义,确保类型安全和出色的开发者体验。本文档涵盖了所有可用的类型和接口。\n\n## 📋 核心类型\n\n### ObjectType\n\n**描述**:通用对"
},
{
"path": "docs/zh-CN/cookbook/error-handling.md",
"chars": 23002,
"preview": "# 错误处理\n\n在同一上下文中运行多个独立应用的微前端应用程序中,健壮的错误处理至关重要。本指南涵盖了处理错误、实现优雅降级以及在基于 qiankun 的微前端系统中维护应用程序稳定性的综合策略。\n\n## 🎯 微前端中的错误类型\n\n### "
},
{
"path": "docs/zh-CN/cookbook/index.md",
"chars": 3652,
"preview": "# 最佳实践\n\n本节包含使用 qiankun 构建生产级微前端应用的实用指南和最佳实践。这些指南基于真实世界的经验和实施微前端架构时面临的常见挑战。\n\n## 🎯 概述\n\n构建微前端需要仔细考虑各个方面,包括架构设计、性能优化、开发工作流和部"
},
{
"path": "docs/zh-CN/cookbook/performance.md",
"chars": 23217,
"preview": "# 性能优化\n\n对于微前端应用来说,性能至关重要。由于多个应用同时加载和运行,优化资源加载、运行时性能和用户体验非常重要。本指南涵盖了优化基于 qiankun 的微前端应用的综合策略。\n\n## 🎯 性能概述\n\n### 常见性能挑战\n\n微前端"
},
{
"path": "docs/zh-CN/cookbook/style-isolation.md",
"chars": 13152,
"preview": "# 样式隔离\n\n样式隔离是微前端架构中最关键的方面之一。当多个应用在同一浏览器上下文中运行时,CSS 冲突可能导致视觉不一致和布局错误。本指南涵盖了在 qiankun 应用中实现有效样式隔离的各种策略。\n\n## 🎯 理解问题\n\n### 微前"
},
{
"path": "docs/zh-CN/ecosystem/create-qiankun.md",
"chars": 8231,
"preview": "# Create Qiankun\n\n`create-qiankun` 是一个专为 qiankun 微前端框架设计的 CLI 脚手架工具。它帮助开发者快速构建示例项目,高效开始微前端开发。\n\n## 🚀 快速开始\n\n### 使用 npm\n\n``"
},
{
"path": "docs/zh-CN/ecosystem/index.md",
"chars": 5418,
"preview": "# 生态系统\n\nqiankun 提供了丰富的 UI 绑定和工具生态系统,帮助你高效地构建和维护微前端应用。\n\n## 🧩 UI 绑定\n\nqiankun 为流行框架提供声明式 UI 组件,使在主应用中加载和管理微应用变得更加容易。\n\n### R"
},
{
"path": "docs/zh-CN/ecosystem/react.md",
"chars": 14419,
"preview": "# React 绑定\n\nqiankun 的官方 React 绑定提供了一种声明式的方式来将微应用集成到您的 React 主应用中。`@qiankunjs/react` 包提供了一个强大的 `<MicroApp />` 组件,内置加载状态、错"
},
{
"path": "docs/zh-CN/ecosystem/vue.md",
"chars": 17429,
"preview": "# Vue 绑定\n\nqiankun 的官方 Vue 绑定提供了一种声明式的方式来将微应用集成到您的 Vue 主应用中。`@qiankunjs/vue` 包提供了一个强大的 `<MicroApp />` 组件,支持 Vue 2/3 兼容性、C"
},
{
"path": "docs/zh-CN/ecosystem/webpack-plugin.md",
"chars": 9174,
"preview": "# Webpack 插件\n\n`@qiankunjs/webpack-plugin` 是专为 qiankun 微前端框架设计的 Webpack 插件。它简化并自动化了将微应用与 qiankun 集成所需的常见配置,确保正确的构建输出和运行时行"
},
{
"path": "docs/zh-CN/faq/index.md",
"chars": 11590,
"preview": "# 常见问题\n\n本 FAQ 涵盖了使用 qiankun 时遇到的最常见问题和问题。如果您找不到所需的答案,请查看我们的 [GitHub Issues](https://github.com/umijs/qiankun/issues) 或加入"
},
{
"path": "docs/zh-CN/guide/index.md",
"chars": 3280,
"preview": "# 什么是 qiankun?\n\nqiankun 是一个基于 [single-spa](https://github.com/single-spa/single-spa) 的微前端实现库,旨在帮助大家能更简单、无痛地构建一个生产可用的微前端架"
},
{
"path": "docs/zh-CN/guide/quick-start.md",
"chars": 5754,
"preview": "# 快速开始\n\n本指南将帮助你在 5 分钟内搭建一个基础的 qiankun 微前端应用。\n\n## 前置条件\n\n- Node.js 16+\n- 基础的 JavaScript/TypeScript 知识\n- 了解 React、Vue 或其他前端"
},
{
"path": "docs/zh-CN/guide/tutorial.md",
"chars": 12257,
"preview": "# 教程\n\n本教程适合新接触 `qiankun` 的人群,从零开始介绍如何构建一个 `qiankun` 项目。\n\n## 主应用\n\n主应用不限技术栈,只需要提供一个容器 DOM,然后注册微应用并启动 qiankun 即可。\n\n首先安装 `qi"
},
{
"path": "docs/zh-CN/index.md",
"chars": 3089,
"preview": "---\nlayout: home\n\nhero:\n name: Qiankun\n text: 微前端解决方案\n tagline: 可能是你见过的最完善的微前端解决方案🧐\n image:\n src: /logo.png\n a"
},
{
"path": "examples/main/index.html",
"chars": 376,
"preview": "<!DOCTYPE html>\n<html lang=\"en\">\n <head>\n <meta charset=\"UTF-8\" />\n <link rel=\"icon\" type=\"image/svg+xml\" href=\"/"
},
{
"path": "examples/main/package.json",
"chars": 1090,
"preview": "{\n \"name\": \"qiankun-main-app\",\n \"version\": \"2.0.0\",\n \"description\": \"Qiankun main application with modern tech stack\""
},
{
"path": "examples/main/postcss.config.js",
"chars": 80,
"preview": "export default {\n plugins: {\n tailwindcss: {},\n autoprefixer: {},\n },\n}\n"
},
{
"path": "examples/main/src/App.tsx",
"chars": 944,
"preview": "import { useEffect } from 'react';\nimport { Layout } from 'antd';\nimport { useQiankunStore } from './store/qiankun';\nimp"
},
{
"path": "examples/main/src/components/Dashboard.tsx",
"chars": 4806,
"preview": "import { Row, Col, Card, Statistic, Typography, Tag, Space, Button } from 'antd';\nimport {\n AppstoreOutlined,\n Thunder"
},
{
"path": "examples/main/src/components/Header.tsx",
"chars": 3551,
"preview": "import { Layout, Button, Badge, Avatar, Dropdown, Space, Typography, Tooltip, theme } from 'antd';\nimport {\n BellOutlin"
},
{
"path": "examples/main/src/components/MicroAppContainer.tsx",
"chars": 3278,
"preview": "import { useEffect, useRef, useCallback } from 'react';\nimport { loadMicroApp, MicroApp } from 'qiankun';\nimport { useQi"
},
{
"path": "examples/main/src/components/Sidebar.tsx",
"chars": 3809,
"preview": "import { useState } from 'react';\nimport { Layout, Menu, Typography, Space, Tag } from 'antd';\nimport { useQiankunStore "
},
{
"path": "examples/main/src/main.tsx",
"chars": 633,
"preview": "import React from 'react';\nimport ReactDOM from 'react-dom/client';\nimport { ConfigProvider } from 'antd';\nimport App fr"
},
{
"path": "examples/main/src/store/qiankun.ts",
"chars": 1322,
"preview": "import { create } from 'zustand';\n\nexport interface GlobalState {\n user?: {\n name: string;\n avatar?: string;\n };"
},
{
"path": "examples/main/src/styles/index.css",
"chars": 1152,
"preview": "@tailwind base;\n@tailwind components;\n@tailwind utilities;\n\n/* Custom scrollbar */\n::-webkit-scrollbar {\n width: 6px;\n "
},
{
"path": "examples/main/src/vite-env.d.ts",
"chars": 38,
"preview": "/// <reference types=\"vite/client\" />\n"
},
{
"path": "examples/main/tailwind.config.js",
"chars": 1498,
"preview": "/** @type {import('tailwindcss').Config} */\nexport default {\n content: [\n \"./index.html\",\n \"./src/**/*.{js,ts,jsx"
},
{
"path": "examples/main/tsconfig.json",
"chars": 700,
"preview": "{\n \"compilerOptions\": {\n \"target\": \"ES2020\",\n \"useDefineForClassFields\": true,\n \"lib\": [\"ES2020\", \"DOM\", \"DOM."
},
{
"path": "examples/main/tsconfig.node.json",
"chars": 213,
"preview": "{\n \"compilerOptions\": {\n \"composite\": true,\n \"skipLibCheck\": true,\n \"module\": \"ESNext\",\n \"moduleResolution\""
},
{
"path": "examples/main/vite.config.ts",
"chars": 376,
"preview": "import { defineConfig } from 'vite'\nimport react from '@vitejs/plugin-react'\nimport path from 'path'\n\n// https://vitejs."
},
{
"path": "examples/purehtml/entry.js",
"chars": 460,
"preview": "const render = $ => {\n $('#purehtml-container').html('Hello, render with jQuery');\n return Promise.resolve();\n};\n\n(glo"
},
{
"path": "examples/purehtml/index.html",
"chars": 521,
"preview": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, in"
},
{
"path": "examples/purehtml/package.json",
"chars": 347,
"preview": "{\n \"name\": \"purehtml\",\n \"version\": \"1.0.0\",\n \"description\": \"\",\n \"main\": \"index.html\",\n \"scripts\": {\n \"start\": \""
},
{
"path": "examples/react/.gitignore",
"chars": 253,
"preview": "# Logs\nlogs\n*.log\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\npnpm-debug.log*\nlerna-debug.log*\n\nnode_modules\ndist\ndis"
},
{
"path": "examples/react/README.md",
"chars": 1607,
"preview": "# React + TypeScript + Vite\n\nThis template provides a minimal setup to get React working in Vite with HMR and some ESLin"
},
{
"path": "examples/react/config/qiankunHtml.ts",
"chars": 1574,
"preview": "import type { IndexHtmlTransformContext, PluginOption } from 'vite';\nimport { load } from 'cheerio';\n\nexport default fun"
},
{
"path": "examples/react/eslint.config.js",
"chars": 734,
"preview": "import js from '@eslint/js'\nimport globals from 'globals'\nimport reactHooks from 'eslint-plugin-react-hooks'\nimport reac"
},
{
"path": "examples/react/index.html",
"chars": 372,
"preview": "<!doctype html>\n<html lang=\"en\">\n <head>\n <meta charset=\"UTF-8\" />\n <link rel=\"icon\" type=\"image/svg+xml\" href=\"/"
},
{
"path": "examples/react/package.json",
"chars": 953,
"preview": "{\n \"name\": \"react\",\n \"private\": true,\n \"version\": \"0.0.0\",\n \"type\": \"module\",\n \"scripts\": {\n \"dev\": \"vite\",\n "
},
{
"path": "examples/react/src/App.css",
"chars": 606,
"preview": "#root {\n max-width: 1280px;\n margin: 0 auto;\n padding: 2rem;\n text-align: center;\n}\n\n.logo {\n height: 6em;\n paddin"
},
{
"path": "examples/react/src/App.tsx",
"chars": 1309,
"preview": "import { useState, version } from 'react'\nimport reactLogo from './assets/react.svg'\nimport viteLogo from '/vite.svg'\nim"
},
{
"path": "examples/react/src/index.css",
"chars": 1161,
"preview": ":root {\n font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;\n line-height: 1.5;\n font-weight: 400;\n\n"
},
{
"path": "examples/react/src/main.tsx",
"chars": 1370,
"preview": "import React from 'react';\nimport ReactDOM from 'react-dom/client';\nimport App from './App';\nimport './index.css';\n\ndecl"
},
{
"path": "examples/react/src/vite-env.d.ts",
"chars": 38,
"preview": "/// <reference types=\"vite/client\" />\n"
},
{
"path": "examples/react/tsconfig.app.json",
"chars": 665,
"preview": "{\n \"compilerOptions\": {\n \"tsBuildInfoFile\": \"./node_modules/.tmp/tsconfig.app.tsbuildinfo\",\n \"target\": \"ES2020\",\n"
},
{
"path": "examples/react/tsconfig.json",
"chars": 119,
"preview": "{\n \"files\": [],\n \"references\": [\n { \"path\": \"./tsconfig.app.json\" },\n { \"path\": \"./tsconfig.node.json\" }\n ]\n}\n"
},
{
"path": "examples/react/tsconfig.node.json",
"chars": 593,
"preview": "{\n \"compilerOptions\": {\n \"tsBuildInfoFile\": \"./node_modules/.tmp/tsconfig.node.tsbuildinfo\",\n \"target\": \"ES2022\","
},
{
"path": "examples/react/vite.config.ts",
"chars": 998,
"preview": "import { defineConfig } from 'vite';\nimport react from '@vitejs/plugin-react';\nimport legacy from '@vitejs/plugin-legacy"
},
{
"path": "examples/vite/.eslintrc.cjs",
"chars": 391,
"preview": "module.exports = {\n env: { browser: true, es2020: true },\n extends: [\n 'eslint:recommended',\n 'plugin:@typescrip"
},
{
"path": "examples/vite/.gitignore",
"chars": 253,
"preview": "# Logs\nlogs\n*.log\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\npnpm-debug.log*\nlerna-debug.log*\n\nnode_modules\ndist\ndis"
},
{
"path": "examples/vite/index.html",
"chars": 541,
"preview": "<!DOCTYPE html>\n<html lang=\"en\">\n <head>\n <script type=\"importmap\">\n {\n \"imports\": {\n \"/@"
},
{
"path": "examples/vite/package.json",
"chars": 454,
"preview": "{\n \"name\": \"vite-micro-app\",\n \"private\": true,\n \"version\": \"0.0.0\",\n \"type\": \"module\",\n \"scripts\": {\n \"dev\": \"vi"
},
{
"path": "examples/vite/src/App.css",
"chars": 606,
"preview": "#root {\n max-width: 1280px;\n margin: 0 auto;\n padding: 2rem;\n text-align: center;\n}\n\n.logo {\n height: 6em;\n paddin"
},
{
"path": "examples/vite/src/App.tsx",
"chars": 938,
"preview": "import { useState } from 'react';\nimport reactLogo from './assets/react.svg';\nimport viteLogo from '/vite.svg';\nimport '"
},
{
"path": "examples/vite/src/index.css",
"chars": 1195,
"preview": ":root {\n font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;\n line-height: 1.5;\n font-weight: 400;\n\n"
},
{
"path": "examples/vite/src/main.tsx",
"chars": 967,
"preview": "import React from 'react';\nimport ReactDOM from 'react-dom/client';\nimport App from './App.tsx';\nimport './index.css';\n\n"
},
{
"path": "examples/vite/src/vite-env.d.ts",
"chars": 38,
"preview": "/// <reference types=\"vite/client\" />\n"
},
{
"path": "examples/vite/tsconfig.json",
"chars": 568,
"preview": "{\n \"compilerOptions\": {\n \"target\": \"ESNext\",\n \"lib\": [\"DOM\", \"DOM.Iterable\", \"ESNext\"],\n \"module\": \"ESNext\",\n "
},
{
"path": "examples/vite/tsconfig.node.json",
"chars": 213,
"preview": "{\n \"compilerOptions\": {\n \"composite\": true,\n \"skipLibCheck\": true,\n \"module\": \"ESNext\",\n \"moduleResolution\""
},
{
"path": "examples/vite/vite.config.ts",
"chars": 200,
"preview": "import { defineConfig } from 'vite';\nimport react from '@vitejs/plugin-react';\n\n// https://vitejs.dev/config/\nexport def"
},
{
"path": "examples/vue/.gitignore",
"chars": 253,
"preview": "# Logs\nlogs\n*.log\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\npnpm-debug.log*\nlerna-debug.log*\n\nnode_modules\ndist\ndis"
},
{
"path": "examples/vue/README.md",
"chars": 442,
"preview": "# Vue 3 + TypeScript + Vite\n\nThis template should help get you started developing with Vue 3 and TypeScript in Vite. The"
},
{
"path": "examples/vue/config/qiankunHtml.ts",
"chars": 1574,
"preview": "import type { IndexHtmlTransformContext, PluginOption } from 'vite';\nimport { load } from 'cheerio';\n\nexport default fun"
},
{
"path": "examples/vue/index.html",
"chars": 368,
"preview": "<!doctype html>\n<html lang=\"en\">\n <head>\n <meta charset=\"UTF-8\" />\n <link rel=\"icon\" type=\"image/svg+xml\" href=\"/"
}
]
// ... and 182 more files (download for full content)
About this extraction
This page contains the full source code of the umijs/qiankun GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 382 files (1.4 MB), approximately 524.5k tokens, and a symbol index with 283 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.